Coverage Report

Created: 2026-02-26 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpac/src/isomedia/iff.c
Line
Count
Source
1
/*
2
 *      GPAC - Multimedia Framework C SDK
3
 *
4
 *      Authors: Cyril Concolato
5
 *      Copyright (c) Telecom ParisTech 2000-2026
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
#include <gpac/internal/isomedia_dev.h>
27
#include <gpac/constants.h>
28
#include <gpac/media_tools.h>
29
30
#ifndef GPAC_DISABLE_ISOM
31
32
GF_Box *ispe_box_new()
33
0
{
34
0
  ISOM_DECL_BOX_ALLOC(GF_ImageSpatialExtentsPropertyBox, GF_ISOM_BOX_TYPE_ISPE);
35
0
  return (GF_Box *)tmp;
36
0
}
37
38
void ispe_box_del(GF_Box *a)
39
0
{
40
0
  GF_ImageSpatialExtentsPropertyBox *p = (GF_ImageSpatialExtentsPropertyBox *)a;
41
0
  gf_free(p);
42
0
}
43
44
GF_Err ispe_box_read(GF_Box *s, GF_BitStream *bs)
45
0
{
46
0
  GF_ImageSpatialExtentsPropertyBox *p = (GF_ImageSpatialExtentsPropertyBox *)s;
47
48
0
  if (p->version == 0 && p->flags == 0) {
49
0
    p->image_width = gf_bs_read_u32(bs);
50
0
    p->image_height = gf_bs_read_u32(bs);
51
0
    return GF_OK;
52
0
  } else {
53
0
    GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("version and flags for ispe box not supported" ));
54
0
    gf_bs_skip_bytes(bs, p->size);
55
0
    return GF_NOT_SUPPORTED;
56
0
  }
57
0
}
58
59
#ifndef GPAC_DISABLE_ISOM_WRITE
60
GF_Err ispe_box_write(GF_Box *s, GF_BitStream *bs)
61
0
{
62
0
  GF_Err e;
63
0
  GF_ImageSpatialExtentsPropertyBox *p = (GF_ImageSpatialExtentsPropertyBox*)s;
64
65
0
  p->version = 0;
66
0
  p->flags = 0;
67
0
  e = gf_isom_full_box_write(s, bs);
68
0
  if (e) return e;
69
0
  gf_bs_write_u32(bs, p->image_width);
70
0
  gf_bs_write_u32(bs, p->image_height);
71
0
  return GF_OK;
72
0
}
73
74
GF_Err ispe_box_size(GF_Box *s)
75
0
{
76
0
  GF_ImageSpatialExtentsPropertyBox *p = (GF_ImageSpatialExtentsPropertyBox*)s;
77
0
  if (p->version == 0 && p->flags == 0) {
78
0
    p->size += 8;
79
0
    return GF_OK;
80
0
  } else {
81
0
    GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("version and flags for ispe box not supported" ));
82
0
    return GF_NOT_SUPPORTED;
83
0
  }
84
0
}
85
#endif
86
87
GF_Box *a1lx_box_new()
88
0
{
89
0
  ISOM_DECL_BOX_ALLOC(GF_AV1LayeredImageIndexingPropertyBox, GF_ISOM_BOX_TYPE_A1LX);
90
0
  return (GF_Box *)tmp;
91
0
}
92
93
void a1lx_box_del(GF_Box *a)
94
0
{
95
0
  GF_AV1LayeredImageIndexingPropertyBox *p = (GF_AV1LayeredImageIndexingPropertyBox *)a;
96
0
  gf_free(p);
97
0
}
98
99
GF_Err a1lx_box_read(GF_Box *s, GF_BitStream *bs)
100
0
{
101
0
  u32 i;
102
0
  GF_AV1LayeredImageIndexingPropertyBox *p = (GF_AV1LayeredImageIndexingPropertyBox *)s;
103
  
104
0
  ISOM_DECREASE_SIZE(p, 1);
105
0
  gf_bs_read_int(bs, 7);
106
0
  p->large_size = gf_bs_read_int(bs, 1);
107
0
  for (i=0; i<3; i++) {
108
0
    if (p->large_size) {
109
0
      ISOM_DECREASE_SIZE(p, 4);
110
0
      p->layer_size[i] = gf_bs_read_u32(bs);
111
0
    } else {
112
0
      ISOM_DECREASE_SIZE(p, 2);
113
0
      p->layer_size[i] = gf_bs_read_u16(bs);
114
0
    }
115
0
  }
116
0
  return GF_OK;
117
0
}
118
119
#ifndef GPAC_DISABLE_ISOM_WRITE
120
GF_Err a1lx_box_write(GF_Box *s, GF_BitStream *bs)
121
0
{
122
0
  u32 i;
123
0
  GF_Err e = gf_isom_box_write_header(s, bs);
124
0
  if (e) return e;
125
0
  GF_AV1LayeredImageIndexingPropertyBox *p = (GF_AV1LayeredImageIndexingPropertyBox*)s;
126
127
0
  gf_bs_write_int(bs, 0, 7);
128
0
  gf_bs_write_int(bs, p->large_size ? 1 : 0, 1);
129
0
  for (i=0; i<3; i++) {
130
0
    if (p->large_size) {
131
0
      gf_bs_write_u32(bs, p->layer_size[i]);
132
0
    } else {
133
0
      gf_bs_write_u16(bs, p->layer_size[i]);
134
0
    }
135
0
  }
136
0
  return GF_OK;
137
0
}
138
139
GF_Err a1lx_box_size(GF_Box *s)
140
0
{
141
0
  GF_AV1LayeredImageIndexingPropertyBox *p = (GF_AV1LayeredImageIndexingPropertyBox*)s;
142
143
  //if large was set, do not override
144
0
  if (! p->large_size) {
145
0
    if (p->layer_size[0]>0xFFFF) p->large_size = 1;
146
0
    else if (p->layer_size[1]>0xFFFF) p->large_size = 1;
147
0
    else if (p->layer_size[2]>0xFFFF) p->large_size = 1;
148
0
  }
149
150
0
  p->size += (p->large_size ? 4 : 2) * 3 + 1;
151
0
  return GF_OK;
152
0
}
153
154
#endif /*GPAC_DISABLE_ISOM_WRITE*/
155
156
GF_Box *a1op_box_new()
157
0
{
158
0
  ISOM_DECL_BOX_ALLOC(GF_AV1OperatingPointSelectorPropertyBox, GF_ISOM_BOX_TYPE_A1OP);
159
0
  return (GF_Box *)tmp;
160
0
}
161
162
void a1op_box_del(GF_Box *a)
163
0
{
164
0
  GF_AV1OperatingPointSelectorPropertyBox *p = (GF_AV1OperatingPointSelectorPropertyBox *)a;
165
0
  gf_free(p);
166
0
}
167
168
GF_Err a1op_box_read(GF_Box *s, GF_BitStream *bs)
169
0
{
170
0
  GF_AV1OperatingPointSelectorPropertyBox *p = (GF_AV1OperatingPointSelectorPropertyBox *)s;
171
0
  p->op_index = gf_bs_read_u8(bs);
172
0
  return GF_OK;
173
0
}
174
175
#ifndef GPAC_DISABLE_ISOM_WRITE
176
GF_Err a1op_box_write(GF_Box *s, GF_BitStream *bs)
177
0
{
178
0
  GF_Err e = gf_isom_box_write_header(s, bs);
179
0
  if (e) return e;
180
0
  GF_AV1OperatingPointSelectorPropertyBox *p = (GF_AV1OperatingPointSelectorPropertyBox*)s;
181
0
  gf_bs_write_u8(bs, p->op_index);
182
0
  return GF_OK;
183
0
}
184
185
GF_Err a1op_box_size(GF_Box *s)
186
0
{
187
0
  GF_AV1OperatingPointSelectorPropertyBox *p = (GF_AV1OperatingPointSelectorPropertyBox*)s;
188
0
  p->size += 1;
189
0
  return GF_OK;
190
0
}
191
192
#endif /*GPAC_DISABLE_ISOM_WRITE*/
193
194
GF_Box *colr_box_new()
195
0
{
196
0
  ISOM_DECL_BOX_ALLOC(GF_ColourInformationBox, GF_ISOM_BOX_TYPE_COLR);
197
0
  return (GF_Box *)tmp;
198
0
}
199
200
void colr_box_del(GF_Box *a)
201
0
{
202
0
  GF_ColourInformationBox *p = (GF_ColourInformationBox *)a;
203
0
  if (p->opaque) gf_free(p->opaque);
204
0
  gf_free(p);
205
0
}
206
207
GF_Err colr_box_read(GF_Box *s, GF_BitStream *bs)
208
0
{
209
0
  GF_ColourInformationBox *p = (GF_ColourInformationBox *)s;
210
211
0
  if (p->is_jp2) {
212
0
    ISOM_DECREASE_SIZE(p, 3);
213
0
    p->method = gf_bs_read_u8(bs);
214
0
    p->precedence = gf_bs_read_u8(bs);
215
0
    p->approx = gf_bs_read_u8(bs);
216
0
    if (p->size) {
217
0
      p->opaque = gf_malloc(sizeof(u8)*(size_t)p->size);
218
0
      p->opaque_size = (u32) p->size;
219
0
      gf_bs_read_data(bs, (char *) p->opaque, p->opaque_size);
220
0
    }
221
0
  } else {
222
0
    ISOM_DECREASE_SIZE(p, 4);
223
0
    p->colour_type = gf_bs_read_u32(bs);
224
0
    switch (p->colour_type) {
225
0
    case GF_ISOM_SUBTYPE_NCLX:
226
0
      ISOM_DECREASE_SIZE(p, 7);
227
0
      p->colour_primaries = gf_bs_read_u16(bs);
228
0
      p->transfer_characteristics = gf_bs_read_u16(bs);
229
0
      p->matrix_coefficients = gf_bs_read_u16(bs);
230
0
      p->full_range_flag = (gf_bs_read_u8(bs) & 0x80) ? GF_TRUE : GF_FALSE;
231
0
      break;
232
0
    case GF_ISOM_SUBTYPE_NCLC:
233
0
      ISOM_DECREASE_SIZE(p, 6);
234
0
      p->colour_primaries = gf_bs_read_u16(bs);
235
0
      p->transfer_characteristics = gf_bs_read_u16(bs);
236
0
      p->matrix_coefficients = gf_bs_read_u16(bs);
237
0
      break;
238
0
    default:
239
0
      p->opaque = gf_malloc(sizeof(u8)*(size_t)p->size);
240
0
      p->opaque_size = (u32) p->size;
241
0
      gf_bs_read_data(bs, (char *) p->opaque, p->opaque_size);
242
0
      break;
243
0
    }
244
0
  }
245
0
  return GF_OK;
246
0
}
247
248
#ifndef GPAC_DISABLE_ISOM_WRITE
249
GF_Err colr_box_write(GF_Box *s, GF_BitStream *bs)
250
0
{
251
0
  GF_Err e;
252
0
  GF_ColourInformationBox *p = (GF_ColourInformationBox*)s;
253
0
  e = gf_isom_box_write_header(s, bs);
254
0
  if (e) return e;
255
256
0
  if (p->is_jp2) {
257
0
    gf_bs_write_u8(bs, p->method);
258
0
    gf_bs_write_u8(bs, p->precedence);
259
0
    gf_bs_write_u8(bs, p->approx);
260
0
    if (p->opaque_size)
261
0
      gf_bs_write_data(bs, (char *)p->opaque, p->opaque_size);
262
0
  } else {
263
0
    switch (p->colour_type) {
264
0
    case GF_ISOM_SUBTYPE_NCLX:
265
0
      gf_bs_write_u32(bs, p->colour_type);
266
0
      gf_bs_write_u16(bs, p->colour_primaries);
267
0
      gf_bs_write_u16(bs, p->transfer_characteristics);
268
0
      gf_bs_write_u16(bs, p->matrix_coefficients);
269
0
      gf_bs_write_u8(bs, (p->full_range_flag == GF_TRUE ? 0x80 : 0));
270
0
      break;
271
0
    case GF_ISOM_SUBTYPE_NCLC:
272
0
      gf_bs_write_u32(bs, p->colour_type);
273
0
      gf_bs_write_u16(bs, p->colour_primaries);
274
0
      gf_bs_write_u16(bs, p->transfer_characteristics);
275
0
      gf_bs_write_u16(bs, p->matrix_coefficients);
276
0
      break;
277
0
    default:
278
0
      gf_bs_write_u32(bs, p->colour_type);
279
0
      gf_bs_write_data(bs, (char *)p->opaque, p->opaque_size);
280
0
      break;
281
0
    }
282
0
  }
283
0
  return GF_OK;
284
0
}
285
286
GF_Err colr_box_size(GF_Box *s)
287
0
{
288
0
  GF_ColourInformationBox *p = (GF_ColourInformationBox*)s;
289
290
0
  if (p->is_jp2) {
291
0
    p->size += 3 + p->opaque_size;
292
0
  } else {
293
0
    switch (p->colour_type) {
294
0
    case GF_ISOM_SUBTYPE_NCLX:
295
0
      p->size += 11;
296
0
      break;
297
0
    case GF_ISOM_SUBTYPE_NCLC:
298
0
      p->size += 10;
299
0
      break;
300
0
    default:
301
0
      p->size += 4 + p->opaque_size;
302
0
      break;
303
0
    }
304
0
  }
305
0
  return GF_OK;
306
0
}
307
308
#endif /*GPAC_DISABLE_ISOM_WRITE*/
309
310
GF_Box *pixi_box_new()
311
0
{
312
0
  ISOM_DECL_BOX_ALLOC(GF_PixelInformationPropertyBox, GF_ISOM_BOX_TYPE_PIXI);
313
0
  return (GF_Box *)tmp;
314
0
}
315
316
void pixi_box_del(GF_Box *a)
317
0
{
318
0
  GF_PixelInformationPropertyBox *p = (GF_PixelInformationPropertyBox *)a;
319
0
  if (p->bits_per_channel) gf_free(p->bits_per_channel);
320
0
  gf_free(p);
321
0
}
322
323
GF_Err pixi_box_read(GF_Box *s, GF_BitStream *bs)
324
0
{
325
0
  u32 i;
326
0
  GF_PixelInformationPropertyBox *p = (GF_PixelInformationPropertyBox *)s;
327
328
0
  if (p->version == 0 && p->flags == 0) {
329
0
    p->num_channels = gf_bs_read_u8(bs);
330
0
    p->bits_per_channel = (u8 *)gf_malloc(p->num_channels);
331
0
    for (i = 0; i < p->num_channels; i++) {
332
0
      ISOM_DECREASE_SIZE(p, 1)
333
0
      p->bits_per_channel[i] = gf_bs_read_u8(bs);
334
0
    }
335
0
    return GF_OK;
336
0
  } else {
337
0
    GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("version and flags for pixi box not supported" ));
338
0
    gf_bs_skip_bytes(bs, p->size);
339
0
    return GF_NOT_SUPPORTED;
340
0
  }
341
0
}
342
343
#ifndef GPAC_DISABLE_ISOM_WRITE
344
GF_Err pixi_box_write(GF_Box *s, GF_BitStream *bs)
345
0
{
346
0
  u32 i;
347
0
  GF_Err e;
348
0
  GF_PixelInformationPropertyBox *p = (GF_PixelInformationPropertyBox*)s;
349
350
0
  p->version = 0;
351
0
  p->flags = 0;
352
0
  e = gf_isom_full_box_write(s, bs);
353
0
  if (e) return e;
354
0
  gf_bs_write_u8(bs, p->num_channels);
355
0
  for (i = 0; i < p->num_channels; i++) {
356
0
    gf_bs_write_u8(bs, p->bits_per_channel[i]);
357
0
  }
358
0
  return GF_OK;
359
0
}
360
361
GF_Err pixi_box_size(GF_Box *s)
362
0
{
363
0
  GF_PixelInformationPropertyBox *p = (GF_PixelInformationPropertyBox*)s;
364
0
  if (p->version == 0 && p->flags == 0) {
365
0
    p->size += 1 + p->num_channels;
366
0
    return GF_OK;
367
0
  } else {
368
0
    GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("version and flags for pixi box not supported" ));
369
0
    return GF_NOT_SUPPORTED;
370
0
  }
371
0
}
372
373
#endif /*GPAC_DISABLE_ISOM_WRITE*/
374
375
GF_Box *rloc_box_new()
376
0
{
377
0
  ISOM_DECL_BOX_ALLOC(GF_RelativeLocationPropertyBox, GF_ISOM_BOX_TYPE_RLOC);
378
0
  return (GF_Box *)tmp;
379
0
}
380
381
void rloc_box_del(GF_Box *a)
382
0
{
383
0
  GF_RelativeLocationPropertyBox *p = (GF_RelativeLocationPropertyBox *)a;
384
0
  gf_free(p);
385
0
}
386
387
GF_Err rloc_box_read(GF_Box *s, GF_BitStream *bs)
388
0
{
389
0
  GF_RelativeLocationPropertyBox *p = (GF_RelativeLocationPropertyBox *)s;
390
391
0
  if (p->version == 0 && p->flags == 0) {
392
0
    p->horizontal_offset = gf_bs_read_u32(bs);
393
0
    p->vertical_offset = gf_bs_read_u32(bs);
394
0
    return GF_OK;
395
0
  } else {
396
0
    GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("version and flags for rloc box not supported" ));
397
0
    gf_bs_skip_bytes(bs, p->size);
398
0
    return GF_NOT_SUPPORTED;
399
0
  }
400
0
}
401
402
#ifndef GPAC_DISABLE_ISOM_WRITE
403
GF_Err rloc_box_write(GF_Box *s, GF_BitStream *bs)
404
0
{
405
0
  GF_Err e;
406
0
  GF_RelativeLocationPropertyBox *p = (GF_RelativeLocationPropertyBox*)s;
407
408
0
  p->version = 0;
409
0
  p->flags = 0;
410
0
  e = gf_isom_full_box_write(s, bs);
411
0
  if (e) return e;
412
0
  gf_bs_write_u32(bs, p->horizontal_offset);
413
0
  gf_bs_write_u32(bs, p->vertical_offset);
414
0
  return GF_OK;
415
0
}
416
417
GF_Err rloc_box_size(GF_Box *s)
418
0
{
419
0
  GF_RelativeLocationPropertyBox *p = (GF_RelativeLocationPropertyBox*)s;
420
0
  if (p->version == 0 && p->flags == 0) {
421
0
    p->size += 8;
422
0
    return GF_OK;
423
0
  } else {
424
0
    GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("version and flags for rloc box not supported" ));
425
0
    return GF_NOT_SUPPORTED;
426
0
  }
427
0
}
428
429
#endif /*GPAC_DISABLE_ISOM_WRITE*/
430
431
GF_Box *irot_box_new()
432
0
{
433
0
  ISOM_DECL_BOX_ALLOC(GF_ImageRotationBox, GF_ISOM_BOX_TYPE_IROT);
434
0
  return (GF_Box *)tmp;
435
0
}
436
437
void irot_box_del(GF_Box *a)
438
0
{
439
0
  GF_ImageRotationBox *p = (GF_ImageRotationBox *)a;
440
0
  gf_free(p);
441
0
}
442
443
GF_Err irot_box_read(GF_Box *s, GF_BitStream *bs)
444
0
{
445
0
  GF_ImageRotationBox *p = (GF_ImageRotationBox *)s;
446
0
  p->angle = gf_bs_read_u8(bs) & 0x3;
447
0
  return GF_OK;
448
0
}
449
450
#ifndef GPAC_DISABLE_ISOM_WRITE
451
GF_Err irot_box_write(GF_Box *s, GF_BitStream *bs)
452
0
{
453
0
  GF_Err e;
454
0
  GF_ImageRotationBox *p = (GF_ImageRotationBox*)s;
455
0
  e = gf_isom_box_write_header(s, bs);
456
0
  if (e) return e;
457
0
  gf_bs_write_u8(bs, p->angle);
458
0
  return GF_OK;
459
0
}
460
461
GF_Err irot_box_size(GF_Box *s)
462
0
{
463
0
  GF_ImageRotationBox *p = (GF_ImageRotationBox*)s;
464
0
  p->size += 1;
465
0
  return GF_OK;
466
0
}
467
468
#endif /*GPAC_DISABLE_ISOM_WRITE*/
469
470
GF_Box *imir_box_new()
471
0
{
472
0
  ISOM_DECL_BOX_ALLOC(GF_ImageMirrorBox, GF_ISOM_BOX_TYPE_IMIR);
473
0
  return (GF_Box *)tmp;
474
0
}
475
476
void imir_box_del(GF_Box *a)
477
0
{
478
0
  GF_ImageMirrorBox *p = (GF_ImageMirrorBox *)a;
479
0
  gf_free(p);
480
0
}
481
482
GF_Err imir_box_read(GF_Box *s, GF_BitStream *bs)
483
0
{
484
0
  GF_ImageMirrorBox *p = (GF_ImageMirrorBox *)s;
485
0
  p->axis = gf_bs_read_u8(bs);
486
0
  if (p->type==GF_ISOM_BOX_TYPE_IMIR)
487
0
    p->axis = p->axis & 0x1;
488
0
  return GF_OK;
489
0
}
490
491
#ifndef GPAC_DISABLE_ISOM_WRITE
492
GF_Err imir_box_write(GF_Box *s, GF_BitStream *bs)
493
0
{
494
0
  GF_Err e;
495
0
  GF_ImageMirrorBox *p = (GF_ImageMirrorBox*)s;
496
0
  e = gf_isom_box_write_header(s, bs);
497
0
  if (e) return e;
498
0
  gf_bs_write_u8(bs, p->axis);
499
0
  return GF_OK;
500
0
}
501
502
GF_Err imir_box_size(GF_Box *s)
503
0
{
504
0
  GF_ImageMirrorBox *p = (GF_ImageMirrorBox*)s;
505
0
  p->size += 1;
506
0
  return GF_OK;
507
0
}
508
509
#endif /*GPAC_DISABLE_ISOM_WRITE*/
510
511
GF_Box *ipco_box_new()
512
0
{
513
0
  ISOM_DECL_BOX_ALLOC(GF_ItemPropertyContainerBox, GF_ISOM_BOX_TYPE_IPCO);
514
0
  return (GF_Box *)tmp;
515
0
}
516
517
void ipco_box_del(GF_Box *s)
518
0
{
519
0
  GF_ItemPropertyContainerBox *p = (GF_ItemPropertyContainerBox *)s;
520
0
  gf_free(p);
521
0
}
522
523
GF_Err ipco_box_read(GF_Box *s, GF_BitStream *bs)
524
0
{
525
0
  return gf_isom_box_array_read(s, bs);
526
0
}
527
528
#ifndef GPAC_DISABLE_ISOM_WRITE
529
530
GF_Err ipco_box_write(GF_Box *s, GF_BitStream *bs)
531
0
{
532
0
  if (!s) return GF_BAD_PARAM;
533
0
  return gf_isom_box_write_header(s, bs);
534
0
}
535
536
GF_Err ipco_box_size(GF_Box *s)
537
0
{
538
0
  return GF_OK;
539
0
}
540
#endif /*GPAC_DISABLE_ISOM_WRITE*/
541
542
GF_Box *iprp_box_new()
543
0
{
544
0
  ISOM_DECL_BOX_ALLOC(GF_ItemPropertiesBox, GF_ISOM_BOX_TYPE_IPRP);
545
0
  return (GF_Box *)tmp;
546
0
}
547
548
void iprp_box_del(GF_Box *s)
549
0
{
550
0
  gf_free(s);
551
0
}
552
553
GF_Err iprp_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem)
554
0
{
555
0
  GF_ItemPropertiesBox *ptr = (GF_ItemPropertiesBox *)s;
556
0
  switch (a->type) {
557
0
  case GF_ISOM_BOX_TYPE_IPCO:
558
0
    BOX_FIELD_ASSIGN(property_container, GF_ItemPropertyContainerBox)
559
0
    break;
560
0
  case GF_ISOM_BOX_TYPE_IPMA:
561
0
    BOX_FIELD_ASSIGN(property_association, GF_ItemPropertyAssociationBox)
562
0
    break;
563
0
  default:
564
0
    return GF_OK;
565
0
  }
566
0
  return GF_OK;
567
0
}
568
569
GF_Err iprp_box_read(GF_Box *s, GF_BitStream *bs)
570
0
{
571
0
  return gf_isom_box_array_read(s, bs);
572
0
}
573
574
#ifndef GPAC_DISABLE_ISOM_WRITE
575
576
GF_Err iprp_box_write(GF_Box *s, GF_BitStream *bs)
577
0
{
578
0
  return gf_isom_box_write_header(s, bs);
579
0
}
580
581
GF_Err iprp_box_size(GF_Box *s)
582
0
{
583
0
  u32 pos=0;
584
0
  GF_ItemPropertiesBox *p = (GF_ItemPropertiesBox *)s;
585
0
  gf_isom_check_position(s, (GF_Box*)p->property_container, &pos);
586
0
  gf_isom_check_position(s, (GF_Box*)p->property_association, &pos);
587
0
  return GF_OK;
588
0
}
589
590
#endif /*GPAC_DISABLE_ISOM_WRITE*/
591
592
GF_Box *ipma_box_new()
593
0
{
594
0
  ISOM_DECL_BOX_ALLOC(GF_ItemPropertyAssociationBox, GF_ISOM_BOX_TYPE_IPMA);
595
0
  tmp->entries = gf_list_new();
596
0
  return (GF_Box *)tmp;
597
0
}
598
599
void ipma_box_del(GF_Box *a)
600
0
{
601
0
  GF_ItemPropertyAssociationBox *p = (GF_ItemPropertyAssociationBox *)a;
602
0
  if (p->entries) {
603
0
    u32 i;
604
0
    u32 count;
605
0
    count = gf_list_count(p->entries);
606
607
0
    for (i = 0; i < count; i++) {
608
0
      GF_ItemPropertyAssociationEntry *entry = (GF_ItemPropertyAssociationEntry *)gf_list_get(p->entries, i);
609
0
      if (entry) {
610
0
        gf_free(entry->associations);
611
0
        gf_free(entry);
612
0
      }
613
0
    }
614
0
    gf_list_del(p->entries);
615
0
  }
616
0
  gf_free(p);
617
0
}
618
619
GF_Err ipma_box_read(GF_Box *s, GF_BitStream *bs)
620
0
{
621
0
  u32 i, j;
622
0
  GF_ItemPropertyAssociationBox *p = (GF_ItemPropertyAssociationBox *)s;
623
0
  u32 entry_count;
624
625
0
  ISOM_DECREASE_SIZE(p, 4)
626
0
  entry_count = gf_bs_read_u32(bs);
627
0
  for (i = 0; i < entry_count; i++) {
628
0
    GF_ItemPropertyAssociationEntry *entry;
629
0
    GF_SAFEALLOC(entry, GF_ItemPropertyAssociationEntry);
630
0
    if (!entry) return GF_OUT_OF_MEM;
631
0
    gf_list_add(p->entries, entry);
632
0
    if (p->version == 0) {
633
0
      ISOM_DECREASE_SIZE(p, 3)
634
0
      entry->item_id = gf_bs_read_u16(bs);
635
0
    } else {
636
0
      ISOM_DECREASE_SIZE(p, 5)
637
0
      entry->item_id = gf_bs_read_u32(bs);
638
0
    }
639
0
    entry->nb_associations = gf_bs_read_u8(bs);
640
0
    entry->associations = gf_malloc(sizeof(GF_ItemPropertyAssociationSlot) * entry->nb_associations);
641
0
    if (!entry->associations) return GF_OUT_OF_MEM;
642
0
    for (j = 0; j < entry->nb_associations; j++) {
643
0
      if (p->flags & 1) {
644
0
        u16 tmp = gf_bs_read_u16(bs);
645
0
        entry->associations[j].essential = (tmp >> 15) ? GF_TRUE : GF_FALSE;
646
0
        entry->associations[j].index = (tmp & 0x7FFF);
647
0
      } else {
648
0
        u8 tmp = gf_bs_read_u8(bs);
649
0
        entry->associations[j].essential = (tmp >> 7) ? GF_TRUE : GF_FALSE;
650
0
        entry->associations[j].index = (tmp & 0x7F);
651
0
      }
652
0
    }
653
0
  }
654
0
  return GF_OK;
655
0
}
656
657
#ifndef GPAC_DISABLE_ISOM_WRITE
658
GF_Err ipma_box_write(GF_Box *s, GF_BitStream *bs)
659
0
{
660
0
  u32 i, j;
661
0
  GF_Err e;
662
0
  u32 entry_count;
663
0
  GF_ItemPropertyAssociationBox *p = (GF_ItemPropertyAssociationBox*)s;
664
665
0
  e = gf_isom_full_box_write(s, bs);
666
0
  if (e) return e;
667
0
  entry_count = gf_list_count(p->entries);
668
0
  gf_bs_write_u32(bs, entry_count);
669
0
  for (i = 0; i < entry_count; i++) {
670
0
    GF_ItemPropertyAssociationEntry *entry = (GF_ItemPropertyAssociationEntry *)gf_list_get(p->entries, i);
671
0
    if (p->version == 0) {
672
0
      gf_bs_write_u16(bs, entry->item_id);
673
0
    } else {
674
0
      gf_bs_write_u32(bs, entry->item_id);
675
0
    }
676
0
    gf_bs_write_u8(bs, entry->nb_associations);
677
0
    for (j = 0; j < entry->nb_associations; j++) {
678
0
      if (p->flags & 1) {
679
0
        gf_bs_write_u16(bs, (u16)( ( (entry->associations[j].essential ? 1 : 0) << 15) | (entry->associations[j].index & 0x7F) ) );
680
0
      } else {
681
0
        gf_bs_write_u8(bs, (u32)(( (entry->associations[j].essential ? 1 : 0) << 7) | entry->associations[j].index));
682
0
      }
683
0
    }
684
0
  }
685
0
  return GF_OK;
686
0
}
687
688
GF_Err ipma_box_size(GF_Box *s)
689
0
{
690
0
  u32 i;
691
0
  u32 entry_count;
692
0
  GF_ItemPropertyAssociationBox *p = (GF_ItemPropertyAssociationBox*)s;
693
694
0
  entry_count = gf_list_count(p->entries);
695
0
  p->size += 4;
696
0
  if (p->version == 0) {
697
0
    p->size += entry_count * 2;
698
0
  } else {
699
0
    p->size += entry_count * 4;
700
0
  }
701
0
  p->size += entry_count;
702
0
  for (i = 0; i < entry_count; i++) {
703
0
    GF_ItemPropertyAssociationEntry *entry = (GF_ItemPropertyAssociationEntry *)gf_list_get(p->entries, i);
704
0
    if (p->flags & 1) {
705
0
      p->size += entry->nb_associations * 2;
706
0
    } else {
707
0
      p->size += entry->nb_associations;
708
0
    }
709
0
  }
710
0
  return GF_OK;
711
0
}
712
713
#endif /*GPAC_DISABLE_ISOM_WRITE*/
714
715
GF_Box *grpl_box_new()
716
0
{
717
0
  ISOM_DECL_BOX_ALLOC(GF_GroupListBox, GF_ISOM_BOX_TYPE_GRPL);
718
0
  return (GF_Box *)tmp;
719
0
}
720
721
void grpl_box_del(GF_Box *s)
722
0
{
723
0
  GF_GroupListBox *p = (GF_GroupListBox *)s;
724
0
  gf_free(p);
725
0
}
726
727
GF_Err grpl_box_read(GF_Box *s, GF_BitStream *bs)
728
0
{
729
0
  return gf_isom_box_array_read(s, bs);
730
0
}
731
732
#ifndef GPAC_DISABLE_ISOM_WRITE
733
734
GF_Err grpl_box_write(GF_Box *s, GF_BitStream *bs)
735
0
{
736
0
  if (!s) return GF_BAD_PARAM;
737
0
  return gf_isom_box_write_header(s, bs);
738
0
}
739
740
GF_Err grpl_box_size(GF_Box *s)
741
0
{
742
0
  return GF_OK;
743
0
}
744
#endif /*GPAC_DISABLE_ISOM_WRITE*/
745
746
747
void grptype_box_del(GF_Box *s)
748
0
{
749
0
  GF_EntityToGroupTypeBox *ptr = (GF_EntityToGroupTypeBox *)s;
750
0
  if (!ptr) return;
751
0
  if (ptr->entity_ids) gf_free(ptr->entity_ids);
752
0
  if (ptr->data) gf_free(ptr->data);
753
0
  gf_free(ptr);
754
0
}
755
756
757
GF_Err grptype_box_read(GF_Box *s, GF_BitStream *bs)
758
0
{
759
0
  u32 i;
760
0
  GF_EntityToGroupTypeBox *ptr = (GF_EntityToGroupTypeBox *)s;
761
762
0
  ISOM_DECREASE_SIZE(ptr, 8)
763
0
  ptr->group_id = gf_bs_read_u32(bs);
764
0
  ptr->entity_id_count = gf_bs_read_u32(bs);
765
766
0
  if (ptr->entity_id_count > ptr->size / 4) return GF_ISOM_INVALID_FILE;
767
768
0
  ptr->entity_ids = (u32 *) gf_malloc(ptr->entity_id_count * sizeof(u32));
769
0
  if (!ptr->entity_ids) return GF_OUT_OF_MEM;
770
771
0
  for (i = 0; i < ptr->entity_id_count; i++) {
772
0
    ptr->entity_ids[i] = gf_bs_read_u32(bs);
773
0
    ISOM_DECREASE_SIZE(ptr, 4)
774
0
  }
775
776
0
  if (ptr->size) {
777
0
    ptr->data = gf_malloc((u32) ptr->size);
778
0
    if (!ptr->data) return GF_OUT_OF_MEM;
779
0
    ptr->data_len = (u32) ptr->size;
780
0
    gf_bs_read_data(bs, ptr->data, ptr->data_len);
781
0
    ptr->size = 0;
782
0
  }
783
0
  return GF_OK;
784
0
}
785
786
GF_Box *grptype_box_new()
787
0
{
788
0
  ISOM_DECL_BOX_ALLOC(GF_EntityToGroupTypeBox, GF_ISOM_BOX_TYPE_GRPT);
789
  //the group type code is assign in gf_isom_box_parse_ex
790
0
  return (GF_Box *)tmp;
791
0
}
792
793
#ifndef GPAC_DISABLE_ISOM_WRITE
794
795
GF_Err grptype_box_write(GF_Box *s, GF_BitStream *bs)
796
0
{
797
0
  GF_Err e;
798
0
  u32 i;
799
0
  GF_EntityToGroupTypeBox *ptr = (GF_EntityToGroupTypeBox *)s;
800
0
  ptr->type = ptr->grouping_type;
801
0
  e = gf_isom_full_box_write(s, bs);
802
0
  if (e) return e;
803
0
  ptr->type = GF_ISOM_BOX_TYPE_GRPT;
804
805
0
  gf_bs_write_u32(bs, ptr->group_id);
806
0
  gf_bs_write_u32(bs, ptr->entity_id_count);
807
808
0
  for (i = 0; i < ptr->entity_id_count; i++) {
809
0
    gf_bs_write_u32(bs, ptr->entity_ids[i]);
810
0
  }
811
0
  if (ptr->data) gf_bs_write_data(bs, ptr->data, ptr->data_len);
812
0
  return GF_OK;
813
0
}
814
815
816
GF_Err grptype_box_size(GF_Box *s)
817
0
{
818
0
  GF_EntityToGroupTypeBox *ptr = (GF_EntityToGroupTypeBox *)s;
819
0
  ptr->size += 8 + 4*ptr->entity_id_count + ptr->data_len;
820
0
  return GF_OK;
821
0
}
822
823
#endif /*GPAC_DISABLE_ISOM_WRITE*/
824
825
826
GF_Box *auxc_box_new()
827
0
{
828
0
  ISOM_DECL_BOX_ALLOC(GF_AuxiliaryTypePropertyBox, GF_ISOM_BOX_TYPE_AUXC);
829
0
  return (GF_Box *)tmp;
830
0
}
831
832
void auxc_box_del(GF_Box *a)
833
0
{
834
0
  GF_AuxiliaryTypePropertyBox *p = (GF_AuxiliaryTypePropertyBox *)a;
835
0
  if (p->aux_urn) gf_free(p->aux_urn);
836
0
  if (p->data) gf_free(p->data);
837
0
  gf_free(p);
838
0
}
839
840
GF_Err auxc_box_read(GF_Box *s, GF_BitStream *bs)
841
0
{
842
0
  GF_AuxiliaryTypePropertyBox *p = (GF_AuxiliaryTypePropertyBox *)s;
843
0
  GF_Err e;
844
845
0
  e = gf_isom_read_null_terminated_string(s, bs, s->size, &p->aux_urn);
846
0
  if (e) return e;
847
0
  p->data_size = (u32) p->size;
848
0
  p->data = gf_malloc(sizeof(char) * p->data_size);
849
0
  gf_bs_read_data(bs, p->data, p->data_size);
850
0
  return GF_OK;
851
0
}
852
853
#ifndef GPAC_DISABLE_ISOM_WRITE
854
GF_Err auxc_box_write(GF_Box *s, GF_BitStream *bs)
855
0
{
856
0
  GF_Err e;
857
0
  GF_AuxiliaryTypePropertyBox *p = (GF_AuxiliaryTypePropertyBox*)s;
858
859
0
  e = gf_isom_full_box_write(s, bs);
860
0
  if (e) return e;
861
  //with terminating 0
862
0
  if (p->aux_urn)
863
0
    gf_bs_write_data(bs, p->aux_urn, (u32) strlen(p->aux_urn) );
864
0
  gf_bs_write_u8(bs, 0);
865
0
  gf_bs_write_data(bs, p->data, p->data_size);
866
867
0
  return GF_OK;
868
0
}
869
870
GF_Err auxc_box_size(GF_Box *s)
871
0
{
872
0
  GF_AuxiliaryTypePropertyBox *p = (GF_AuxiliaryTypePropertyBox*)s;
873
0
  p->size += (p->aux_urn ? strlen(p->aux_urn) : 0) + 1 + p->data_size;
874
0
  return GF_OK;
875
0
}
876
877
#endif /*GPAC_DISABLE_ISOM_WRITE*/
878
879
void auxi_box_del(GF_Box *s)
880
0
{
881
0
  GF_AuxiliaryTypeInfoBox *ptr = (GF_AuxiliaryTypeInfoBox *)s;
882
0
  if (ptr->aux_track_type) gf_free(ptr->aux_track_type);
883
0
  if (ptr) gf_free(ptr);
884
0
  return;
885
0
}
886
887
GF_Err auxi_box_read(GF_Box *s, GF_BitStream *bs)
888
0
{
889
0
  GF_AuxiliaryTypeInfoBox *ptr = (GF_AuxiliaryTypeInfoBox *)s;
890
0
  return gf_isom_read_null_terminated_string(s, bs, s->size, &ptr->aux_track_type);
891
0
}
892
893
GF_Box *auxi_box_new()
894
0
{
895
0
  ISOM_DECL_BOX_ALLOC(GF_AuxiliaryTypeInfoBox, GF_ISOM_BOX_TYPE_AUXI);
896
0
  return (GF_Box *) tmp;
897
0
}
898
899
#ifndef GPAC_DISABLE_ISOM_WRITE
900
901
GF_Err auxi_box_write(GF_Box *s, GF_BitStream *bs)
902
0
{
903
0
  GF_Err e;
904
0
  GF_AuxiliaryTypeInfoBox *ptr = (GF_AuxiliaryTypeInfoBox *)s;
905
906
0
  e = gf_isom_full_box_write(s, bs);
907
0
  if (e) return e;
908
  //with terminating 0
909
0
  if (ptr->aux_track_type)
910
0
    gf_bs_write_data(bs, ptr->aux_track_type, (u32) strlen(ptr->aux_track_type) );
911
0
  gf_bs_write_u8(bs, 0);
912
0
  return GF_OK;
913
0
}
914
915
GF_Err auxi_box_size(GF_Box *s)
916
0
{
917
0
  GF_AuxiliaryTypeInfoBox *ptr = (GF_AuxiliaryTypeInfoBox *)s;
918
0
  ptr->size += (ptr->aux_track_type ? strlen(ptr->aux_track_type) : 0 )+ 1;
919
0
  return GF_OK;
920
0
}
921
922
#endif /*GPAC_DISABLE_ISOM_WRITE*/
923
GF_Box *oinf_box_new()
924
0
{
925
0
  ISOM_DECL_BOX_ALLOC(GF_OINFPropertyBox, GF_ISOM_BOX_TYPE_OINF);
926
0
  tmp->oinf = gf_isom_oinf_new_entry();
927
0
  return (GF_Box *)tmp;
928
0
}
929
930
void oinf_box_del(GF_Box *a)
931
0
{
932
0
  GF_OINFPropertyBox *p = (GF_OINFPropertyBox *)a;
933
0
  if (p->oinf) gf_isom_oinf_del_entry(p->oinf);
934
0
  gf_free(p);
935
0
}
936
937
GF_Err oinf_box_read(GF_Box *s, GF_BitStream *bs)
938
0
{
939
0
  GF_OINFPropertyBox *p = (GF_OINFPropertyBox *)s;
940
0
  return gf_isom_oinf_read_entry(p->oinf, bs);
941
0
}
942
943
#ifndef GPAC_DISABLE_ISOM_WRITE
944
GF_Err oinf_box_write(GF_Box *s, GF_BitStream *bs)
945
0
{
946
0
  GF_Err e;
947
0
  GF_OINFPropertyBox *p = (GF_OINFPropertyBox*)s;
948
949
0
  e = gf_isom_full_box_write(s, bs);
950
0
  if (e) return e;
951
0
  return gf_isom_oinf_write_entry(p->oinf, bs);
952
0
}
953
954
GF_Err oinf_box_size(GF_Box *s)
955
0
{
956
0
  GF_OINFPropertyBox *p = (GF_OINFPropertyBox*)s;
957
0
  if (!p->oinf) return GF_BAD_PARAM;
958
0
  p->size += gf_isom_oinf_size_entry(p->oinf);
959
0
  return GF_OK;
960
0
}
961
962
#endif /*GPAC_DISABLE_ISOM_WRITE*/
963
964
GF_Box *tols_box_new()
965
0
{
966
0
  ISOM_DECL_BOX_ALLOC(GF_TargetOLSPropertyBox, GF_ISOM_BOX_TYPE_TOLS);
967
0
  return (GF_Box *)tmp;
968
0
}
969
970
void tols_box_del(GF_Box *a)
971
0
{
972
0
  gf_free(a);
973
0
}
974
975
GF_Err tols_box_read(GF_Box *s, GF_BitStream *bs)
976
0
{
977
0
  GF_TargetOLSPropertyBox *p = (GF_TargetOLSPropertyBox *)s;
978
979
0
  ISOM_DECREASE_SIZE(p, 2)
980
0
  p->target_ols_index = gf_bs_read_u16(bs);
981
0
  return GF_OK;
982
0
}
983
984
#ifndef GPAC_DISABLE_ISOM_WRITE
985
GF_Err tols_box_write(GF_Box *s, GF_BitStream *bs)
986
0
{
987
0
  GF_Err e;
988
0
  GF_TargetOLSPropertyBox *p = (GF_TargetOLSPropertyBox*)s;
989
990
0
  e = gf_isom_full_box_write(s, bs);
991
0
  if (e) return e;
992
0
  gf_bs_write_u16(bs, p->target_ols_index);
993
0
  return GF_OK;
994
0
}
995
996
GF_Err tols_box_size(GF_Box *s)
997
0
{
998
0
  GF_TargetOLSPropertyBox *p = (GF_TargetOLSPropertyBox*)s;
999
0
  p->size += 2;
1000
0
  return GF_OK;
1001
0
}
1002
1003
#endif /*GPAC_DISABLE_ISOM_WRITE*/
1004
1005
1006
GF_Box *clli_box_new()
1007
0
{
1008
0
  ISOM_DECL_BOX_ALLOC(GF_ContentLightLevelBox, GF_ISOM_BOX_TYPE_CLLI);
1009
0
  return (GF_Box *)tmp;
1010
0
}
1011
1012
void clli_box_del(GF_Box *a)
1013
0
{
1014
0
  GF_ContentLightLevelBox *p = (GF_ContentLightLevelBox *)a;
1015
0
  gf_free(p);
1016
0
}
1017
1018
GF_Err clli_box_read(GF_Box *s, GF_BitStream *bs)
1019
0
{
1020
0
  GF_ContentLightLevelBox *p = (GF_ContentLightLevelBox *)s;
1021
0
  ISOM_DECREASE_SIZE(p, 4)
1022
0
  p->clli.max_content_light_level = gf_bs_read_u16(bs);
1023
0
  p->clli.max_pic_average_light_level = gf_bs_read_u16(bs);
1024
0
  return GF_OK;
1025
0
}
1026
1027
#ifndef GPAC_DISABLE_ISOM_WRITE
1028
1029
GF_Err clli_box_write(GF_Box *s, GF_BitStream *bs)
1030
0
{
1031
0
  GF_Err e;
1032
0
  GF_ContentLightLevelBox *p = (GF_ContentLightLevelBox*)s;
1033
0
  e = gf_isom_box_write_header(s, bs);
1034
0
  if (e) return e;
1035
0
  gf_bs_write_u16(bs, p->clli.max_content_light_level);
1036
0
  gf_bs_write_u16(bs, p->clli.max_pic_average_light_level);
1037
0
  return GF_OK;
1038
0
}
1039
1040
GF_Err clli_box_size(GF_Box *s)
1041
0
{
1042
0
  GF_ContentLightLevelBox *p = (GF_ContentLightLevelBox*)s;
1043
0
  p->size += 4;
1044
0
  return GF_OK;
1045
0
}
1046
1047
#endif /*GPAC_DISABLE_ISOM_WRITE*/
1048
1049
1050
GF_Box *mdcv_box_new()
1051
0
{
1052
0
  ISOM_DECL_BOX_ALLOC(GF_MasteringDisplayColourVolumeBox, GF_ISOM_BOX_TYPE_MDCV);
1053
0
  return (GF_Box *)tmp;
1054
0
}
1055
1056
void mdcv_box_del(GF_Box *a)
1057
0
{
1058
0
  GF_MasteringDisplayColourVolumeBox *p = (GF_MasteringDisplayColourVolumeBox *)a;
1059
0
  gf_free(p);
1060
0
}
1061
1062
GF_Err mdcv_box_read(GF_Box *s, GF_BitStream *bs)
1063
0
{
1064
0
  int c = 0;
1065
0
  GF_MasteringDisplayColourVolumeBox *p = (GF_MasteringDisplayColourVolumeBox *)s;
1066
0
  ISOM_DECREASE_SIZE(p, 24)
1067
0
  for (c = 0; c<3; c++) {
1068
0
    p->mdcv.display_primaries[c].x = gf_bs_read_u16(bs);
1069
0
    p->mdcv.display_primaries[c].y = gf_bs_read_u16(bs);
1070
0
  }
1071
0
  p->mdcv.white_point_x = gf_bs_read_u16(bs);
1072
0
  p->mdcv.white_point_y = gf_bs_read_u16(bs);
1073
0
  p->mdcv.max_display_mastering_luminance = gf_bs_read_u32(bs);
1074
0
  p->mdcv.min_display_mastering_luminance = gf_bs_read_u32(bs);
1075
1076
0
  return GF_OK;
1077
0
}
1078
1079
#ifndef GPAC_DISABLE_ISOM_WRITE
1080
1081
GF_Err mdcv_box_write(GF_Box *s, GF_BitStream *bs)
1082
0
{
1083
0
  int c = 0;
1084
0
  GF_Err e;
1085
0
  GF_MasteringDisplayColourVolumeBox *p = (GF_MasteringDisplayColourVolumeBox*)s;
1086
0
  e = gf_isom_box_write_header(s, bs);
1087
0
  if (e) return e;
1088
1089
0
  for (c = 0; c<3; c++) {
1090
0
    gf_bs_write_u16(bs, p->mdcv.display_primaries[c].x);
1091
0
    gf_bs_write_u16(bs, p->mdcv.display_primaries[c].y);
1092
0
  }
1093
0
  gf_bs_write_u16(bs, p->mdcv.white_point_x);
1094
0
  gf_bs_write_u16(bs, p->mdcv.white_point_y);
1095
0
  gf_bs_write_u32(bs, p->mdcv.max_display_mastering_luminance);
1096
0
  gf_bs_write_u32(bs, p->mdcv.min_display_mastering_luminance);
1097
  
1098
0
  return GF_OK;
1099
0
}
1100
1101
GF_Err mdcv_box_size(GF_Box *s)
1102
0
{
1103
0
  GF_MasteringDisplayColourVolumeBox *p = (GF_MasteringDisplayColourVolumeBox*)s;
1104
0
  p->size += 24;
1105
0
  return GF_OK;
1106
0
}
1107
1108
#endif /*GPAC_DISABLE_ISOM_WRITE*/
1109
1110
1111
GF_Box *ienc_box_new()
1112
0
{
1113
0
  ISOM_DECL_BOX_ALLOC(GF_ItemEncryptionPropertyBox, GF_ISOM_BOX_TYPE_IENC);
1114
0
  return (GF_Box *)tmp;
1115
0
}
1116
1117
void ienc_box_del(GF_Box *a)
1118
0
{
1119
0
  GF_ItemEncryptionPropertyBox *p = (GF_ItemEncryptionPropertyBox *)a;
1120
0
  if (p->key_info) gf_free(p->key_info);
1121
0
  gf_free(p);
1122
0
}
1123
1124
GF_Err ienc_box_read(GF_Box *s, GF_BitStream *bs)
1125
0
{
1126
0
  u32 nb_keys;
1127
0
  GF_ItemEncryptionPropertyBox *p = (GF_ItemEncryptionPropertyBox *)s;
1128
1129
0
  ISOM_DECREASE_SIZE(p, 3)
1130
0
  gf_bs_read_u8(bs);
1131
0
  if (p->version == 0) {
1132
0
    gf_bs_read_u8(bs);
1133
0
  } else {
1134
0
    p->skip_byte_block = gf_bs_read_int(bs, 4);
1135
0
    p->crypt_byte_block = gf_bs_read_int(bs, 4);
1136
0
  }
1137
0
  nb_keys = gf_bs_read_u8(bs);
1138
0
  if (nb_keys * (sizeof(bin128)+1) > p->size)
1139
0
    return GF_NON_COMPLIANT_BITSTREAM;
1140
0
  p->key_info_size = (u32) (3+p->size);
1141
0
  p->key_info = gf_malloc(sizeof(u8) * p->key_info_size);
1142
0
  if (!p->key_info) return GF_OUT_OF_MEM;
1143
0
  p->key_info[0] = 1;
1144
0
  p->key_info[1] = 0;
1145
0
  p->key_info[2] = nb_keys;
1146
0
  gf_bs_read_data(bs, p->key_info+3, (u32) p->size);
1147
0
  p->size = 0;
1148
0
  if (!gf_cenc_validate_key_info(p->key_info, p->key_info_size))
1149
0
    return GF_ISOM_INVALID_FILE;
1150
0
  return GF_OK;
1151
0
}
1152
1153
#ifndef GPAC_DISABLE_ISOM_WRITE
1154
GF_Err ienc_box_write(GF_Box *s, GF_BitStream *bs)
1155
0
{
1156
0
  GF_Err e;
1157
0
  u32 nb_keys;
1158
0
  GF_ItemEncryptionPropertyBox *p = (GF_ItemEncryptionPropertyBox*)s;
1159
0
  if (p->skip_byte_block || p->crypt_byte_block)
1160
0
    p->version = 1;
1161
0
  e = gf_isom_full_box_write(s, bs);
1162
0
  if (e) return e;
1163
0
  gf_bs_write_u8(bs, 0);
1164
0
  if (p->version) {
1165
0
    gf_bs_write_int(bs, p->skip_byte_block, 4);
1166
0
    gf_bs_write_int(bs, p->crypt_byte_block, 4);
1167
0
  } else {
1168
0
    gf_bs_write_u8(bs, 0);
1169
0
  }
1170
0
  if (p->key_info[0]) {
1171
0
    if (p->key_info[1]) {
1172
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Too many keys for ienc box, max is 255)\n"))
1173
0
      return GF_BAD_PARAM;
1174
0
    }
1175
0
    nb_keys = p->key_info[2];
1176
0
  } else {
1177
0
    nb_keys = 1;
1178
0
  }
1179
0
  gf_bs_write_u8(bs, nb_keys);
1180
0
  gf_bs_write_data(bs, p->key_info+3, p->key_info_size-3);
1181
0
  return GF_OK;
1182
0
}
1183
1184
GF_Err ienc_box_size(GF_Box *s)
1185
0
{
1186
0
  GF_ItemEncryptionPropertyBox *p = (GF_ItemEncryptionPropertyBox*)s;
1187
0
  if (!p->key_info || (p->key_info_size<19))
1188
0
    return GF_BAD_PARAM;
1189
0
  p->size += 3 + p->key_info_size-3;
1190
0
  return GF_OK;
1191
0
}
1192
1193
#endif /*GPAC_DISABLE_ISOM_WRITE*/
1194
1195
1196
GF_Box *iaux_box_new()
1197
0
{
1198
0
  ISOM_DECL_BOX_ALLOC(GF_AuxiliaryInfoPropertyBox, GF_ISOM_BOX_TYPE_IAUX);
1199
0
  return (GF_Box *)tmp;
1200
0
}
1201
1202
void iaux_box_del(GF_Box *a)
1203
0
{
1204
0
  gf_free(a);
1205
0
}
1206
1207
GF_Err iaux_box_read(GF_Box *s, GF_BitStream *bs)
1208
0
{
1209
0
  GF_AuxiliaryInfoPropertyBox *p = (GF_AuxiliaryInfoPropertyBox *)s;
1210
1211
0
  ISOM_DECREASE_SIZE(p, 8)
1212
0
  p->aux_info_type = gf_bs_read_u32(bs);
1213
0
  p->aux_info_parameter = gf_bs_read_u32(bs);
1214
0
  return GF_OK;
1215
0
}
1216
1217
#ifndef GPAC_DISABLE_ISOM_WRITE
1218
GF_Err iaux_box_write(GF_Box *s, GF_BitStream *bs)
1219
0
{
1220
0
  GF_Err e;
1221
0
  GF_AuxiliaryInfoPropertyBox *p = (GF_AuxiliaryInfoPropertyBox*)s;
1222
1223
0
  e = gf_isom_full_box_write(s, bs);
1224
0
  if (e) return e;
1225
0
  gf_bs_write_u32(bs, p->aux_info_type);
1226
0
  gf_bs_write_u32(bs, p->aux_info_parameter);
1227
0
  return GF_OK;
1228
0
}
1229
1230
GF_Err iaux_box_size(GF_Box *s)
1231
0
{
1232
0
  GF_AuxiliaryInfoPropertyBox *p = (GF_AuxiliaryInfoPropertyBox*)s;
1233
0
  p->size += 8;
1234
0
  return GF_OK;
1235
0
}
1236
1237
#endif /*GPAC_DISABLE_ISOM_WRITE*/
1238
1239
GF_Box *fnch_box_new()
1240
0
{
1241
0
  ISOM_DECL_BOX_ALLOC(GF_FontCharacteristicsPropertyBox, GF_ISOM_BOX_TYPE_FNCH);
1242
0
  return (GF_Box *)tmp;
1243
0
}
1244
1245
void fnch_box_del(GF_Box *a)
1246
0
{
1247
0
  GF_FontCharacteristicsPropertyBox *p = (GF_FontCharacteristicsPropertyBox *)a;
1248
0
  if (p->font_family)
1249
0
    gf_free(p->font_family);
1250
0
  if (p->font_style)
1251
0
    gf_free(p->font_style);
1252
0
  if (p->font_weight)
1253
0
    gf_free(p->font_weight);
1254
0
  gf_free(p);
1255
0
}
1256
1257
GF_Err fnch_box_read(GF_Box *s, GF_BitStream *bs)
1258
0
{
1259
0
  GF_FontCharacteristicsPropertyBox *p = (GF_FontCharacteristicsPropertyBox *)s;
1260
1261
0
  p->font_family = gf_bs_read_utf8(bs);
1262
0
  p->font_style = gf_bs_read_utf8(bs);
1263
0
  p->font_weight = gf_bs_read_utf8(bs);
1264
0
  return GF_OK;
1265
0
}
1266
1267
#ifndef GPAC_DISABLE_ISOM_WRITE
1268
GF_Err fnch_box_write(GF_Box *s, GF_BitStream *bs)
1269
0
{
1270
0
  GF_Err e;
1271
0
  GF_FontCharacteristicsPropertyBox *p = (GF_FontCharacteristicsPropertyBox *)s;
1272
1273
0
  e = gf_isom_full_box_write(s, bs);
1274
0
  if (e)
1275
0
    return e;
1276
0
  gf_bs_write_utf8(bs, p->font_family);
1277
0
  gf_bs_write_utf8(bs, p->font_style);
1278
0
  gf_bs_write_utf8(bs, p->font_weight);
1279
0
  return GF_OK;
1280
0
}
1281
1282
GF_Err fnch_box_size(GF_Box *s)
1283
0
{
1284
0
  GF_FontCharacteristicsPropertyBox *p = (GF_FontCharacteristicsPropertyBox *)s;
1285
0
  p->size += (p->font_family ? strlen(p->font_family) : 0) + 1;
1286
0
  p->size += (p->font_style ? strlen(p->font_style) : 0) + 1;
1287
0
  p->size += (p->font_weight ? strlen(p->font_weight) : 0) + 1;
1288
0
  return GF_OK;
1289
0
}
1290
#endif /*GPAC_DISABLE_ISOM_WRITE*/
1291
1292
GF_Box *txlo_box_new()
1293
0
{
1294
0
  ISOM_DECL_BOX_ALLOC(GF_TextLayoutPropertyBox, GF_ISOM_BOX_TYPE_TXLO);
1295
0
  return (GF_Box *)tmp;
1296
0
}
1297
1298
void txlo_box_del(GF_Box *a)
1299
0
{
1300
0
  GF_TextLayoutPropertyBox *p = (GF_TextLayoutPropertyBox *)a;
1301
0
  if (p->direction)
1302
0
    gf_free(p->direction);
1303
0
  if (p->writing_mode)
1304
0
    gf_free(p->writing_mode);
1305
0
  gf_free(p);
1306
0
}
1307
1308
GF_Err txlo_box_read(GF_Box *s, GF_BitStream *bs)
1309
0
{
1310
0
  GF_TextLayoutPropertyBox *p = (GF_TextLayoutPropertyBox *)s;
1311
1312
0
  if ((p->flags & 0x1) == 1)
1313
0
  {
1314
0
    p->reference_width = gf_bs_read_u32(bs);
1315
0
    p->reference_height = gf_bs_read_u32(bs);
1316
0
    p->x = (s32)gf_bs_read_u32(bs);
1317
0
    p->y = (s32)gf_bs_read_u32(bs);
1318
0
    p->width = gf_bs_read_u32(bs);
1319
0
    p->height = gf_bs_read_u32(bs);
1320
0
  }
1321
0
  else
1322
0
  {
1323
0
    p->reference_width = gf_bs_read_u16(bs);
1324
0
    p->reference_height = gf_bs_read_u16(bs);
1325
0
    p->x = (s16)gf_bs_read_u16(bs);
1326
0
    p->y = (s16)gf_bs_read_u16(bs);
1327
0
    p->width = gf_bs_read_u16(bs);
1328
0
    p->height = gf_bs_read_u16(bs);
1329
0
  }
1330
0
  p->font_size = gf_bs_read_u16(bs);
1331
0
  p->direction = gf_bs_read_utf8(bs);
1332
0
  p->writing_mode = gf_bs_read_utf8(bs);
1333
0
  return GF_OK;
1334
0
}
1335
1336
#ifndef GPAC_DISABLE_ISOM_WRITE
1337
GF_Err txlo_box_write(GF_Box *s, GF_BitStream *bs)
1338
0
{
1339
0
  GF_Err e;
1340
0
  GF_TextLayoutPropertyBox *p = (GF_TextLayoutPropertyBox *)s;
1341
0
  p->flags = 0x01;
1342
1343
0
  e = gf_isom_full_box_write(s, bs);
1344
0
  if (e)
1345
0
    return e;
1346
0
  gf_bs_write_u32(bs, p->reference_width);
1347
0
  gf_bs_write_u32(bs, p->reference_height);
1348
0
  gf_bs_write_u32(bs, (u32)p->x);
1349
0
  gf_bs_write_u32(bs, (u32)p->y);
1350
0
  gf_bs_write_u32(bs, p->width);
1351
0
  gf_bs_write_u32(bs, p->height);
1352
0
  gf_bs_write_u16(bs, p->font_size);
1353
0
  gf_bs_write_utf8(bs, p->direction);
1354
0
  gf_bs_write_utf8(bs, p->writing_mode);
1355
0
  return GF_OK;
1356
0
}
1357
1358
GF_Err txlo_box_size(GF_Box *s)
1359
0
{
1360
0
  GF_TextLayoutPropertyBox *p = (GF_TextLayoutPropertyBox *)s;
1361
0
  p->size += 26;
1362
0
  p->size += (p->direction ? strlen(p->direction) : 0) + 1;
1363
0
  p->size += (p->writing_mode ? strlen(p->writing_mode) : 0) + 1;
1364
0
  return GF_OK;
1365
0
}
1366
#endif /*GPAC_DISABLE_ISOM_WRITE*/
1367
1368
#ifndef GPAC_DISABLE_ISOM_WRITE
1369
1370
0
static GF_Err gf_isom_iff_create_image_item_from_track_internal(GF_ISOFile *movie, Bool root_meta, u32 meta_track_number, u32 imported_track, const char *item_name, u32 item_id, GF_ImageItemProperties *image_props, GF_List *item_extent_refs, u32 sample_number) {
1371
0
  GF_Err e;
1372
0
  u32 w, h, hSpacing, vSpacing;
1373
0
  u8 num_channels;
1374
0
  u8 bits_per_channel[3];
1375
0
  u32 subtype;
1376
0
  GF_ISOSample *sample = NULL;
1377
0
  u32 timescale;
1378
0
  u32 item_type = 0;
1379
0
  GF_ImageItemProperties local_image_props;
1380
0
  GF_ImageItemProtection ipro, *orig_ipro = NULL;
1381
0
  Bool config_needed = 0;
1382
0
  GF_Box *config_box = NULL;
1383
0
  Bool is_cenc = GF_FALSE;
1384
0
  Bool is_first = GF_TRUE;
1385
0
  Bool neg_time = (image_props && image_props->time<0) ? GF_TRUE : GF_FALSE;
1386
0
  char *tile_name = NULL;
1387
0
  u8 *sai = NULL;
1388
0
  u32 sai_size = 0, sai_alloc_size = 0;
1389
0
  u32 sample_desc_index = 0;
1390
0
  GF_ISOFile *fsrc = movie;
1391
0
  Bool reset_brands = GF_FALSE;
1392
1393
  //only reset brands if first item import
1394
0
  if (!gf_isom_get_meta_item_count(movie, root_meta, meta_track_number))
1395
0
    reset_brands = GF_TRUE;
1396
1397
0
  if (image_props && image_props->src_file)
1398
0
    fsrc = image_props->src_file;
1399
1400
0
  if (image_props && image_props->tile_mode != TILE_ITEM_NONE) {
1401
    /* Processing the input file in Tiled mode:
1402
       The single track is split into multiple tracks
1403
       and each track is processed to create an item */
1404
0
    u32 i, count;
1405
0
    u32 tile_track;
1406
0
    GF_List *tile_item_ids;
1407
0
    GF_TileItemMode orig_tile_mode;
1408
1409
0
#if !defined(GPAC_DISABLE_AV_PARSERS) && !defined(GPAC_DISABLE_MEDIA_IMPORT)
1410
0
    if (image_props->src_file)
1411
0
      e = GF_SERVICE_ERROR;
1412
0
    else
1413
0
      e = gf_media_split_hevc_tiles(movie, 0);
1414
#else
1415
    e = GF_NOT_SUPPORTED;
1416
#endif
1417
1418
0
    if (e) return e;
1419
0
    tile_item_ids = gf_list_new();
1420
0
    orig_tile_mode = image_props->tile_mode;
1421
0
    image_props->tile_mode = TILE_ITEM_NONE;
1422
0
    count = gf_isom_get_reference_count(movie, imported_track, GF_ISOM_REF_SABT);
1423
0
    for (i = 0; i < count; i++) {
1424
0
      u32 *tile_item_id = gf_malloc(sizeof(u32));
1425
0
      if (!tile_item_id) return GF_OUT_OF_MEM;
1426
1427
0
      *tile_item_id = item_id + i+1;
1428
0
      gf_list_add(tile_item_ids, tile_item_id);
1429
0
      e = gf_isom_get_reference(movie, imported_track, GF_ISOM_REF_SABT, 1, &tile_track);
1430
0
      if (e) return e;
1431
0
      tile_name = NULL;
1432
0
      if (item_name) {
1433
0
        char szTmp[50];
1434
0
        sprintf(szTmp, "-Tile%d", i+1);
1435
0
        gf_dynstrcat(&tile_name, item_name, NULL);
1436
0
        gf_dynstrcat(&tile_name, szTmp, NULL);
1437
0
      }
1438
0
      if (orig_tile_mode != TILE_ITEM_SINGLE || image_props->single_tile_number == i + 1) {
1439
0
        e = gf_isom_iff_create_image_item_from_track(movie, root_meta, meta_track_number, tile_track, tile_name, *tile_item_id, NULL, NULL);
1440
0
      }
1441
0
      if (tile_name) gf_free(tile_name);
1442
0
      if (e) return e;
1443
0
      gf_isom_remove_track(movie, tile_track);
1444
0
      if (orig_tile_mode == TILE_ITEM_ALL_BASE) {
1445
0
        e = gf_isom_meta_add_item_ref(movie, root_meta, meta_track_number, *tile_item_id, item_id, GF_ISOM_REF_TBAS, NULL);
1446
0
      }
1447
0
      if (e) return e;
1448
0
    }
1449
0
    tile_name = NULL;
1450
0
    if (item_name) {
1451
0
      gf_dynstrcat(&tile_name, item_name, NULL);
1452
0
      gf_dynstrcat(&tile_name, "-TileBase", NULL);
1453
0
    }
1454
0
    if (orig_tile_mode == TILE_ITEM_ALL_BASE) {
1455
0
      gf_isom_iff_create_image_item_from_track(movie, root_meta, meta_track_number, imported_track, tile_name, item_id, image_props, tile_item_ids);
1456
0
    }
1457
0
    else if (orig_tile_mode == TILE_ITEM_ALL_GRID) {
1458
      // TODO
1459
0
    }
1460
0
    if (tile_name) gf_free(tile_name);
1461
1462
0
    for (i = 0; i < count; i++) {
1463
0
      u32 *tile_item_id = gf_list_get(tile_item_ids, i);
1464
0
      gf_free(tile_item_id);
1465
0
    }
1466
0
    gf_list_del(tile_item_ids);
1467
0
    return GF_OK;
1468
0
  }
1469
1470
0
  if (!image_props) {
1471
0
    image_props = &local_image_props;
1472
0
    memset(image_props, 0, sizeof(GF_ImageItemProperties));
1473
0
  } else {
1474
0
    orig_ipro = image_props->cenc_info;
1475
0
    image_props->cenc_info = NULL;
1476
0
  }
1477
1478
0
  if (!imported_track) {
1479
0
    GF_ImageItemProperties src_props;
1480
0
    u32 item_idx, ref_id, nb_items, for_ref_idx;
1481
0
    u32 scheme_type=0, scheme_version=0;
1482
0
    Bool found=GF_FALSE;
1483
0
    const char *orig_item_name, *orig_item_mime_type, *orig_item_encoding;
1484
0
    nb_items = gf_isom_get_meta_item_count(fsrc, GF_TRUE, 0);
1485
1486
0
    for_ref_idx = image_props->item_ref_id ? gf_isom_get_meta_item_by_id(fsrc, GF_TRUE, 0, image_props->item_ref_id) : 0;
1487
0
    if (image_props->item_ref_id && !for_ref_idx) {
1488
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Error: No item with ID %d, cannnot import\n", image_props->item_ref_id));
1489
0
      return GF_BAD_PARAM;
1490
0
    }
1491
1492
0
    for (item_idx=1; item_idx<=nb_items; item_idx++) {
1493
0
      if (for_ref_idx && (for_ref_idx != item_idx)) continue;
1494
1495
1496
0
      if (gf_isom_meta_get_item_ref_count(fsrc, GF_TRUE, 0, image_props->item_ref_id, GF_4CC('d','i','m','g')) > 0) {
1497
0
        if (!for_ref_idx) continue;
1498
0
        GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Error: Cannnot import derived image, only native image import is supported\n"));
1499
0
        return GF_NOT_SUPPORTED;
1500
0
      }
1501
1502
0
      orig_item_name = orig_item_mime_type = orig_item_encoding = NULL;
1503
0
      gf_isom_get_meta_item_info(fsrc, GF_TRUE, 0, item_idx, &ref_id, &item_type, &scheme_type, &scheme_version, NULL, NULL, NULL, &orig_item_name, &orig_item_mime_type, &orig_item_encoding);
1504
1505
0
      if (!ref_id) return GF_BAD_PARAM;
1506
0
      if (image_props->item_ref_id && (ref_id != image_props->item_ref_id)) return GF_ISOM_INVALID_FILE;
1507
1508
0
      gf_isom_get_meta_image_props(fsrc, GF_TRUE, 0, ref_id, &src_props, NULL);
1509
1510
0
      image_props->config = src_props.config;
1511
0
      image_props->width = src_props.width;
1512
0
      image_props->height = src_props.height;
1513
0
      image_props->num_channels = src_props.num_channels;
1514
0
      memcpy(image_props->av1_layer_size, src_props.av1_layer_size, sizeof(u32)*3);
1515
0
      memcpy(image_props->bits_per_channel, src_props.bits_per_channel, sizeof(u32)*3);
1516
0
      if (!image_props->hSpacing && !image_props->vSpacing) {
1517
0
        image_props->hSpacing = src_props.hSpacing;
1518
0
        image_props->vSpacing = src_props.vSpacing;
1519
0
      }
1520
0
      if (image_props->copy_props) {
1521
0
        if (!image_props->hOffset && !image_props->vOffset) {
1522
0
          image_props->hOffset = src_props.hOffset;
1523
0
          image_props->vOffset = src_props.vOffset;
1524
0
        }
1525
0
        if (!image_props->clap_wden) {
1526
0
          image_props->clap_wnum = src_props.clap_wnum;
1527
0
          image_props->clap_wden = src_props.clap_wden;
1528
0
          image_props->clap_hnum = src_props.clap_hnum;
1529
0
          image_props->clap_hden = src_props.clap_hden;
1530
0
          image_props->clap_honum = src_props.clap_honum;
1531
0
          image_props->clap_hoden = src_props.clap_hoden;
1532
0
          image_props->clap_vonum = src_props.clap_vonum;
1533
0
          image_props->clap_voden = src_props.clap_voden;
1534
0
        }
1535
0
        if (!image_props->alpha) image_props->alpha = src_props.alpha;
1536
0
        if (!image_props->depth) image_props->depth = src_props.depth;
1537
0
        if (!image_props->hidden) image_props->hidden = src_props.hidden;
1538
0
        if (!image_props->angle) image_props->angle = src_props.angle;
1539
0
        if (!image_props->mirror) image_props->mirror = src_props.mirror;
1540
0
        if (!image_props->av1_op_index) image_props->av1_op_index = src_props.av1_op_index;
1541
0
      }
1542
0
      if (!item_name) item_name = orig_item_name;
1543
1544
0
      if (!image_props->use_reference || (fsrc == image_props->src_file)) {
1545
0
        u8 *data = NULL;
1546
0
        u32 size=0;
1547
0
        e = gf_isom_extract_meta_item_mem(fsrc, GF_TRUE, 0, ref_id, &data, &size, &size, NULL, GF_FALSE);
1548
0
        if (e) return GF_BAD_PARAM;
1549
1550
0
        e = gf_isom_add_meta_item_memory(movie, root_meta, meta_track_number, item_name, &item_id, item_type, NULL, NULL, image_props, data, size, NULL);
1551
0
        if (data) gf_free(data);
1552
0
      } else {
1553
0
        e = gf_isom_add_meta_item_sample_ref(movie, root_meta, meta_track_number, item_name, &item_id, item_type, NULL, NULL, image_props, 0, ref_id);
1554
0
      }
1555
0
      if (e) return e;
1556
0
      found = GF_TRUE;
1557
0
    }
1558
0
    if (!found) {
1559
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Error: Cannot import any image\n"));
1560
0
      return GF_URL_ERROR;
1561
0
    }
1562
0
    return GF_OK;
1563
0
  }
1564
1565
0
import_next_sample:
1566
1567
0
  timescale = gf_isom_get_media_timescale(fsrc, imported_track);
1568
0
  if (image_props->sample_num) {
1569
0
    sample_number = image_props->sample_num;
1570
0
    sample = gf_isom_get_sample(fsrc, imported_track, sample_number, &sample_desc_index);
1571
0
    e = gf_isom_last_error(fsrc);
1572
0
  } else if (image_props->time<0) {
1573
0
    sample = gf_isom_get_sample(fsrc, imported_track, sample_number, &sample_desc_index);
1574
0
    e = gf_isom_last_error(fsrc);
1575
0
  } else {
1576
0
    e = gf_isom_get_sample_for_media_time(fsrc, imported_track, (u64)(image_props->time*timescale), &sample_desc_index, GF_ISOM_SEARCH_SYNC_FORWARD, &sample, &sample_number, NULL);
1577
0
  }
1578
0
  if (e || !sample || !sample->IsRAP) {
1579
0
    if (!sample) {
1580
0
      if (is_first) {
1581
0
        GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("No sample found%s\n", (image_props->time<0) ? "" : " for requested time"));
1582
0
      } else {
1583
0
        e = GF_OK;
1584
0
        goto exit;
1585
0
      }
1586
0
    } else if ((image_props->time<0) || (image_props->step_time)) {
1587
0
      if (image_props->sample_num) {
1588
0
        GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Error: imported sample %d (DTS "LLU") is not a sync sample (RAP %d size %d)\n", sample_number, sample->DTS, sample->IsRAP, sample->dataLength));
1589
0
      } else if (image_props->step_time) {
1590
0
        gf_isom_sample_del(&sample);
1591
0
        e = GF_OK;
1592
0
        goto exit;
1593
0
      } else {
1594
0
        gf_isom_sample_del(&sample);
1595
0
        sample_number++;
1596
0
        if (sample_number == gf_isom_get_sample_count(fsrc, imported_track)) {
1597
0
          e = GF_OK;
1598
0
          goto exit;
1599
0
        }
1600
0
        goto import_next_sample;
1601
0
      }
1602
0
    } else {
1603
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Error no sync sample found after time %g\n", image_props->time));
1604
0
    }
1605
0
    if (!e) e = GF_BAD_PARAM;
1606
0
    goto exit;
1607
0
  }
1608
1609
  /* Check if the track type is supported as item type */
1610
  /* Get the config box if needed */
1611
0
  subtype = gf_isom_get_media_subtype(fsrc, imported_track, sample_desc_index);
1612
0
  if (gf_isom_is_media_encrypted(fsrc, imported_track, sample_desc_index)) {
1613
0
    if (gf_isom_is_cenc_media(fsrc, imported_track, sample_desc_index)) {
1614
0
      e = gf_isom_get_original_format_type(fsrc, imported_track, sample_desc_index, &subtype);
1615
0
      if (e) goto exit;
1616
0
      is_cenc = GF_TRUE;
1617
0
    } else {
1618
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Protected sample not using CENC, cannot add as item\n"));
1619
0
      e = GF_BAD_PARAM;
1620
0
      goto exit;
1621
0
    }
1622
0
  }
1623
1624
1625
0
  switch (subtype) {
1626
0
  case GF_ISOM_SUBTYPE_AVC_H264:
1627
0
  case GF_ISOM_SUBTYPE_AVC2_H264:
1628
0
  case GF_ISOM_SUBTYPE_AVC3_H264:
1629
0
  case GF_ISOM_SUBTYPE_AVC4_H264:
1630
    //FIXME: in avc1 with multiple descriptor, we should take the right description index
1631
0
    config_box = gf_isom_box_new(GF_ISOM_BOX_TYPE_AVCC);
1632
0
    if (!config_box) { e = GF_OUT_OF_MEM; goto exit; }
1633
0
    ((GF_AVCConfigurationBox *)config_box)->config = gf_isom_avc_config_get(fsrc, imported_track, sample_desc_index);
1634
0
    if (! ((GF_AVCConfigurationBox *)config_box)->config) { e = GF_OUT_OF_MEM; goto exit; }
1635
0
    item_type = GF_ISOM_SUBTYPE_AVC_H264;
1636
0
    config_needed = 1;
1637
0
    num_channels = 3;
1638
0
    bits_per_channel[0] = ((GF_AVCConfigurationBox *)config_box)->config->luma_bit_depth;
1639
0
    bits_per_channel[1] = ((GF_AVCConfigurationBox *)config_box)->config->chroma_bit_depth;
1640
0
    bits_per_channel[2] = ((GF_AVCConfigurationBox *)config_box)->config->chroma_bit_depth;
1641
0
    break;
1642
0
  case GF_ISOM_SUBTYPE_SVC_H264:
1643
0
    config_box = gf_isom_box_new(GF_ISOM_BOX_TYPE_SVCC);
1644
0
    if (!config_box) { e = GF_OUT_OF_MEM; goto exit; }
1645
0
    ((GF_AVCConfigurationBox *)config_box)->config = gf_isom_svc_config_get(fsrc, imported_track, sample_desc_index);
1646
0
    if (! ((GF_AVCConfigurationBox *)config_box)->config) { e = GF_OUT_OF_MEM; goto exit; }
1647
0
    item_type = GF_ISOM_SUBTYPE_SVC_H264;
1648
0
    config_needed = 1;
1649
0
    num_channels = 3;
1650
0
    bits_per_channel[0] = ((GF_AVCConfigurationBox *)config_box)->config->luma_bit_depth;
1651
0
    bits_per_channel[1] = ((GF_AVCConfigurationBox *)config_box)->config->chroma_bit_depth;
1652
0
    bits_per_channel[2] = ((GF_AVCConfigurationBox *)config_box)->config->chroma_bit_depth;
1653
0
    break;
1654
0
  case GF_ISOM_SUBTYPE_MVC_H264:
1655
0
    config_box = gf_isom_box_new(GF_ISOM_BOX_TYPE_MVCC);
1656
0
    if (!config_box) { e = GF_OUT_OF_MEM; goto exit; }
1657
0
    ((GF_AVCConfigurationBox *)config_box)->config = gf_isom_mvc_config_get(fsrc, imported_track, sample_desc_index);
1658
0
    if (! ((GF_AVCConfigurationBox *)config_box)->config) { e = GF_OUT_OF_MEM; goto exit; }
1659
0
    item_type = GF_ISOM_SUBTYPE_MVC_H264;
1660
0
    config_needed = 1;
1661
0
    num_channels = 3;
1662
0
    bits_per_channel[0] = ((GF_AVCConfigurationBox *)config_box)->config->luma_bit_depth;
1663
0
    bits_per_channel[1] = ((GF_AVCConfigurationBox *)config_box)->config->chroma_bit_depth;
1664
0
    bits_per_channel[2] = ((GF_AVCConfigurationBox *)config_box)->config->chroma_bit_depth;
1665
0
    break;
1666
0
  case GF_ISOM_SUBTYPE_HVC1:
1667
0
  case GF_ISOM_SUBTYPE_HEV1:
1668
0
  case GF_ISOM_SUBTYPE_HVC2:
1669
0
  case GF_ISOM_SUBTYPE_HEV2:
1670
0
  case GF_ISOM_SUBTYPE_HVT1:
1671
0
  case GF_ISOM_SUBTYPE_LHV1:
1672
0
  case GF_ISOM_SUBTYPE_LHE1:
1673
0
    config_box = gf_isom_box_new(GF_ISOM_BOX_TYPE_HVCC);
1674
0
    if (!config_box) { e = GF_OUT_OF_MEM; goto exit; }
1675
0
    ((GF_HEVCConfigurationBox *)config_box)->config = gf_isom_hevc_config_get(fsrc, imported_track, sample_desc_index);
1676
0
    if (! ((GF_HEVCConfigurationBox *)config_box)->config) { e = GF_OUT_OF_MEM; goto exit; }
1677
0
    if (subtype == GF_ISOM_SUBTYPE_HVT1) {
1678
0
      item_type = GF_ISOM_SUBTYPE_HVT1;
1679
0
    }
1680
0
    else {
1681
0
      item_type = GF_ISOM_SUBTYPE_HVC1;
1682
0
    }
1683
0
    config_needed = 1;
1684
0
    if (!((GF_HEVCConfigurationBox *)config_box)->config) {
1685
0
      ((GF_HEVCConfigurationBox *)config_box)->config = gf_isom_lhvc_config_get(fsrc, imported_track, sample_desc_index);
1686
0
      if (! ((GF_HEVCConfigurationBox *)config_box)->config) { e = GF_OUT_OF_MEM; goto exit; }
1687
0
      item_type = GF_ISOM_SUBTYPE_LHV1;
1688
0
    }
1689
0
    num_channels = 3;
1690
0
    bits_per_channel[0] = ((GF_HEVCConfigurationBox *)config_box)->config->luma_bit_depth;
1691
0
    bits_per_channel[1] = ((GF_HEVCConfigurationBox *)config_box)->config->chroma_bit_depth;
1692
0
    bits_per_channel[2] = ((GF_HEVCConfigurationBox *)config_box)->config->chroma_bit_depth;
1693
    //media_brand = GF_ISOM_BRAND_HEIC;
1694
0
    break;
1695
0
  case GF_ISOM_SUBTYPE_AV01:
1696
0
    {
1697
0
      config_box = gf_isom_box_new(GF_ISOM_BOX_TYPE_AV1C);
1698
0
      if (!config_box) { e = GF_OUT_OF_MEM; goto exit; }
1699
0
      ((GF_AV1ConfigurationBox *)config_box)->config = gf_isom_av1_config_get(fsrc, imported_track, sample_desc_index);
1700
0
      if (! ((GF_AV1ConfigurationBox *)config_box)->config) { e = GF_OUT_OF_MEM; goto exit; }
1701
0
      item_type = GF_ISOM_SUBTYPE_AV01;
1702
0
      config_needed = 1;
1703
0
      u8 depth = ((GF_AV1ConfigurationBox *)config_box)->config->high_bitdepth ? (((GF_AV1ConfigurationBox *)config_box)->config->twelve_bit ? 12 : 10 ) : 8;
1704
0
      if (((GF_AV1ConfigurationBox *)config_box)->config->monochrome) {
1705
0
        num_channels = 1;
1706
0
        bits_per_channel[0] = depth;
1707
0
        bits_per_channel[1] = 0;
1708
0
        bits_per_channel[2] = 0;
1709
0
      } else {
1710
0
        num_channels = 3;
1711
0
        bits_per_channel[0] = depth;
1712
0
        bits_per_channel[1] = depth;
1713
0
        bits_per_channel[2] = depth;
1714
0
      }
1715
      // presence of OBU SH in config is not recommended and properties should be used instead of metadata OBUs
1716
0
      while (gf_list_count(((GF_AV1ConfigurationBox *)config_box)->config->obu_array)) {
1717
0
        GF_AV1_OBUArrayEntry *obu = gf_list_pop_back(((GF_AV1ConfigurationBox *)config_box)->config->obu_array);
1718
0
        if (obu) {
1719
0
          if (obu->obu) gf_free(obu->obu);
1720
0
          gf_free(obu);
1721
0
        }
1722
0
      }
1723
0
      gf_list_del(((GF_AV1ConfigurationBox *)config_box)->config->obu_array);
1724
0
      ((GF_AV1ConfigurationBox *)config_box)->config->obu_array = NULL;
1725
0
      e = gf_media_av1_layer_size_get(fsrc, imported_track, sample_number, image_props->av1_op_index, image_props->av1_layer_size);
1726
0
    if (e) {
1727
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("AV1 operating point index out of range for stream\n"));
1728
0
    goto exit;
1729
0
    }
1730
      //media_brand = GF_ISOM_BRAND_AVIF;
1731
0
    }
1732
0
    break;
1733
1734
0
  case GF_ISOM_SUBTYPE_VVC1:
1735
0
    config_box = gf_isom_box_new(GF_ISOM_BOX_TYPE_VVCC);
1736
0
    if (!config_box) { e = GF_OUT_OF_MEM; goto exit; }
1737
0
    ((GF_VVCConfigurationBox *)config_box)->config = gf_isom_vvc_config_get(fsrc, imported_track, sample_desc_index);
1738
0
    if (! ((GF_VVCConfigurationBox *)config_box)->config) { e = GF_OUT_OF_MEM; goto exit; }
1739
0
    item_type = GF_ISOM_SUBTYPE_VVC1;
1740
1741
0
    config_needed = 1;
1742
0
    num_channels = 3;
1743
0
    bits_per_channel[0] = ((GF_VVCConfigurationBox *)config_box)->config->bit_depth;
1744
0
    bits_per_channel[1] = bits_per_channel[2] = bits_per_channel[0];
1745
    //media_brand = GF_ISOM_BRAND_HEIC;
1746
0
    break;
1747
0
  default:
1748
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Error: Codec not supported to create HEIF image items\n"));
1749
0
    e = GF_NOT_SUPPORTED;
1750
0
    goto exit;
1751
0
  }
1752
0
  if (config_needed && !config_box && !((GF_AVCConfigurationBox *)config_box)->config) {
1753
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Error: Image type %s requires a missing configuration box\n", gf_4cc_to_str(item_type)));
1754
0
    e = GF_BAD_PARAM;
1755
0
    goto exit;
1756
0
  }
1757
  /* Get some images properties from the track data */
1758
0
  e = gf_isom_get_visual_info(fsrc, imported_track, sample_desc_index, &w, &h);
1759
0
  if (e) {
1760
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Error determining image size\n"));
1761
0
    goto exit;
1762
0
  }
1763
0
  e = gf_isom_get_pixel_aspect_ratio(fsrc, imported_track, sample_desc_index, &hSpacing, &vSpacing);
1764
0
  if (e) {
1765
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Error determining image aspect ratio\n"));
1766
0
    goto exit;
1767
0
  }
1768
0
  if (!image_props->width && !image_props->height) {
1769
0
    image_props->width = w;
1770
0
    image_props->height = h;
1771
0
  }
1772
0
  if (!image_props->hSpacing && !image_props->vSpacing) {
1773
0
    image_props->hSpacing = hSpacing;
1774
0
    image_props->vSpacing = vSpacing;
1775
0
  }
1776
0
  image_props->config = config_box;
1777
0
  if (!image_props->num_channels) {
1778
0
    image_props->num_channels = num_channels;
1779
0
    image_props->bits_per_channel[0] = bits_per_channel[0];
1780
0
    image_props->bits_per_channel[1] = bits_per_channel[1];
1781
0
    image_props->bits_per_channel[2] = bits_per_channel[2];
1782
0
  }
1783
0
  if (is_cenc) {
1784
0
    Bool Is_Encrypted;
1785
1786
0
    memset(&ipro, 0, sizeof(GF_ImageItemProtection));
1787
0
    gf_isom_get_cenc_info(fsrc, imported_track, sample_desc_index, NULL, &ipro.scheme_type, &ipro.scheme_version);
1788
0
    e = gf_isom_get_sample_cenc_info(fsrc, imported_track, sample_number, &Is_Encrypted, &ipro.crypt_byte_block, &ipro.skip_byte_block, &ipro.key_info, &ipro.key_info_size);
1789
0
    if (e) goto exit;
1790
1791
0
    if (Is_Encrypted) {
1792
0
      sai_size = sai_alloc_size;
1793
0
      e = gf_isom_cenc_get_sample_aux_info(fsrc, imported_track, sample_number, sample_desc_index, NULL, &sai, &sai_size);
1794
0
      if (e) goto exit;
1795
1796
0
      if (sai_size > sai_alloc_size)
1797
0
        sai_alloc_size = sai_size;
1798
1799
0
      ipro.sai_data = sai;
1800
0
      ipro.sai_data_size = sai_size;
1801
0
      image_props->cenc_info = &ipro;
1802
1803
0
      if (is_first) {
1804
0
        u32 i, nb_pssh = gf_isom_get_pssh_count(fsrc);
1805
0
        for (i=0; i<nb_pssh; i++) {
1806
0
          bin128 SystemID;
1807
0
          u32 version;
1808
0
          u32 KID_count;
1809
0
          const bin128 *KIDs;
1810
0
          const u8 *private_data;
1811
0
          u32 private_data_size;
1812
1813
0
          gf_isom_get_pssh_info(fsrc, i+1, SystemID, &version, &KID_count, &KIDs, &private_data, &private_data_size);
1814
          
1815
0
          gf_isom_cenc_set_pssh(movie, SystemID, version, KID_count, (bin128 *) KIDs, (u8 *) private_data, private_data_size, 2);
1816
0
        }
1817
0
      }
1818
1819
0
    } else {
1820
0
      image_props->cenc_info = NULL;
1821
0
    }
1822
0
  }
1823
0
  if (!item_id) {
1824
0
    e = gf_isom_meta_get_next_item_id(movie, root_meta, meta_track_number, &item_id);
1825
0
    if (e) goto exit;
1826
0
  }
1827
0
  if (image_props->use_reference) {
1828
0
    if (image_props->sample_num) {
1829
0
      GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("referring trackID %d sample %d as item %d\n", imported_track, sample_number, item_id));
1830
0
    } else {
1831
0
      GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("referring trackID %d sample at time %.3f as item %d\n", imported_track, (sample->DTS+sample->CTS_Offset)*1.0/timescale, item_id));
1832
0
    }
1833
0
    e = gf_isom_add_meta_item_sample_ref(movie, root_meta, meta_track_number, item_name, &item_id, item_type, NULL, NULL, image_props, imported_track, sample_number);
1834
0
  } else {
1835
1836
0
    if (image_props->sample_num) {
1837
0
      GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("Adding sample %d as item %d\n", sample_number, item_id));
1838
0
    } else {
1839
0
      GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("Adding sample at time %.3f as item %d\n", (sample->DTS+sample->CTS_Offset)*1.0/timescale, item_id));
1840
0
    }
1841
0
    e = gf_isom_add_meta_item_memory(movie, root_meta, meta_track_number, item_name, &item_id, item_type, NULL, NULL, image_props, sample->data, sample->dataLength, item_extent_refs);
1842
0
  }
1843
1844
0
  image_props->cenc_info = NULL;
1845
1846
0
  if (reset_brands) {
1847
0
    gf_isom_set_brand_info(movie, GF_ISOM_BRAND_MIF1, 0);
1848
0
    gf_isom_reset_alt_brands(movie);
1849
1850
    // TODO Analyze configuration to determine the brand */
1851
    //if (media_brand) {
1852
    //  gf_isom_modify_alternate_brand(movie, media_brand, GF_TRUE);
1853
    //}
1854
0
  }
1855
1856
  
1857
0
  if (neg_time)
1858
0
    image_props->time = -1;
1859
1860
0
  if (!e && !image_props->sample_num && ((image_props->time<0) || image_props->end_time || image_props->step_time)) {
1861
0
    if (image_props->end_time || image_props->step_time) {
1862
0
      Double t = (Double) (sample->DTS + sample->CTS_Offset);
1863
0
      t /= timescale;
1864
0
      if (image_props->step_time) {
1865
0
        t += image_props->step_time;
1866
0
      } else {
1867
        //step 1ms
1868
0
        t += 0.001;
1869
0
      }
1870
1871
0
      if ((image_props->end_time>0) && (t>image_props->end_time)) {
1872
0
        goto exit;
1873
0
      }
1874
0
      image_props->time = t;
1875
0
    }
1876
1877
0
    item_id=0;
1878
0
    gf_isom_sample_del(&sample);
1879
0
    if (config_box) {
1880
0
      gf_isom_box_del(config_box);
1881
0
      config_box = NULL;
1882
0
    }
1883
0
    is_first = GF_FALSE;
1884
0
    if (sample_number >= gf_isom_get_sample_count(fsrc, imported_track)) return e;
1885
0
    sample_number++;
1886
    //avoid recursion this could get quite big
1887
0
    goto import_next_sample;
1888
0
  }
1889
1890
0
exit:
1891
0
  if (sai) gf_free(sai);
1892
0
  gf_isom_sample_del(&sample);
1893
0
  if (config_box) gf_isom_box_del(config_box);
1894
0
  image_props->cenc_info = orig_ipro;
1895
0
  return e;
1896
0
}
1897
1898
static
1899
0
GF_Err gf_isom_iff_create_image_grid_item_internal(GF_ISOFile *movie, Bool root_meta, u32 meta_track_number, const char *item_name, u32 *item_id, GF_ImageItemProperties *image_props) {
1900
0
  GF_Err e = GF_OK;
1901
0
  u32 grid4cc = GF_4CC('g', 'r', 'i', 'd');
1902
0
  GF_BitStream *grid_bs;
1903
0
  if (image_props->num_grid_rows < 1 || image_props->num_grid_columns < 1 || image_props->num_grid_rows > 256 || image_props->num_grid_columns > 256) {
1904
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Wrong grid parameters: %d, %d\n", image_props->num_grid_rows, image_props->num_grid_columns));
1905
0
    return GF_BAD_PARAM;
1906
0
  }
1907
0
  if (image_props->width == 0 || image_props->height == 0) {
1908
0
    GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("At least one grid dimension set to 0: %d, %d\n", image_props->width, image_props->height));
1909
0
    return GF_BAD_PARAM;
1910
0
  }
1911
0
  grid_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
1912
0
  if (!grid_bs) return GF_OUT_OF_MEM;
1913
0
  gf_bs_write_u8(grid_bs, 0); //version
1914
0
  gf_bs_write_u8(grid_bs, (image_props->width > 1<<16 || image_props->height > 1<<16) ? 1 : 0); // flags
1915
0
  gf_bs_write_u8(grid_bs, image_props->num_grid_rows-1);
1916
0
  gf_bs_write_u8(grid_bs, image_props->num_grid_columns-1);
1917
0
  gf_bs_write_u16(grid_bs, image_props->width);
1918
0
  gf_bs_write_u16(grid_bs, image_props->height);
1919
0
  u8 *grid_data;
1920
0
  u32 grid_data_size;
1921
0
  gf_bs_get_content(grid_bs, &grid_data, &grid_data_size);
1922
0
  e = gf_isom_add_meta_item_memory(movie, root_meta, meta_track_number, item_name, item_id, grid4cc, NULL, NULL, image_props, grid_data, grid_data_size, NULL);
1923
0
  gf_free(grid_data);
1924
0
  gf_bs_del(grid_bs);
1925
0
  return e;
1926
0
}
1927
1928
GF_EXPORT
1929
GF_Err gf_isom_iff_create_image_grid_item(GF_ISOFile *movie, Bool root_meta, u32 meta_track_number, const char *item_name, u32 item_id, GF_ImageItemProperties *image_props)
1930
0
{
1931
0
  return gf_isom_iff_create_image_grid_item_internal(movie, root_meta, meta_track_number, item_name, &item_id, image_props);
1932
0
}
1933
1934
static GF_Err iff_create_auto_grid(GF_ISOFile *movie, Bool root_meta, u32 meta_track_number, const char *item_name, u32 item_id, GF_ImageItemProperties *image_props)
1935
0
{
1936
0
  GF_Err e;
1937
0
  GF_ImageItemProperties props;
1938
0
  u32 w=0, h=0;
1939
0
  u32 *imgs_ids=NULL;
1940
0
  u32 nb_imgs=0, nb_src_imgs;
1941
0
  u32 nb_cols, nb_rows;
1942
0
  u32 last_valid_nb_cols;
1943
0
  Bool first_pass = GF_TRUE;
1944
0
  Double ar;
1945
0
  u32 i, nb_items = gf_isom_get_meta_item_count(movie, root_meta, meta_track_number);
1946
0
  for (i=0; i<nb_items; i++) {
1947
0
    u32 an_item_id, item_type;
1948
0
    gf_isom_get_meta_item_info(movie, root_meta, meta_track_number, i+1, &an_item_id, &item_type, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1949
1950
0
    if (!item_id) continue;
1951
0
    if (item_type==GF_ISOM_ITEM_TYPE_AUXI) continue;
1952
1953
0
    memset(&props, 0, sizeof(props));
1954
0
    gf_isom_get_meta_image_props(movie, root_meta, meta_track_number, an_item_id, &props, NULL);
1955
0
    if (!props.width || !props.height) continue;
1956
1957
0
    if (!w) w = props.width;
1958
0
    if (!h) h = props.height;
1959
1960
0
    if ((w != props.width) || (h != props.height)) {
1961
0
      if (imgs_ids) gf_free(imgs_ids);
1962
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Auto grid can only be generated for images of the same size - try using `-add-derived-image type=grid`\n"));
1963
0
      return GF_NOT_SUPPORTED;
1964
0
    }
1965
0
    imgs_ids = gf_realloc(imgs_ids, sizeof(u32) * (nb_imgs+1));
1966
0
    if (!imgs_ids) return GF_OUT_OF_MEM;
1967
0
    imgs_ids[nb_imgs] = an_item_id;
1968
0
    nb_imgs++;
1969
0
  }
1970
1971
0
  if (!nb_imgs || !w || !h) {
1972
0
    if (imgs_ids) gf_free(imgs_ids);
1973
0
    GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("No image items found\n"));
1974
0
    return GF_BAD_PARAM;
1975
0
  }
1976
1977
  //try roughly the same aspect ratio
1978
0
  if (image_props->auto_grid_ratio) {
1979
0
    ar = image_props->auto_grid_ratio;
1980
0
  } else {
1981
0
    ar = w;
1982
0
    ar /= h;
1983
0
  }
1984
0
  nb_src_imgs = nb_imgs;
1985
1986
0
recompute_grid:
1987
0
  nb_cols=1;
1988
0
  nb_rows=1;
1989
0
  last_valid_nb_cols = 0;
1990
1991
0
  if (nb_imgs>1) {
1992
0
    while (nb_cols < nb_imgs) {
1993
0
      Double target_ar = ((Double) nb_cols) * w;
1994
0
      nb_rows = nb_imgs / nb_cols;
1995
0
      if (nb_rows * nb_cols != nb_imgs) {
1996
0
        nb_cols++;
1997
0
        continue;
1998
0
      }
1999
0
      target_ar /= ((Double)nb_rows) * h;
2000
0
      if (target_ar >= ar) break;
2001
0
      last_valid_nb_cols = nb_cols;
2002
0
      nb_cols++;
2003
0
    }
2004
0
  }
2005
0
  if ((nb_cols==nb_imgs) && last_valid_nb_cols) {
2006
0
    nb_cols = last_valid_nb_cols;
2007
0
    nb_rows = nb_imgs / nb_cols;
2008
0
  }
2009
2010
0
  if (first_pass && (nb_imgs>1) && ((nb_cols==1) || (nb_rows==1) ) ) {
2011
0
    if (nb_imgs % 2) {
2012
0
      GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("Not an even number of images, removing last item from grid\n"));
2013
0
      nb_imgs--;
2014
0
      first_pass = GF_FALSE;
2015
0
      goto recompute_grid;
2016
0
    }
2017
0
  }
2018
2019
0
  memset(&props, 0, sizeof(props));
2020
0
  if (image_props)
2021
0
    memcpy(&props, image_props, sizeof(props));
2022
0
  props.hidden = GF_FALSE;
2023
0
  props.width = nb_cols * w;
2024
0
  props.height = nb_rows * h;
2025
0
  props.num_grid_rows = nb_rows;
2026
0
  props.num_grid_columns = nb_cols;
2027
0
  GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("Grid: %u rows %u cols - size %ux%u pixels\n", nb_cols, nb_rows, props.width, props.height));
2028
2029
0
  e = gf_isom_iff_create_image_grid_item_internal(movie, root_meta, meta_track_number, item_name, &item_id, &props);
2030
0
  if (e) {
2031
0
    gf_free(imgs_ids);
2032
0
    return e;
2033
0
  }
2034
2035
0
  for (i=0; i<nb_imgs; i++) {
2036
0
    e = gf_isom_meta_add_item_ref(movie, root_meta, meta_track_number, item_id, imgs_ids[i], GF_4CC('d','i','m','g'), NULL);
2037
0
    if (e) goto exit;
2038
0
  }
2039
2040
  //we might want an option to avoid this?
2041
  //if (image_props->hidden)
2042
0
  {
2043
0
    GF_MetaBox *meta = gf_isom_get_meta(movie, root_meta, meta_track_number);
2044
0
    for (i=0; i<nb_src_imgs; i++) {
2045
0
      GF_ItemInfoEntryBox *iinf;
2046
0
      u32 j=0;
2047
0
      while ((iinf = (GF_ItemInfoEntryBox *)gf_list_enum(meta->item_infos->item_infos, &j))) {
2048
0
        if (iinf->item_ID == imgs_ids[i]) {
2049
0
          iinf->flags |= 0x1;
2050
0
          break;
2051
0
        }
2052
0
      }
2053
0
    }
2054
0
    e = gf_isom_set_meta_primary_item(movie, root_meta, meta_track_number, item_id);
2055
0
  }
2056
2057
0
exit:
2058
0
  gf_free(imgs_ids);
2059
0
  return e;
2060
0
}
2061
2062
GF_EXPORT
2063
0
GF_Err gf_isom_iff_create_image_overlay_item(GF_ISOFile *movie, Bool root_meta, u32 meta_track_number, const char *item_name, u32 item_id, GF_ImageItemProperties *image_props) {
2064
0
  u32 i;
2065
0
  Bool use32bitFields = GF_FALSE;
2066
0
  GF_Err e = GF_OK;
2067
0
  u32 overlay4cc = GF_4CC('i', 'o', 'v', 'l');
2068
0
  GF_BitStream *overlay_bs;
2069
0
  if (image_props->overlay_count == 0 || image_props->width == 0 || image_props->height == 0) {
2070
0
    GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("Unusual overlay parameters: %d, %d, %d\n", image_props->overlay_count, image_props->width, image_props->height));
2071
0
  }
2072
0
  if (image_props->width <= 1<<16 || image_props->height <= 1<<16) {
2073
0
    for (i=0; i< image_props->overlay_count; i++) {
2074
0
      if ( image_props->overlay_offsets[i].horizontal > 1<<16 ||
2075
0
        image_props->overlay_offsets[i].vertical > 1<<16) {
2076
0
        use32bitFields = GF_TRUE;
2077
0
        break;
2078
0
      }
2079
0
    }
2080
0
  } else {
2081
0
    use32bitFields = GF_TRUE;
2082
0
  }
2083
0
  overlay_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
2084
0
  if (!overlay_bs) return GF_OUT_OF_MEM;
2085
0
  gf_bs_write_u8(overlay_bs, 0); // version
2086
0
  gf_bs_write_u8(overlay_bs, use32bitFields ? 1 : 0); // flags
2087
0
  gf_bs_write_u16(overlay_bs, image_props->overlay_canvas_fill_value_r);
2088
0
  gf_bs_write_u16(overlay_bs, image_props->overlay_canvas_fill_value_g);
2089
0
  gf_bs_write_u16(overlay_bs, image_props->overlay_canvas_fill_value_b);
2090
0
  gf_bs_write_u16(overlay_bs, image_props->overlay_canvas_fill_value_a);
2091
0
  gf_bs_write_u16(overlay_bs, image_props->width);
2092
0
  gf_bs_write_u16(overlay_bs, image_props->height);
2093
0
  for (i = 0; i <image_props->overlay_count; i++) {
2094
0
    gf_bs_write_u16(overlay_bs, image_props->overlay_offsets[i].horizontal);
2095
0
    gf_bs_write_u16(overlay_bs, image_props->overlay_offsets[i].vertical);
2096
0
  }
2097
0
  u8 *overlay_data;
2098
0
  u32 overlay_data_size;
2099
0
  gf_bs_get_content(overlay_bs, &overlay_data, &overlay_data_size);
2100
0
  e = gf_isom_add_meta_item_memory(movie, root_meta, meta_track_number, item_name, &item_id, overlay4cc, NULL, NULL, image_props, overlay_data, overlay_data_size, NULL);
2101
0
  gf_free(overlay_data);
2102
0
  gf_bs_del(overlay_bs);
2103
0
  return e;
2104
0
}
2105
2106
GF_EXPORT
2107
0
GF_Err gf_isom_iff_create_image_identity_item(GF_ISOFile *movie, Bool root_meta, u32 meta_track_number, const char *item_name, u32 item_id, GF_ImageItemProperties *image_props) {
2108
0
  GF_Err e = GF_OK;
2109
0
  u32 identity4cc = GF_4CC('i', 'd', 'e', 'n');
2110
0
  if (image_props->width == 0 || image_props->height == 0) {
2111
0
    GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("At least one identity dimension set to 0: %d, %d\n", image_props->width, image_props->height));
2112
0
  }
2113
0
  e = gf_isom_add_meta_item_memory(movie, root_meta, meta_track_number, item_name, &item_id, identity4cc, NULL, NULL, image_props, NULL, 0, NULL);
2114
0
  return e;
2115
0
}
2116
2117
GF_EXPORT
2118
GF_Err gf_isom_iff_create_image_item_from_track(GF_ISOFile *movie, Bool root_meta, u32 meta_track_number, u32 imported_track, const char *item_name, u32 item_id, GF_ImageItemProperties *image_props, GF_List *item_extent_refs)
2119
0
{
2120
2121
0
  if (image_props && image_props->auto_grid)
2122
0
    return iff_create_auto_grid(movie, root_meta, meta_track_number, item_name, item_id, image_props);
2123
2124
0
  return gf_isom_iff_create_image_item_from_track_internal(movie, root_meta, meta_track_number, imported_track, item_name, item_id, image_props, item_extent_refs, 1);
2125
0
}
2126
2127
#endif /*GPAC_DISABLE_ISOM_WRITE*/
2128
2129
2130
#endif /*GPAC_DISABLE_ISOM*/