Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Cyril Concolato
5 : * Copyright (c) Telecom ParisTech 2000-2021
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 160 : GF_Box *ispe_box_new()
33 : {
34 320 : ISOM_DECL_BOX_ALLOC(GF_ImageSpatialExtentsPropertyBox, GF_ISOM_BOX_TYPE_ISPE);
35 160 : return (GF_Box *)tmp;
36 : }
37 :
38 160 : void ispe_box_del(GF_Box *a)
39 : {
40 : GF_ImageSpatialExtentsPropertyBox *p = (GF_ImageSpatialExtentsPropertyBox *)a;
41 160 : gf_free(p);
42 160 : }
43 :
44 58 : GF_Err ispe_box_read(GF_Box *s, GF_BitStream *bs)
45 : {
46 : GF_ImageSpatialExtentsPropertyBox *p = (GF_ImageSpatialExtentsPropertyBox *)s;
47 :
48 58 : if (p->version == 0 && p->flags == 0) {
49 58 : p->image_width = gf_bs_read_u32(bs);
50 58 : p->image_height = gf_bs_read_u32(bs);
51 58 : return GF_OK;
52 : } 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 : }
57 : }
58 :
59 : #ifndef GPAC_DISABLE_ISOM_WRITE
60 102 : GF_Err ispe_box_write(GF_Box *s, GF_BitStream *bs)
61 : {
62 : GF_Err e;
63 : GF_ImageSpatialExtentsPropertyBox *p = (GF_ImageSpatialExtentsPropertyBox*)s;
64 :
65 102 : p->version = 0;
66 102 : p->flags = 0;
67 102 : e = gf_isom_full_box_write(s, bs);
68 102 : if (e) return e;
69 102 : gf_bs_write_u32(bs, p->image_width);
70 102 : gf_bs_write_u32(bs, p->image_height);
71 102 : return GF_OK;
72 : }
73 :
74 308 : GF_Err ispe_box_size(GF_Box *s)
75 : {
76 : GF_ImageSpatialExtentsPropertyBox *p = (GF_ImageSpatialExtentsPropertyBox*)s;
77 308 : if (p->version == 0 && p->flags == 0) {
78 308 : p->size += 8;
79 308 : return GF_OK;
80 : } else {
81 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("version and flags for ispe box not supported" ));
82 : return GF_NOT_SUPPORTED;
83 : }
84 : }
85 :
86 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
87 :
88 454 : GF_Box *colr_box_new()
89 : {
90 908 : ISOM_DECL_BOX_ALLOC(GF_ColourInformationBox, GF_ISOM_BOX_TYPE_COLR);
91 454 : return (GF_Box *)tmp;
92 : }
93 :
94 454 : void colr_box_del(GF_Box *a)
95 : {
96 : GF_ColourInformationBox *p = (GF_ColourInformationBox *)a;
97 454 : if (p->opaque) gf_free(p->opaque);
98 454 : gf_free(p);
99 454 : }
100 :
101 377 : GF_Err colr_box_read(GF_Box *s, GF_BitStream *bs)
102 : {
103 : GF_ColourInformationBox *p = (GF_ColourInformationBox *)s;
104 :
105 377 : if (p->is_jp2) {
106 27 : ISOM_DECREASE_SIZE(p, 3);
107 27 : p->method = gf_bs_read_u8(bs);
108 27 : p->precedence = gf_bs_read_u8(bs);
109 27 : p->approx = gf_bs_read_u8(bs);
110 27 : if (p->size) {
111 27 : p->opaque = gf_malloc(sizeof(u8)*(size_t)p->size);
112 27 : p->opaque_size = (u32) p->size;
113 27 : gf_bs_read_data(bs, (char *) p->opaque, p->opaque_size);
114 : }
115 : } else {
116 350 : ISOM_DECREASE_SIZE(p, 4);
117 350 : p->colour_type = gf_bs_read_u32(bs);
118 350 : switch (p->colour_type) {
119 335 : case GF_ISOM_SUBTYPE_NCLX:
120 335 : ISOM_DECREASE_SIZE(p, 7);
121 335 : p->colour_primaries = gf_bs_read_u16(bs);
122 335 : p->transfer_characteristics = gf_bs_read_u16(bs);
123 335 : p->matrix_coefficients = gf_bs_read_u16(bs);
124 335 : p->full_range_flag = (gf_bs_read_u8(bs) & 0x80) ? GF_TRUE : GF_FALSE;
125 335 : break;
126 13 : case GF_ISOM_SUBTYPE_NCLC:
127 13 : ISOM_DECREASE_SIZE(p, 6);
128 13 : p->colour_primaries = gf_bs_read_u16(bs);
129 13 : p->transfer_characteristics = gf_bs_read_u16(bs);
130 13 : p->matrix_coefficients = gf_bs_read_u16(bs);
131 13 : break;
132 2 : default:
133 2 : p->opaque = gf_malloc(sizeof(u8)*(size_t)p->size);
134 2 : p->opaque_size = (u32) p->size;
135 2 : gf_bs_read_data(bs, (char *) p->opaque, p->opaque_size);
136 2 : break;
137 : }
138 : }
139 : return GF_OK;
140 : }
141 :
142 : #ifndef GPAC_DISABLE_ISOM_WRITE
143 252 : GF_Err colr_box_write(GF_Box *s, GF_BitStream *bs)
144 : {
145 : GF_Err e;
146 : GF_ColourInformationBox *p = (GF_ColourInformationBox*)s;
147 252 : e = gf_isom_box_write_header(s, bs);
148 252 : if (e) return e;
149 :
150 252 : if (p->is_jp2) {
151 23 : gf_bs_write_u8(bs, p->method);
152 23 : gf_bs_write_u8(bs, p->precedence);
153 23 : gf_bs_write_u8(bs, p->approx);
154 23 : if (p->opaque_size)
155 23 : gf_bs_write_data(bs, (char *)p->opaque, p->opaque_size);
156 : } else {
157 229 : switch (p->colour_type) {
158 216 : case GF_ISOM_SUBTYPE_NCLX:
159 216 : gf_bs_write_u32(bs, p->colour_type);
160 216 : gf_bs_write_u16(bs, p->colour_primaries);
161 216 : gf_bs_write_u16(bs, p->transfer_characteristics);
162 216 : gf_bs_write_u16(bs, p->matrix_coefficients);
163 216 : gf_bs_write_u8(bs, (p->full_range_flag == GF_TRUE ? 0x80 : 0));
164 216 : break;
165 11 : case GF_ISOM_SUBTYPE_NCLC:
166 11 : gf_bs_write_u32(bs, p->colour_type);
167 11 : gf_bs_write_u16(bs, p->colour_primaries);
168 11 : gf_bs_write_u16(bs, p->transfer_characteristics);
169 11 : gf_bs_write_u16(bs, p->matrix_coefficients);
170 11 : break;
171 2 : default:
172 2 : gf_bs_write_u32(bs, p->colour_type);
173 2 : gf_bs_write_data(bs, (char *)p->opaque, p->opaque_size);
174 2 : break;
175 : }
176 : }
177 : return GF_OK;
178 : }
179 :
180 433 : GF_Err colr_box_size(GF_Box *s)
181 : {
182 : GF_ColourInformationBox *p = (GF_ColourInformationBox*)s;
183 :
184 433 : if (p->is_jp2) {
185 30 : p->size += 3 + p->opaque_size;
186 : } else {
187 403 : switch (p->colour_type) {
188 380 : case GF_ISOM_SUBTYPE_NCLX:
189 380 : p->size += 11;
190 380 : break;
191 21 : case GF_ISOM_SUBTYPE_NCLC:
192 21 : p->size += 10;
193 21 : break;
194 2 : default:
195 2 : p->size += 4 + p->opaque_size;
196 2 : break;
197 : }
198 : }
199 433 : return GF_OK;
200 : }
201 :
202 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
203 :
204 140 : GF_Box *pixi_box_new()
205 : {
206 280 : ISOM_DECL_BOX_ALLOC(GF_PixelInformationPropertyBox, GF_ISOM_BOX_TYPE_PIXI);
207 140 : return (GF_Box *)tmp;
208 : }
209 :
210 140 : void pixi_box_del(GF_Box *a)
211 : {
212 : GF_PixelInformationPropertyBox *p = (GF_PixelInformationPropertyBox *)a;
213 140 : if (p->bits_per_channel) gf_free(p->bits_per_channel);
214 140 : gf_free(p);
215 140 : }
216 :
217 54 : GF_Err pixi_box_read(GF_Box *s, GF_BitStream *bs)
218 : {
219 : u32 i;
220 : GF_PixelInformationPropertyBox *p = (GF_PixelInformationPropertyBox *)s;
221 :
222 54 : if (p->version == 0 && p->flags == 0) {
223 54 : p->num_channels = gf_bs_read_u8(bs);
224 54 : p->bits_per_channel = (u8 *)gf_malloc(p->num_channels);
225 213 : for (i = 0; i < p->num_channels; i++) {
226 159 : ISOM_DECREASE_SIZE(p, 1)
227 159 : p->bits_per_channel[i] = gf_bs_read_u8(bs);
228 : }
229 : return GF_OK;
230 : } else {
231 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("version and flags for pixi box not supported" ));
232 0 : gf_bs_skip_bytes(bs, p->size);
233 0 : return GF_NOT_SUPPORTED;
234 : }
235 : }
236 :
237 : #ifndef GPAC_DISABLE_ISOM_WRITE
238 86 : GF_Err pixi_box_write(GF_Box *s, GF_BitStream *bs)
239 : {
240 : u32 i;
241 : GF_Err e;
242 : GF_PixelInformationPropertyBox *p = (GF_PixelInformationPropertyBox*)s;
243 :
244 86 : p->version = 0;
245 86 : p->flags = 0;
246 86 : e = gf_isom_full_box_write(s, bs);
247 86 : if (e) return e;
248 86 : gf_bs_write_u8(bs, p->num_channels);
249 341 : for (i = 0; i < p->num_channels; i++) {
250 255 : gf_bs_write_u8(bs, p->bits_per_channel[i]);
251 : }
252 : return GF_OK;
253 : }
254 :
255 257 : GF_Err pixi_box_size(GF_Box *s)
256 : {
257 : GF_PixelInformationPropertyBox *p = (GF_PixelInformationPropertyBox*)s;
258 257 : if (p->version == 0 && p->flags == 0) {
259 257 : p->size += 1 + p->num_channels;
260 257 : return GF_OK;
261 : } else {
262 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("version and flags for pixi box not supported" ));
263 : return GF_NOT_SUPPORTED;
264 : }
265 : }
266 :
267 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
268 :
269 3 : GF_Box *rloc_box_new()
270 : {
271 6 : ISOM_DECL_BOX_ALLOC(GF_RelativeLocationPropertyBox, GF_ISOM_BOX_TYPE_RLOC);
272 3 : return (GF_Box *)tmp;
273 : }
274 :
275 3 : void rloc_box_del(GF_Box *a)
276 : {
277 : GF_RelativeLocationPropertyBox *p = (GF_RelativeLocationPropertyBox *)a;
278 3 : gf_free(p);
279 3 : }
280 :
281 1 : GF_Err rloc_box_read(GF_Box *s, GF_BitStream *bs)
282 : {
283 : GF_RelativeLocationPropertyBox *p = (GF_RelativeLocationPropertyBox *)s;
284 :
285 1 : if (p->version == 0 && p->flags == 0) {
286 1 : p->horizontal_offset = gf_bs_read_u32(bs);
287 1 : p->vertical_offset = gf_bs_read_u32(bs);
288 1 : return GF_OK;
289 : } else {
290 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("version and flags for rloc box not supported" ));
291 0 : gf_bs_skip_bytes(bs, p->size);
292 0 : return GF_NOT_SUPPORTED;
293 : }
294 : }
295 :
296 : #ifndef GPAC_DISABLE_ISOM_WRITE
297 1 : GF_Err rloc_box_write(GF_Box *s, GF_BitStream *bs)
298 : {
299 : GF_Err e;
300 : GF_RelativeLocationPropertyBox *p = (GF_RelativeLocationPropertyBox*)s;
301 :
302 1 : p->version = 0;
303 1 : p->flags = 0;
304 1 : e = gf_isom_full_box_write(s, bs);
305 1 : if (e) return e;
306 1 : gf_bs_write_u32(bs, p->horizontal_offset);
307 1 : gf_bs_write_u32(bs, p->vertical_offset);
308 1 : return GF_OK;
309 : }
310 :
311 1 : GF_Err rloc_box_size(GF_Box *s)
312 : {
313 : GF_RelativeLocationPropertyBox *p = (GF_RelativeLocationPropertyBox*)s;
314 1 : if (p->version == 0 && p->flags == 0) {
315 1 : p->size += 8;
316 1 : return GF_OK;
317 : } else {
318 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("version and flags for rloc box not supported" ));
319 : return GF_NOT_SUPPORTED;
320 : }
321 : }
322 :
323 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
324 :
325 17 : GF_Box *irot_box_new()
326 : {
327 34 : ISOM_DECL_BOX_ALLOC(GF_ImageRotationBox, GF_ISOM_BOX_TYPE_IROT);
328 17 : return (GF_Box *)tmp;
329 : }
330 :
331 17 : void irot_box_del(GF_Box *a)
332 : {
333 : GF_ImageRotationBox *p = (GF_ImageRotationBox *)a;
334 17 : gf_free(p);
335 17 : }
336 :
337 3 : GF_Err irot_box_read(GF_Box *s, GF_BitStream *bs)
338 : {
339 : GF_ImageRotationBox *p = (GF_ImageRotationBox *)s;
340 3 : p->angle = gf_bs_read_u8(bs) & 0x3;
341 3 : return GF_OK;
342 : }
343 :
344 : #ifndef GPAC_DISABLE_ISOM_WRITE
345 13 : GF_Err irot_box_write(GF_Box *s, GF_BitStream *bs)
346 : {
347 : GF_Err e;
348 : GF_ImageRotationBox *p = (GF_ImageRotationBox*)s;
349 13 : e = gf_isom_box_write_header(s, bs);
350 13 : if (e) return e;
351 13 : gf_bs_write_u8(bs, p->angle);
352 13 : return GF_OK;
353 : }
354 :
355 37 : GF_Err irot_box_size(GF_Box *s)
356 : {
357 : GF_ImageRotationBox *p = (GF_ImageRotationBox*)s;
358 37 : p->size += 1;
359 37 : return GF_OK;
360 : }
361 :
362 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
363 :
364 12 : GF_Box *imir_box_new()
365 : {
366 24 : ISOM_DECL_BOX_ALLOC(GF_ImageMirrorBox, GF_ISOM_BOX_TYPE_IMIR);
367 12 : return (GF_Box *)tmp;
368 : }
369 :
370 12 : void imir_box_del(GF_Box *a)
371 : {
372 : GF_ImageMirrorBox *p = (GF_ImageMirrorBox *)a;
373 12 : gf_free(p);
374 12 : }
375 :
376 1 : GF_Err imir_box_read(GF_Box *s, GF_BitStream *bs)
377 : {
378 : GF_ImageMirrorBox *p = (GF_ImageMirrorBox *)s;
379 1 : p->axis = gf_bs_read_u8(bs) & 0x1;
380 1 : return GF_OK;
381 : }
382 :
383 : #ifndef GPAC_DISABLE_ISOM_WRITE
384 10 : GF_Err imir_box_write(GF_Box *s, GF_BitStream *bs)
385 : {
386 : GF_Err e;
387 : GF_ImageMirrorBox *p = (GF_ImageMirrorBox*)s;
388 10 : e = gf_isom_box_write_header(s, bs);
389 10 : if (e) return e;
390 10 : gf_bs_write_u8(bs, p->axis);
391 10 : return GF_OK;
392 : }
393 :
394 28 : GF_Err imir_box_size(GF_Box *s)
395 : {
396 : GF_ImageMirrorBox *p = (GF_ImageMirrorBox*)s;
397 28 : p->size += 1;
398 28 : return GF_OK;
399 : }
400 :
401 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
402 :
403 143 : GF_Box *ipco_box_new()
404 : {
405 286 : ISOM_DECL_BOX_ALLOC(GF_ItemPropertyContainerBox, GF_ISOM_BOX_TYPE_IPCO);
406 143 : return (GF_Box *)tmp;
407 : }
408 :
409 143 : void ipco_box_del(GF_Box *s)
410 : {
411 : GF_ItemPropertyContainerBox *p = (GF_ItemPropertyContainerBox *)s;
412 143 : gf_free(p);
413 143 : }
414 :
415 54 : GF_Err ipco_box_read(GF_Box *s, GF_BitStream *bs)
416 : {
417 54 : return gf_isom_box_array_read(s, bs);
418 : }
419 :
420 : #ifndef GPAC_DISABLE_ISOM_WRITE
421 :
422 89 : GF_Err ipco_box_write(GF_Box *s, GF_BitStream *bs)
423 : {
424 89 : if (!s) return GF_BAD_PARAM;
425 89 : return gf_isom_box_write_header(s, bs);
426 : }
427 :
428 269 : GF_Err ipco_box_size(GF_Box *s)
429 : {
430 269 : return GF_OK;
431 : }
432 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
433 :
434 143 : GF_Box *iprp_box_new()
435 : {
436 286 : ISOM_DECL_BOX_ALLOC(GF_ItemPropertiesBox, GF_ISOM_BOX_TYPE_IPRP);
437 143 : return (GF_Box *)tmp;
438 : }
439 :
440 143 : void iprp_box_del(GF_Box *s)
441 : {
442 143 : gf_free(s);
443 143 : }
444 :
445 106 : GF_Err iprp_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem)
446 : {
447 : GF_ItemPropertiesBox *ptr = (GF_ItemPropertiesBox *)s;
448 106 : switch (a->type) {
449 53 : case GF_ISOM_BOX_TYPE_IPCO:
450 53 : BOX_FIELD_ASSIGN(property_container, GF_ItemPropertyContainerBox)
451 53 : break;
452 53 : case GF_ISOM_BOX_TYPE_IPMA:
453 53 : BOX_FIELD_ASSIGN(property_association, GF_ItemPropertyAssociationBox)
454 53 : break;
455 : default:
456 : return GF_OK;
457 : }
458 : return GF_OK;
459 : }
460 :
461 54 : GF_Err iprp_box_read(GF_Box *s, GF_BitStream *bs)
462 : {
463 54 : return gf_isom_box_array_read(s, bs);
464 : }
465 :
466 : #ifndef GPAC_DISABLE_ISOM_WRITE
467 :
468 89 : GF_Err iprp_box_write(GF_Box *s, GF_BitStream *bs)
469 : {
470 89 : return gf_isom_box_write_header(s, bs);
471 : }
472 :
473 269 : GF_Err iprp_box_size(GF_Box *s)
474 : {
475 269 : u32 pos=0;
476 : GF_ItemPropertiesBox *p = (GF_ItemPropertiesBox *)s;
477 269 : gf_isom_check_position(s, (GF_Box*)p->property_container, &pos);
478 269 : gf_isom_check_position(s, (GF_Box*)p->property_association, &pos);
479 269 : return GF_OK;
480 : }
481 :
482 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
483 :
484 144 : GF_Box *ipma_box_new()
485 : {
486 288 : ISOM_DECL_BOX_ALLOC(GF_ItemPropertyAssociationBox, GF_ISOM_BOX_TYPE_IPMA);
487 144 : tmp->entries = gf_list_new();
488 144 : return (GF_Box *)tmp;
489 : }
490 :
491 144 : void ipma_box_del(GF_Box *a)
492 : {
493 : GF_ItemPropertyAssociationBox *p = (GF_ItemPropertyAssociationBox *)a;
494 144 : if (p->entries) {
495 : u32 i;
496 : u32 count;
497 144 : count = gf_list_count(p->entries);
498 :
499 481 : for (i = 0; i < count; i++) {
500 337 : GF_ItemPropertyAssociationEntry *entry = (GF_ItemPropertyAssociationEntry *)gf_list_get(p->entries, i);
501 337 : if (entry) {
502 337 : gf_free(entry->associations);
503 337 : gf_free(entry);
504 : }
505 : }
506 144 : gf_list_del(p->entries);
507 : }
508 144 : gf_free(p);
509 144 : }
510 :
511 54 : GF_Err ipma_box_read(GF_Box *s, GF_BitStream *bs)
512 : {
513 : u32 i, j;
514 : GF_ItemPropertyAssociationBox *p = (GF_ItemPropertyAssociationBox *)s;
515 : u32 entry_count;
516 :
517 54 : ISOM_DECREASE_SIZE(p, 4)
518 54 : entry_count = gf_bs_read_u32(bs);
519 173 : for (i = 0; i < entry_count; i++) {
520 : GF_ItemPropertyAssociationEntry *entry;
521 119 : GF_SAFEALLOC(entry, GF_ItemPropertyAssociationEntry);
522 119 : if (!entry) return GF_OUT_OF_MEM;
523 119 : gf_list_add(p->entries, entry);
524 119 : if (p->version == 0) {
525 119 : ISOM_DECREASE_SIZE(p, 3)
526 119 : entry->item_id = gf_bs_read_u16(bs);
527 : } else {
528 0 : ISOM_DECREASE_SIZE(p, 5)
529 0 : entry->item_id = gf_bs_read_u32(bs);
530 : }
531 119 : entry->nb_associations = gf_bs_read_u8(bs);
532 119 : entry->associations = gf_malloc(sizeof(GF_ItemPropertyAssociationSlot) * entry->nb_associations);
533 119 : if (!entry->associations) return GF_OUT_OF_MEM;
534 492 : for (j = 0; j < entry->nb_associations; j++) {
535 492 : if (p->flags & 1) {
536 0 : u16 tmp = gf_bs_read_u16(bs);
537 0 : entry->associations[j].essential = (tmp >> 15) ? GF_TRUE : GF_FALSE;
538 0 : entry->associations[j].index = (tmp & 0x7FFF);
539 : } else {
540 492 : u8 tmp = gf_bs_read_u8(bs);
541 492 : entry->associations[j].essential = (tmp >> 7) ? GF_TRUE : GF_FALSE;
542 492 : entry->associations[j].index = (tmp & 0x7F);
543 : }
544 : }
545 : }
546 : return GF_OK;
547 : }
548 :
549 : #ifndef GPAC_DISABLE_ISOM_WRITE
550 89 : GF_Err ipma_box_write(GF_Box *s, GF_BitStream *bs)
551 : {
552 : u32 i, j;
553 : GF_Err e;
554 : u32 entry_count;
555 : GF_ItemPropertyAssociationBox *p = (GF_ItemPropertyAssociationBox*)s;
556 :
557 89 : e = gf_isom_full_box_write(s, bs);
558 89 : if (e) return e;
559 89 : entry_count = gf_list_count(p->entries);
560 89 : gf_bs_write_u32(bs, entry_count);
561 308 : for (i = 0; i < entry_count; i++) {
562 219 : GF_ItemPropertyAssociationEntry *entry = (GF_ItemPropertyAssociationEntry *)gf_list_get(p->entries, i);
563 219 : if (p->version == 0) {
564 219 : gf_bs_write_u16(bs, entry->item_id);
565 : } else {
566 0 : gf_bs_write_u32(bs, entry->item_id);
567 : }
568 219 : gf_bs_write_u8(bs, entry->nb_associations);
569 1110 : for (j = 0; j < entry->nb_associations; j++) {
570 891 : if (p->flags & 1) {
571 0 : gf_bs_write_u16(bs, (u16)( ( (entry->associations[j].essential ? 1 : 0) << 15) | (entry->associations[j].index & 0x7F) ) );
572 : } else {
573 891 : gf_bs_write_u8(bs, (u32)(( (entry->associations[j].essential ? 1 : 0) << 7) | entry->associations[j].index));
574 : }
575 : }
576 : }
577 : return GF_OK;
578 : }
579 :
580 269 : GF_Err ipma_box_size(GF_Box *s)
581 : {
582 : u32 i;
583 : u32 entry_count;
584 : GF_ItemPropertyAssociationBox *p = (GF_ItemPropertyAssociationBox*)s;
585 :
586 269 : entry_count = gf_list_count(p->entries);
587 269 : p->size += 4;
588 269 : if (p->version == 0) {
589 269 : p->size += entry_count * 2;
590 : } else {
591 0 : p->size += entry_count * 4;
592 : }
593 269 : p->size += entry_count;
594 930 : for (i = 0; i < entry_count; i++) {
595 661 : GF_ItemPropertyAssociationEntry *entry = (GF_ItemPropertyAssociationEntry *)gf_list_get(p->entries, i);
596 661 : if (p->flags & 1) {
597 0 : p->size += entry->nb_associations * 2;
598 : } else {
599 661 : p->size += entry->nb_associations;
600 : }
601 : }
602 269 : return GF_OK;
603 : }
604 :
605 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
606 :
607 3 : GF_Box *grpl_box_new()
608 : {
609 6 : ISOM_DECL_BOX_ALLOC(GF_GroupListBox, GF_ISOM_BOX_TYPE_GRPL);
610 3 : return (GF_Box *)tmp;
611 : }
612 :
613 3 : void grpl_box_del(GF_Box *s)
614 : {
615 : GF_GroupListBox *p = (GF_GroupListBox *)s;
616 3 : gf_free(p);
617 3 : }
618 :
619 1 : GF_Err grpl_box_read(GF_Box *s, GF_BitStream *bs)
620 : {
621 1 : return gf_isom_box_array_read_ex(s, bs, s->type);
622 : }
623 :
624 : #ifndef GPAC_DISABLE_ISOM_WRITE
625 :
626 1 : GF_Err grpl_box_write(GF_Box *s, GF_BitStream *bs)
627 : {
628 1 : if (!s) return GF_BAD_PARAM;
629 1 : return gf_isom_box_write_header(s, bs);
630 : }
631 :
632 1 : GF_Err grpl_box_size(GF_Box *s)
633 : {
634 1 : return GF_OK;
635 : }
636 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
637 :
638 :
639 2 : void grptype_box_del(GF_Box *s)
640 : {
641 : GF_EntityToGroupTypeBox *ptr = (GF_EntityToGroupTypeBox *)s;
642 2 : if (!ptr) return;
643 2 : if (ptr->entity_ids) gf_free(ptr->entity_ids);
644 2 : gf_free(ptr);
645 : }
646 :
647 :
648 0 : GF_Err grptype_box_read(GF_Box *s, GF_BitStream *bs)
649 : {
650 : u32 i;
651 : GF_EntityToGroupTypeBox *ptr = (GF_EntityToGroupTypeBox *)s;
652 :
653 0 : ISOM_DECREASE_SIZE(ptr, 8)
654 0 : ptr->group_id = gf_bs_read_u32(bs);
655 0 : ptr->entity_id_count = gf_bs_read_u32(bs);
656 :
657 0 : if (ptr->entity_id_count > ptr->size / 4) return GF_ISOM_INVALID_FILE;
658 :
659 0 : ptr->entity_ids = (u32 *) gf_malloc(ptr->entity_id_count * sizeof(u32));
660 0 : if (!ptr->entity_ids) return GF_OUT_OF_MEM;
661 :
662 0 : for (i = 0; i < ptr->entity_id_count; i++) {
663 0 : ptr->entity_ids[i] = gf_bs_read_u32(bs);
664 : }
665 : return GF_OK;
666 : }
667 :
668 2 : GF_Box *grptype_box_new()
669 : {
670 4 : ISOM_DECL_BOX_ALLOC(GF_EntityToGroupTypeBox, GF_ISOM_BOX_TYPE_GRPT);
671 : //the group type code is assign in gf_isom_box_parse_ex
672 2 : return (GF_Box *)tmp;
673 : }
674 :
675 : #ifndef GPAC_DISABLE_ISOM_WRITE
676 :
677 1 : GF_Err grptype_box_write(GF_Box *s, GF_BitStream *bs)
678 : {
679 : GF_Err e;
680 : u32 i;
681 : GF_EntityToGroupTypeBox *ptr = (GF_EntityToGroupTypeBox *)s;
682 1 : ptr->type = ptr->grouping_type;
683 1 : e = gf_isom_full_box_write(s, bs);
684 1 : if (e) return e;
685 1 : ptr->type = GF_ISOM_BOX_TYPE_GRPT;
686 :
687 1 : gf_bs_write_u32(bs, ptr->group_id);
688 1 : gf_bs_write_u32(bs, ptr->entity_id_count);
689 :
690 1 : for (i = 0; i < ptr->entity_id_count; i++) {
691 0 : gf_bs_write_u32(bs, ptr->entity_ids[i]);
692 : }
693 : return GF_OK;
694 : }
695 :
696 :
697 1 : GF_Err grptype_box_size(GF_Box *s)
698 : {
699 : GF_EntityToGroupTypeBox *ptr = (GF_EntityToGroupTypeBox *)s;
700 1 : ptr->size += 8 + 4*ptr->entity_id_count;
701 1 : return GF_OK;
702 : }
703 :
704 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
705 :
706 :
707 4 : GF_Box *auxc_box_new()
708 : {
709 8 : ISOM_DECL_BOX_ALLOC(GF_AuxiliaryTypePropertyBox, GF_ISOM_BOX_TYPE_AUXC);
710 4 : return (GF_Box *)tmp;
711 : }
712 :
713 4 : void auxc_box_del(GF_Box *a)
714 : {
715 : GF_AuxiliaryTypePropertyBox *p = (GF_AuxiliaryTypePropertyBox *)a;
716 4 : if (p->aux_urn) gf_free(p->aux_urn);
717 4 : if (p->data) gf_free(p->data);
718 4 : gf_free(p);
719 4 : }
720 :
721 1 : GF_Err auxc_box_read(GF_Box *s, GF_BitStream *bs)
722 : {
723 : GF_AuxiliaryTypePropertyBox *p = (GF_AuxiliaryTypePropertyBox *)s;
724 : GF_Err e;
725 :
726 1 : e = gf_isom_read_null_terminated_string(s, bs, s->size, &p->aux_urn);
727 1 : if (e) return e;
728 1 : p->data_size = (u32) p->size;
729 1 : p->data = gf_malloc(sizeof(char) * p->data_size);
730 1 : gf_bs_read_data(bs, p->data, p->data_size);
731 1 : return GF_OK;
732 : }
733 :
734 : #ifndef GPAC_DISABLE_ISOM_WRITE
735 2 : GF_Err auxc_box_write(GF_Box *s, GF_BitStream *bs)
736 : {
737 : GF_Err e;
738 : GF_AuxiliaryTypePropertyBox *p = (GF_AuxiliaryTypePropertyBox*)s;
739 :
740 2 : e = gf_isom_full_box_write(s, bs);
741 2 : if (e) return e;
742 : //with terminating 0
743 2 : if (p->aux_urn)
744 1 : gf_bs_write_data(bs, p->aux_urn, (u32) strlen(p->aux_urn) );
745 2 : gf_bs_write_u8(bs, 0);
746 2 : gf_bs_write_data(bs, p->data, p->data_size);
747 :
748 2 : return GF_OK;
749 : }
750 :
751 4 : GF_Err auxc_box_size(GF_Box *s)
752 : {
753 : GF_AuxiliaryTypePropertyBox *p = (GF_AuxiliaryTypePropertyBox*)s;
754 4 : p->size += (p->aux_urn ? strlen(p->aux_urn) : 0) + 1 + p->data_size;
755 4 : return GF_OK;
756 : }
757 :
758 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
759 :
760 4 : void auxi_box_del(GF_Box *s)
761 : {
762 : GF_AuxiliaryTypeInfoBox *ptr = (GF_AuxiliaryTypeInfoBox *)s;
763 4 : if (ptr->aux_track_type) gf_free(ptr->aux_track_type);
764 4 : if (ptr) gf_free(ptr);
765 4 : return;
766 : }
767 :
768 1 : GF_Err auxi_box_read(GF_Box *s, GF_BitStream *bs)
769 : {
770 : GF_AuxiliaryTypeInfoBox *ptr = (GF_AuxiliaryTypeInfoBox *)s;
771 1 : return gf_isom_read_null_terminated_string(s, bs, s->size, &ptr->aux_track_type);
772 : }
773 :
774 4 : GF_Box *auxi_box_new()
775 : {
776 8 : ISOM_DECL_BOX_ALLOC(GF_AuxiliaryTypeInfoBox, GF_ISOM_BOX_TYPE_AUXI);
777 4 : return (GF_Box *) tmp;
778 : }
779 :
780 : #ifndef GPAC_DISABLE_ISOM_WRITE
781 :
782 2 : GF_Err auxi_box_write(GF_Box *s, GF_BitStream *bs)
783 : {
784 : GF_Err e;
785 : GF_AuxiliaryTypeInfoBox *ptr = (GF_AuxiliaryTypeInfoBox *)s;
786 :
787 2 : e = gf_isom_full_box_write(s, bs);
788 2 : if (e) return e;
789 : //with terminating 0
790 2 : if (ptr->aux_track_type)
791 1 : gf_bs_write_data(bs, ptr->aux_track_type, (u32) strlen(ptr->aux_track_type) );
792 2 : gf_bs_write_u8(bs, 0);
793 2 : return GF_OK;
794 : }
795 :
796 4 : GF_Err auxi_box_size(GF_Box *s)
797 : {
798 : GF_AuxiliaryTypeInfoBox *ptr = (GF_AuxiliaryTypeInfoBox *)s;
799 4 : ptr->size += (ptr->aux_track_type ? strlen(ptr->aux_track_type) : 0 )+ 1;
800 4 : return GF_OK;
801 : }
802 :
803 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
804 3 : GF_Box *oinf_box_new()
805 : {
806 6 : ISOM_DECL_BOX_ALLOC(GF_OINFPropertyBox, GF_ISOM_BOX_TYPE_OINF);
807 3 : tmp->oinf = gf_isom_oinf_new_entry();
808 3 : return (GF_Box *)tmp;
809 : }
810 :
811 3 : void oinf_box_del(GF_Box *a)
812 : {
813 : GF_OINFPropertyBox *p = (GF_OINFPropertyBox *)a;
814 3 : if (p->oinf) gf_isom_oinf_del_entry(p->oinf);
815 3 : gf_free(p);
816 3 : }
817 :
818 1 : GF_Err oinf_box_read(GF_Box *s, GF_BitStream *bs)
819 : {
820 : GF_OINFPropertyBox *p = (GF_OINFPropertyBox *)s;
821 1 : return gf_isom_oinf_read_entry(p->oinf, bs);
822 : }
823 :
824 : #ifndef GPAC_DISABLE_ISOM_WRITE
825 1 : GF_Err oinf_box_write(GF_Box *s, GF_BitStream *bs)
826 : {
827 : GF_Err e;
828 : GF_OINFPropertyBox *p = (GF_OINFPropertyBox*)s;
829 :
830 1 : e = gf_isom_full_box_write(s, bs);
831 1 : if (e) return e;
832 1 : return gf_isom_oinf_write_entry(p->oinf, bs);
833 : }
834 :
835 1 : GF_Err oinf_box_size(GF_Box *s)
836 : {
837 : GF_OINFPropertyBox *p = (GF_OINFPropertyBox*)s;
838 1 : if (!p->oinf) return GF_BAD_PARAM;
839 1 : p->size += gf_isom_oinf_size_entry(p->oinf);
840 1 : return GF_OK;
841 : }
842 :
843 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
844 :
845 3 : GF_Box *tols_box_new()
846 : {
847 6 : ISOM_DECL_BOX_ALLOC(GF_TargetOLSPropertyBox, GF_ISOM_BOX_TYPE_TOLS);
848 3 : return (GF_Box *)tmp;
849 : }
850 :
851 3 : void tols_box_del(GF_Box *a)
852 : {
853 3 : gf_free(a);
854 3 : }
855 :
856 1 : GF_Err tols_box_read(GF_Box *s, GF_BitStream *bs)
857 : {
858 : GF_TargetOLSPropertyBox *p = (GF_TargetOLSPropertyBox *)s;
859 :
860 1 : ISOM_DECREASE_SIZE(p, 2)
861 1 : p->target_ols_index = gf_bs_read_u16(bs);
862 1 : return GF_OK;
863 : }
864 :
865 : #ifndef GPAC_DISABLE_ISOM_WRITE
866 1 : GF_Err tols_box_write(GF_Box *s, GF_BitStream *bs)
867 : {
868 : GF_Err e;
869 : GF_TargetOLSPropertyBox *p = (GF_TargetOLSPropertyBox*)s;
870 :
871 1 : e = gf_isom_full_box_write(s, bs);
872 1 : if (e) return e;
873 1 : gf_bs_write_u16(bs, p->target_ols_index);
874 1 : return GF_OK;
875 : }
876 :
877 1 : GF_Err tols_box_size(GF_Box *s)
878 : {
879 : GF_TargetOLSPropertyBox *p = (GF_TargetOLSPropertyBox*)s;
880 1 : p->size += 2;
881 1 : return GF_OK;
882 : }
883 :
884 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
885 :
886 :
887 4 : GF_Box *clli_box_new()
888 : {
889 8 : ISOM_DECL_BOX_ALLOC(GF_ContentLightLevelBox, GF_ISOM_BOX_TYPE_CLLI);
890 4 : return (GF_Box *)tmp;
891 : }
892 :
893 4 : void clli_box_del(GF_Box *a)
894 : {
895 : GF_ContentLightLevelBox *p = (GF_ContentLightLevelBox *)a;
896 4 : gf_free(p);
897 4 : }
898 :
899 1 : GF_Err clli_box_read(GF_Box *s, GF_BitStream *bs)
900 : {
901 : GF_ContentLightLevelBox *p = (GF_ContentLightLevelBox *)s;
902 1 : ISOM_DECREASE_SIZE(p, 4)
903 1 : p->clli.max_content_light_level = gf_bs_read_u16(bs);
904 1 : p->clli.max_pic_average_light_level = gf_bs_read_u16(bs);
905 1 : return GF_OK;
906 : }
907 :
908 : #ifndef GPAC_DISABLE_ISOM_WRITE
909 :
910 2 : GF_Err clli_box_write(GF_Box *s, GF_BitStream *bs)
911 : {
912 : GF_Err e;
913 : GF_ContentLightLevelBox *p = (GF_ContentLightLevelBox*)s;
914 2 : e = gf_isom_box_write_header(s, bs);
915 2 : if (e) return e;
916 2 : gf_bs_write_u16(bs, p->clli.max_content_light_level);
917 2 : gf_bs_write_u16(bs, p->clli.max_pic_average_light_level);
918 2 : return GF_OK;
919 : }
920 :
921 4 : GF_Err clli_box_size(GF_Box *s)
922 : {
923 : GF_ContentLightLevelBox *p = (GF_ContentLightLevelBox*)s;
924 4 : p->size += 4;
925 4 : return GF_OK;
926 : }
927 :
928 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
929 :
930 :
931 4 : GF_Box *mdcv_box_new()
932 : {
933 8 : ISOM_DECL_BOX_ALLOC(GF_MasteringDisplayColourVolumeBox, GF_ISOM_BOX_TYPE_MDCV);
934 4 : return (GF_Box *)tmp;
935 : }
936 :
937 4 : void mdcv_box_del(GF_Box *a)
938 : {
939 : GF_MasteringDisplayColourVolumeBox *p = (GF_MasteringDisplayColourVolumeBox *)a;
940 4 : gf_free(p);
941 4 : }
942 :
943 1 : GF_Err mdcv_box_read(GF_Box *s, GF_BitStream *bs)
944 : {
945 : int c = 0;
946 : GF_MasteringDisplayColourVolumeBox *p = (GF_MasteringDisplayColourVolumeBox *)s;
947 1 : ISOM_DECREASE_SIZE(p, 24)
948 4 : for (c = 0; c<3; c++) {
949 3 : p->mdcv.display_primaries[c].x = gf_bs_read_u16(bs);
950 3 : p->mdcv.display_primaries[c].y = gf_bs_read_u16(bs);
951 : }
952 1 : p->mdcv.white_point_x = gf_bs_read_u16(bs);
953 1 : p->mdcv.white_point_y = gf_bs_read_u16(bs);
954 1 : p->mdcv.max_display_mastering_luminance = gf_bs_read_u32(bs);
955 1 : p->mdcv.min_display_mastering_luminance = gf_bs_read_u32(bs);
956 :
957 1 : return GF_OK;
958 : }
959 :
960 : #ifndef GPAC_DISABLE_ISOM_WRITE
961 :
962 2 : GF_Err mdcv_box_write(GF_Box *s, GF_BitStream *bs)
963 : {
964 : int c = 0;
965 : GF_Err e;
966 : GF_MasteringDisplayColourVolumeBox *p = (GF_MasteringDisplayColourVolumeBox*)s;
967 2 : e = gf_isom_box_write_header(s, bs);
968 2 : if (e) return e;
969 :
970 6 : for (c = 0; c<3; c++) {
971 6 : gf_bs_write_u16(bs, p->mdcv.display_primaries[c].x);
972 6 : gf_bs_write_u16(bs, p->mdcv.display_primaries[c].y);
973 : }
974 2 : gf_bs_write_u16(bs, p->mdcv.white_point_x);
975 2 : gf_bs_write_u16(bs, p->mdcv.white_point_y);
976 2 : gf_bs_write_u32(bs, p->mdcv.max_display_mastering_luminance);
977 2 : gf_bs_write_u32(bs, p->mdcv.min_display_mastering_luminance);
978 :
979 2 : return GF_OK;
980 : }
981 :
982 4 : GF_Err mdcv_box_size(GF_Box *s)
983 : {
984 : GF_MasteringDisplayColourVolumeBox *p = (GF_MasteringDisplayColourVolumeBox*)s;
985 4 : p->size += 24;
986 4 : return GF_OK;
987 : }
988 :
989 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
990 :
991 :
992 48 : GF_Box *ienc_box_new()
993 : {
994 96 : ISOM_DECL_BOX_ALLOC(GF_ItemEncryptionPropertyBox, GF_ISOM_BOX_TYPE_IENC);
995 48 : return (GF_Box *)tmp;
996 : }
997 :
998 48 : void ienc_box_del(GF_Box *a)
999 : {
1000 : GF_ItemEncryptionPropertyBox *p = (GF_ItemEncryptionPropertyBox *)a;
1001 48 : if (p->key_info) gf_free(p->key_info);
1002 48 : gf_free(p);
1003 48 : }
1004 :
1005 23 : GF_Err ienc_box_read(GF_Box *s, GF_BitStream *bs)
1006 : {
1007 : u32 nb_keys;
1008 : GF_ItemEncryptionPropertyBox *p = (GF_ItemEncryptionPropertyBox *)s;
1009 :
1010 23 : ISOM_DECREASE_SIZE(p, 3)
1011 23 : gf_bs_read_u8(bs);
1012 23 : if (p->version == 0) {
1013 15 : gf_bs_read_u8(bs);
1014 : } else {
1015 8 : p->skip_byte_block = gf_bs_read_int(bs, 4);
1016 8 : p->crypt_byte_block = gf_bs_read_int(bs, 4);
1017 : }
1018 23 : nb_keys = gf_bs_read_u8(bs);
1019 23 : if (nb_keys * (sizeof(bin128)+1) > p->size)
1020 : return GF_NON_COMPLIANT_BITSTREAM;
1021 23 : p->key_info_size = (u32) (3+p->size);
1022 23 : p->key_info = gf_malloc(sizeof(u8) * p->key_info_size);
1023 23 : if (!p->key_info) return GF_OUT_OF_MEM;
1024 23 : p->key_info[0] = 1;
1025 23 : p->key_info[1] = 0;
1026 23 : p->key_info[2] = nb_keys;
1027 23 : gf_bs_read_data(bs, p->key_info+3, (u32) p->size);
1028 23 : p->size = 0;
1029 23 : if (!gf_cenc_validate_key_info(p->key_info, p->key_info_size))
1030 : return GF_ISOM_INVALID_FILE;
1031 23 : return GF_OK;
1032 : }
1033 :
1034 : #ifndef GPAC_DISABLE_ISOM_WRITE
1035 23 : GF_Err ienc_box_write(GF_Box *s, GF_BitStream *bs)
1036 : {
1037 : GF_Err e;
1038 : u32 nb_keys;
1039 : GF_ItemEncryptionPropertyBox *p = (GF_ItemEncryptionPropertyBox*)s;
1040 23 : if (p->skip_byte_block || p->crypt_byte_block)
1041 8 : p->version = 1;
1042 23 : e = gf_isom_full_box_write(s, bs);
1043 23 : if (e) return e;
1044 23 : gf_bs_write_u8(bs, 0);
1045 23 : if (p->version) {
1046 8 : gf_bs_write_int(bs, p->skip_byte_block, 4);
1047 8 : gf_bs_write_int(bs, p->crypt_byte_block, 4);
1048 : } else {
1049 15 : gf_bs_write_u8(bs, 0);
1050 : }
1051 23 : if (p->key_info[0]) {
1052 3 : if (p->key_info[1]) {
1053 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Too many keys for ienc box, max is 255)\n"))
1054 : return GF_BAD_PARAM;
1055 : }
1056 3 : nb_keys = p->key_info[2];
1057 : } else {
1058 : nb_keys = 1;
1059 : }
1060 23 : gf_bs_write_u8(bs, nb_keys);
1061 23 : gf_bs_write_data(bs, p->key_info+3, p->key_info_size-3);
1062 23 : return GF_OK;
1063 : }
1064 :
1065 70 : GF_Err ienc_box_size(GF_Box *s)
1066 : {
1067 : GF_ItemEncryptionPropertyBox *p = (GF_ItemEncryptionPropertyBox*)s;
1068 70 : if (!p->key_info || (p->key_info_size<19))
1069 : return GF_BAD_PARAM;
1070 69 : p->size += 3 + p->key_info_size-3;
1071 69 : return GF_OK;
1072 : }
1073 :
1074 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
1075 :
1076 :
1077 9 : GF_Box *iaux_box_new()
1078 : {
1079 18 : ISOM_DECL_BOX_ALLOC(GF_AuxiliaryInfoPropertyBox, GF_ISOM_BOX_TYPE_IAUX);
1080 9 : return (GF_Box *)tmp;
1081 : }
1082 :
1083 9 : void iaux_box_del(GF_Box *a)
1084 : {
1085 9 : gf_free(a);
1086 9 : }
1087 :
1088 4 : GF_Err iaux_box_read(GF_Box *s, GF_BitStream *bs)
1089 : {
1090 : GF_AuxiliaryInfoPropertyBox *p = (GF_AuxiliaryInfoPropertyBox *)s;
1091 :
1092 4 : ISOM_DECREASE_SIZE(p, 8)
1093 4 : p->aux_info_type = gf_bs_read_u32(bs);
1094 4 : p->aux_info_parameter = gf_bs_read_u32(bs);
1095 4 : return GF_OK;
1096 : }
1097 :
1098 : #ifndef GPAC_DISABLE_ISOM_WRITE
1099 4 : GF_Err iaux_box_write(GF_Box *s, GF_BitStream *bs)
1100 : {
1101 : GF_Err e;
1102 : GF_AuxiliaryInfoPropertyBox *p = (GF_AuxiliaryInfoPropertyBox*)s;
1103 :
1104 4 : e = gf_isom_full_box_write(s, bs);
1105 4 : if (e) return e;
1106 4 : gf_bs_write_u32(bs, p->aux_info_type);
1107 4 : gf_bs_write_u32(bs, p->aux_info_parameter);
1108 4 : return GF_OK;
1109 : }
1110 :
1111 10 : GF_Err iaux_box_size(GF_Box *s)
1112 : {
1113 : GF_AuxiliaryInfoPropertyBox *p = (GF_AuxiliaryInfoPropertyBox*)s;
1114 10 : p->size += 8;
1115 10 : return GF_OK;
1116 : }
1117 :
1118 : #endif /*GPAC_DISABLE_ISOM_WRITE*/
1119 :
1120 :
1121 :
1122 102 : 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) {
1123 : #ifndef GPAC_DISABLE_ISOM_WRITE
1124 : GF_Err e;
1125 : u32 w, h, hSpacing, vSpacing;
1126 : u8 num_channels;
1127 : u8 bits_per_channel[3];
1128 : u32 subtype;
1129 102 : GF_ISOSample *sample = NULL;
1130 : u32 timescale;
1131 : u32 item_type = 0;
1132 : GF_ImageItemProperties local_image_props;
1133 : GF_ImageItemProtection ipro, *orig_ipro = NULL;
1134 : Bool config_needed = 0;
1135 : GF_Box *config_box = NULL;
1136 : Bool is_cenc = GF_FALSE;
1137 : Bool is_first = GF_TRUE;
1138 102 : Bool neg_time = (image_props && image_props->time<0) ? GF_TRUE : GF_FALSE;
1139 102 : u8 *sai = NULL;
1140 102 : u32 sai_size = 0, sai_alloc_size = 0;
1141 102 : u32 sample_desc_index = 0;
1142 : GF_ISOFile *fsrc = movie;
1143 :
1144 102 : if (image_props && image_props->src_file)
1145 : fsrc = image_props->src_file;
1146 :
1147 102 : if (image_props && image_props->tile_mode != TILE_ITEM_NONE) {
1148 : /* Processing the input file in Tiled mode:
1149 : The single track is split into multiple tracks
1150 : and each track is processed to create an item */
1151 : u32 i, count;
1152 : u32 tile_track;
1153 : GF_List *tile_item_ids;
1154 : char sz_item_name[256];
1155 : GF_TileItemMode orig_tile_mode;
1156 :
1157 : #if !defined(GPAC_DISABLE_HEVC) && !defined(GPAC_DISABLE_AV_PARSERS)
1158 1 : if (image_props->src_file)
1159 : e = GF_SERVICE_ERROR;
1160 : else
1161 1 : e = gf_media_split_hevc_tiles(movie, 0);
1162 : #else
1163 : e = GF_NOT_SUPPORTED;
1164 : #endif
1165 :
1166 1 : if (e) return e;
1167 1 : tile_item_ids = gf_list_new();
1168 1 : orig_tile_mode = image_props->tile_mode;
1169 1 : image_props->tile_mode = TILE_ITEM_NONE;
1170 1 : count = gf_isom_get_reference_count(movie, imported_track, GF_ISOM_REF_SABT);
1171 11 : for (i = 0; i < count; i++) {
1172 9 : u32 *tile_item_id = gf_malloc(sizeof(u32));
1173 9 : if (!tile_item_id) return GF_OUT_OF_MEM;
1174 :
1175 9 : *tile_item_id = item_id + i+1;
1176 9 : gf_list_add(tile_item_ids, tile_item_id);
1177 9 : e = gf_isom_get_reference(movie, imported_track, GF_ISOM_REF_SABT, 1, &tile_track);
1178 9 : if (e) return e;
1179 9 : sprintf(sz_item_name, "%s-Tile%d", (item_name ? item_name : "Image"), i + 1);
1180 9 : if (orig_tile_mode != TILE_ITEM_SINGLE || image_props->single_tile_number == i + 1) {
1181 9 : e = gf_isom_iff_create_image_item_from_track(movie, root_meta, meta_track_number, tile_track, sz_item_name, *tile_item_id, NULL, NULL);
1182 : }
1183 9 : if (e) return e;
1184 9 : gf_isom_remove_track(movie, tile_track);
1185 9 : if (orig_tile_mode == TILE_ITEM_ALL_BASE) {
1186 9 : e = gf_isom_meta_add_item_ref(movie, root_meta, meta_track_number, *tile_item_id, item_id, GF_ISOM_REF_TBAS, NULL);
1187 : }
1188 9 : if (e) return e;
1189 : }
1190 1 : sprintf(sz_item_name, "%s-TileBase", (item_name ? item_name : "Image"));
1191 1 : if (orig_tile_mode == TILE_ITEM_ALL_BASE) {
1192 1 : gf_isom_iff_create_image_item_from_track(movie, root_meta, meta_track_number, imported_track, sz_item_name, item_id, image_props, tile_item_ids);
1193 : }
1194 : else if (orig_tile_mode == TILE_ITEM_ALL_GRID) {
1195 : // TODO
1196 : }
1197 9 : for (i = 0; i < count; i++) {
1198 9 : u32 *tile_item_id = gf_list_get(tile_item_ids, i);
1199 9 : gf_free(tile_item_id);
1200 : }
1201 1 : gf_list_del(tile_item_ids);
1202 1 : return GF_OK;
1203 : }
1204 :
1205 101 : if (!image_props) {
1206 : image_props = &local_image_props;
1207 : memset(image_props, 0, sizeof(GF_ImageItemProperties));
1208 : } else {
1209 51 : orig_ipro = image_props->cenc_info;
1210 51 : image_props->cenc_info = NULL;
1211 : }
1212 :
1213 101 : import_next_sample:
1214 :
1215 385 : timescale = gf_isom_get_media_timescale(fsrc, imported_track);
1216 385 : if (image_props->sample_num) {
1217 5 : sample_number = image_props->sample_num;
1218 5 : sample = gf_isom_get_sample(fsrc, imported_track, sample_number, &sample_desc_index);
1219 5 : e = gf_isom_last_error(fsrc);
1220 380 : } else if (image_props->time<0) {
1221 265 : sample = gf_isom_get_sample(fsrc, imported_track, sample_number, &sample_desc_index);
1222 265 : e = gf_isom_last_error(fsrc);
1223 : } else {
1224 115 : 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);
1225 : }
1226 385 : if (e || !sample || !sample->IsRAP) {
1227 243 : if (!sample) {
1228 2 : if (is_first) {
1229 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("No sample found%s\n", (image_props->time<0) ? "" : " for requested time"));
1230 : } else {
1231 : e = GF_OK;
1232 : goto exit;
1233 : }
1234 241 : } else if ((image_props->time<0) || (image_props->step_time)) {
1235 241 : if (image_props->sample_num) {
1236 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));
1237 241 : } else if (image_props->step_time) {
1238 0 : gf_isom_sample_del(&sample);
1239 : e = GF_OK;
1240 0 : goto exit;
1241 : } else {
1242 241 : gf_isom_sample_del(&sample);
1243 241 : sample_number++;
1244 241 : if (sample_number == gf_isom_get_sample_count(fsrc, imported_track)) {
1245 : e = GF_OK;
1246 : goto exit;
1247 : }
1248 : goto import_next_sample;
1249 : }
1250 : } else {
1251 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Error no sync sample found after time %g\n", image_props->time));
1252 : }
1253 0 : if (!e) e = GF_BAD_PARAM;
1254 : goto exit;
1255 : }
1256 :
1257 : /* Check if the track type is supported as item type */
1258 : /* Get the config box if needed */
1259 142 : subtype = gf_isom_get_media_subtype(fsrc, imported_track, sample_desc_index);
1260 142 : if (gf_isom_is_media_encrypted(fsrc, imported_track, sample_desc_index)) {
1261 13 : if (gf_isom_is_cenc_media(fsrc, imported_track, sample_desc_index)) {
1262 13 : e = gf_isom_get_original_format_type(fsrc, imported_track, sample_desc_index, &subtype);
1263 13 : if (e) goto exit;
1264 : is_cenc = GF_TRUE;
1265 : } else {
1266 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Protected sample not using CENC, cannot add as item\n"));
1267 : e = GF_BAD_PARAM;
1268 : goto exit;
1269 : }
1270 : }
1271 :
1272 :
1273 142 : switch (subtype) {
1274 12 : case GF_ISOM_SUBTYPE_AVC_H264:
1275 : case GF_ISOM_SUBTYPE_AVC2_H264:
1276 : case GF_ISOM_SUBTYPE_AVC3_H264:
1277 : case GF_ISOM_SUBTYPE_AVC4_H264:
1278 : //FIXME: in avc1 with multiple descriptor, we should take the right description index
1279 12 : config_box = gf_isom_box_new(GF_ISOM_BOX_TYPE_AVCC);
1280 12 : if (!config_box) { e = GF_OUT_OF_MEM; goto exit; }
1281 12 : ((GF_AVCConfigurationBox *)config_box)->config = gf_isom_avc_config_get(fsrc, imported_track, sample_desc_index);
1282 12 : if (! ((GF_AVCConfigurationBox *)config_box)->config) { e = GF_OUT_OF_MEM; goto exit; }
1283 : item_type = GF_ISOM_SUBTYPE_AVC_H264;
1284 : config_needed = 1;
1285 : num_channels = 3;
1286 12 : bits_per_channel[0] = ((GF_AVCConfigurationBox *)config_box)->config->luma_bit_depth;
1287 12 : bits_per_channel[1] = ((GF_AVCConfigurationBox *)config_box)->config->chroma_bit_depth;
1288 : bits_per_channel[2] = ((GF_AVCConfigurationBox *)config_box)->config->chroma_bit_depth;
1289 12 : break;
1290 0 : case GF_ISOM_SUBTYPE_SVC_H264:
1291 0 : config_box = gf_isom_box_new(GF_ISOM_BOX_TYPE_SVCC);
1292 0 : if (!config_box) { e = GF_OUT_OF_MEM; goto exit; }
1293 0 : ((GF_AVCConfigurationBox *)config_box)->config = gf_isom_svc_config_get(fsrc, imported_track, sample_desc_index);
1294 0 : if (! ((GF_AVCConfigurationBox *)config_box)->config) { e = GF_OUT_OF_MEM; goto exit; }
1295 : item_type = GF_ISOM_SUBTYPE_SVC_H264;
1296 : config_needed = 1;
1297 : num_channels = 3;
1298 0 : bits_per_channel[0] = ((GF_AVCConfigurationBox *)config_box)->config->luma_bit_depth;
1299 0 : bits_per_channel[1] = ((GF_AVCConfigurationBox *)config_box)->config->chroma_bit_depth;
1300 : bits_per_channel[2] = ((GF_AVCConfigurationBox *)config_box)->config->chroma_bit_depth;
1301 0 : break;
1302 0 : case GF_ISOM_SUBTYPE_MVC_H264:
1303 0 : config_box = gf_isom_box_new(GF_ISOM_BOX_TYPE_MVCC);
1304 0 : if (!config_box) { e = GF_OUT_OF_MEM; goto exit; }
1305 0 : ((GF_AVCConfigurationBox *)config_box)->config = gf_isom_mvc_config_get(fsrc, imported_track, sample_desc_index);
1306 0 : if (! ((GF_AVCConfigurationBox *)config_box)->config) { e = GF_OUT_OF_MEM; goto exit; }
1307 : item_type = GF_ISOM_SUBTYPE_MVC_H264;
1308 : config_needed = 1;
1309 : num_channels = 3;
1310 0 : bits_per_channel[0] = ((GF_AVCConfigurationBox *)config_box)->config->luma_bit_depth;
1311 0 : bits_per_channel[1] = ((GF_AVCConfigurationBox *)config_box)->config->chroma_bit_depth;
1312 : bits_per_channel[2] = ((GF_AVCConfigurationBox *)config_box)->config->chroma_bit_depth;
1313 0 : break;
1314 78 : case GF_ISOM_SUBTYPE_HVC1:
1315 : case GF_ISOM_SUBTYPE_HEV1:
1316 : case GF_ISOM_SUBTYPE_HVC2:
1317 : case GF_ISOM_SUBTYPE_HEV2:
1318 : case GF_ISOM_SUBTYPE_HVT1:
1319 : case GF_ISOM_SUBTYPE_LHV1:
1320 : case GF_ISOM_SUBTYPE_LHE1:
1321 78 : config_box = gf_isom_box_new(GF_ISOM_BOX_TYPE_HVCC);
1322 78 : if (!config_box) { e = GF_OUT_OF_MEM; goto exit; }
1323 78 : ((GF_HEVCConfigurationBox *)config_box)->config = gf_isom_hevc_config_get(fsrc, imported_track, sample_desc_index);
1324 78 : if (! ((GF_HEVCConfigurationBox *)config_box)->config) { e = GF_OUT_OF_MEM; goto exit; }
1325 78 : if (subtype == GF_ISOM_SUBTYPE_HVT1) {
1326 : item_type = GF_ISOM_SUBTYPE_HVT1;
1327 : }
1328 : else {
1329 : item_type = GF_ISOM_SUBTYPE_HVC1;
1330 : }
1331 : config_needed = 1;
1332 : if (!((GF_HEVCConfigurationBox *)config_box)->config) {
1333 : ((GF_HEVCConfigurationBox *)config_box)->config = gf_isom_lhvc_config_get(fsrc, imported_track, sample_desc_index);
1334 : if (! ((GF_HEVCConfigurationBox *)config_box)->config) { e = GF_OUT_OF_MEM; goto exit; }
1335 : item_type = GF_ISOM_SUBTYPE_LHV1;
1336 : }
1337 : num_channels = 3;
1338 78 : bits_per_channel[0] = ((GF_HEVCConfigurationBox *)config_box)->config->luma_bit_depth;
1339 78 : bits_per_channel[1] = ((GF_HEVCConfigurationBox *)config_box)->config->chroma_bit_depth;
1340 : bits_per_channel[2] = ((GF_HEVCConfigurationBox *)config_box)->config->chroma_bit_depth;
1341 : //media_brand = GF_ISOM_BRAND_HEIC;
1342 78 : break;
1343 52 : case GF_ISOM_SUBTYPE_AV01:
1344 : {
1345 52 : config_box = gf_isom_box_new(GF_ISOM_BOX_TYPE_AV1C);
1346 52 : if (!config_box) { e = GF_OUT_OF_MEM; goto exit; }
1347 52 : ((GF_AV1ConfigurationBox *)config_box)->config = gf_isom_av1_config_get(fsrc, imported_track, sample_desc_index);
1348 52 : if (! ((GF_AV1ConfigurationBox *)config_box)->config) { e = GF_OUT_OF_MEM; goto exit; }
1349 : item_type = GF_ISOM_SUBTYPE_AV01;
1350 : config_needed = 1;
1351 52 : u8 depth = ((GF_AV1ConfigurationBox *)config_box)->config->high_bitdepth ? (((GF_AV1ConfigurationBox *)config_box)->config->twelve_bit ? 12 : 10 ) : 8;
1352 52 : if (((GF_AV1ConfigurationBox *)config_box)->config->monochrome) {
1353 : num_channels = 1;
1354 : bits_per_channel[0] = depth;
1355 : bits_per_channel[1] = 0;
1356 : bits_per_channel[2] = 0;
1357 : } else {
1358 : num_channels = 3;
1359 : bits_per_channel[0] = depth;
1360 : bits_per_channel[1] = depth;
1361 : bits_per_channel[2] = depth;
1362 : }
1363 : //media_brand = GF_ISOM_BRAND_AVIF;
1364 : }
1365 : break;
1366 :
1367 0 : case GF_ISOM_SUBTYPE_VVC1:
1368 0 : config_box = gf_isom_box_new(GF_ISOM_BOX_TYPE_VVCC);
1369 0 : if (!config_box) { e = GF_OUT_OF_MEM; goto exit; }
1370 0 : ((GF_VVCConfigurationBox *)config_box)->config = gf_isom_vvc_config_get(fsrc, imported_track, sample_desc_index);
1371 0 : if (! ((GF_VVCConfigurationBox *)config_box)->config) { e = GF_OUT_OF_MEM; goto exit; }
1372 : item_type = GF_ISOM_SUBTYPE_VVC1;
1373 :
1374 : config_needed = 1;
1375 : num_channels = 3;
1376 0 : bits_per_channel[0] = ((GF_VVCConfigurationBox *)config_box)->config->bit_depth_plus_one - 1;
1377 : bits_per_channel[1] = bits_per_channel[2] = bits_per_channel[0];
1378 : //media_brand = GF_ISOM_BRAND_HEIC;
1379 0 : break;
1380 0 : default:
1381 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Error: Codec not supported to create HEIF image items\n"));
1382 : e = GF_NOT_SUPPORTED;
1383 : goto exit;
1384 : }
1385 142 : if (config_needed && !config_box && !((GF_AVCConfigurationBox *)config_box)->config) {
1386 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)));
1387 : e = GF_BAD_PARAM;
1388 : goto exit;
1389 : }
1390 : /* Get some images properties from the track data */
1391 142 : e = gf_isom_get_visual_info(fsrc, imported_track, sample_desc_index, &w, &h);
1392 142 : if (e) {
1393 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Error determining image size\n"));
1394 : goto exit;
1395 : }
1396 142 : e = gf_isom_get_pixel_aspect_ratio(fsrc, imported_track, sample_desc_index, &hSpacing, &vSpacing);
1397 142 : if (e) {
1398 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Error determining image aspect ratio\n"));
1399 : goto exit;
1400 : }
1401 142 : if (!image_props->width && !image_props->height) {
1402 101 : image_props->width = w;
1403 101 : image_props->height = h;
1404 : }
1405 142 : if (!image_props->hSpacing && !image_props->vSpacing) {
1406 101 : image_props->hSpacing = hSpacing;
1407 101 : image_props->vSpacing = vSpacing;
1408 : }
1409 142 : image_props->config = config_box;
1410 142 : if (!image_props->num_channels) {
1411 101 : image_props->num_channels = num_channels;
1412 101 : image_props->bits_per_channel[0] = bits_per_channel[0];
1413 101 : image_props->bits_per_channel[1] = bits_per_channel[1];
1414 101 : image_props->bits_per_channel[2] = bits_per_channel[2];
1415 : }
1416 142 : if (is_cenc) {
1417 : Bool Is_Encrypted;
1418 :
1419 : memset(&ipro, 0, sizeof(GF_ImageItemProtection));
1420 13 : gf_isom_get_cenc_info(fsrc, imported_track, sample_desc_index, NULL, &ipro.scheme_type, &ipro.scheme_version);
1421 13 : e = gf_isom_get_sample_cenc_info(fsrc, imported_track, sample_desc_index, &Is_Encrypted, &ipro.crypt_byte_block, &ipro.skip_byte_block, &ipro.key_info, &ipro.key_info_size);
1422 13 : if (e) goto exit;
1423 :
1424 13 : if (Is_Encrypted) {
1425 13 : sai_size = sai_alloc_size;
1426 13 : e = gf_isom_cenc_get_sample_aux_info(fsrc, imported_track, sample_number, sample_desc_index, NULL, &sai, &sai_size);
1427 13 : if (e) goto exit;
1428 :
1429 13 : if (sai_size > sai_alloc_size)
1430 : sai_alloc_size = sai_size;
1431 :
1432 13 : ipro.sai_data = sai;
1433 13 : ipro.sai_data_size = sai_size;
1434 13 : image_props->cenc_info = &ipro;
1435 :
1436 13 : if (is_first) {
1437 13 : u32 i, nb_pssh = gf_isom_get_pssh_count(fsrc);
1438 44 : for (i=0; i<nb_pssh; i++) {
1439 : bin128 SystemID;
1440 : u32 version;
1441 : u32 KID_count;
1442 : const bin128 *KIDs;
1443 : const u8 *private_data;
1444 : u32 private_data_size;
1445 :
1446 18 : gf_isom_get_pssh_info(fsrc, i+1, SystemID, &version, &KID_count, &KIDs, &private_data, &private_data_size);
1447 :
1448 18 : gf_cenc_set_pssh(movie, SystemID, version, KID_count, (bin128 *) KIDs, (u8 *) private_data, private_data_size, 2);
1449 : }
1450 : }
1451 :
1452 : } else {
1453 0 : image_props->cenc_info = NULL;
1454 : }
1455 : }
1456 :
1457 142 : if (!item_id) {
1458 41 : e = gf_isom_meta_get_next_item_id(movie, root_meta, meta_track_number, &item_id);
1459 41 : if (e) goto exit;
1460 : }
1461 142 : if (image_props->use_reference) {
1462 1 : if (image_props->sample_num) {
1463 1 : GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("referring trackID %d sample %d as item %d\n", imported_track, sample_number, item_id));
1464 : } else {
1465 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));
1466 : }
1467 1 : e = gf_isom_add_meta_item_sample_ref(movie, root_meta, meta_track_number, (!item_name || !strlen(item_name)) ? "Image" : item_name, &item_id, item_type, NULL, NULL, image_props, imported_track, sample_number);
1468 : } else {
1469 :
1470 141 : if (image_props->sample_num) {
1471 4 : GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("Adding sample %d as item %d\n", sample_number, item_id));
1472 : } else {
1473 137 : 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));
1474 : }
1475 141 : e = gf_isom_add_meta_item_memory(movie, root_meta, meta_track_number, (!item_name || !strlen(item_name) ? "Image" : item_name), &item_id, item_type, NULL, NULL, image_props, sample->data, sample->dataLength, item_extent_refs);
1476 :
1477 : }
1478 :
1479 142 : image_props->cenc_info = NULL;
1480 :
1481 142 : gf_isom_set_brand_info(movie, GF_ISOM_BRAND_MIF1, 0);
1482 142 : gf_isom_reset_alt_brands(movie);
1483 : // TODO Analyze configuration to determine the brand */
1484 : //if (media_brand) {
1485 : // gf_isom_modify_alternate_brand(movie, media_brand, GF_TRUE);
1486 : //}
1487 :
1488 142 : if (neg_time)
1489 25 : image_props->time = -1;
1490 :
1491 421 : if (!e && !image_props->sample_num && ((image_props->time<0) || image_props->end_time || image_props->step_time)) {
1492 48 : if (image_props->end_time || image_props->step_time) {
1493 26 : Double t = (Double) (sample->DTS + sample->CTS_Offset);
1494 26 : t /= timescale;
1495 26 : if (image_props->step_time) {
1496 6 : t += image_props->step_time;
1497 : } else {
1498 : //step 1ms
1499 20 : t += 0.001;
1500 : }
1501 :
1502 26 : if ((image_props->end_time>0) && (t>image_props->end_time)) {
1503 : goto exit;
1504 : }
1505 22 : image_props->time = t;
1506 : }
1507 :
1508 44 : item_id=0;
1509 44 : gf_isom_sample_del(&sample);
1510 44 : if (config_box) {
1511 44 : gf_isom_box_del(config_box);
1512 : config_box = NULL;
1513 : }
1514 : is_first = GF_FALSE;
1515 44 : if (sample_number >= gf_isom_get_sample_count(fsrc, imported_track)) return e;
1516 43 : sample_number++;
1517 : //avoid recursion this could get quite big
1518 43 : goto import_next_sample;
1519 : }
1520 :
1521 198 : exit:
1522 100 : if (sai) gf_free(sai);
1523 100 : gf_isom_sample_del(&sample);
1524 100 : if (config_box) gf_isom_box_del(config_box);
1525 100 : image_props->cenc_info = orig_ipro;
1526 100 : return e;
1527 :
1528 :
1529 : #else
1530 : return GF_NOT_SUPPORTED;
1531 : #endif
1532 :
1533 : }
1534 :
1535 : static
1536 9 : 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) {
1537 : GF_Err e = GF_OK;
1538 : u32 grid4cc = GF_4CC('g', 'r', 'i', 'd');
1539 : GF_BitStream *grid_bs;
1540 9 : if (image_props->num_grid_rows < 1 || image_props->num_grid_columns < 1 || image_props->width == 0 || image_props->height == 0) {
1541 : return GF_BAD_PARAM;
1542 : }
1543 9 : grid_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
1544 9 : if (!grid_bs) return GF_OUT_OF_MEM;
1545 9 : gf_bs_write_u8(grid_bs, 0);
1546 9 : gf_bs_write_u8(grid_bs, 0);
1547 9 : gf_bs_write_u8(grid_bs, image_props->num_grid_rows-1);
1548 9 : gf_bs_write_u8(grid_bs, image_props->num_grid_columns-1);
1549 9 : gf_bs_write_u16(grid_bs, image_props->width);
1550 9 : gf_bs_write_u16(grid_bs, image_props->height);
1551 : u8 *grid_data;
1552 : u32 grid_data_size;
1553 9 : gf_bs_get_content(grid_bs, &grid_data, &grid_data_size);
1554 9 : 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);
1555 9 : gf_free(grid_data);
1556 9 : gf_bs_del(grid_bs);
1557 9 : return e;
1558 : }
1559 :
1560 : GF_EXPORT
1561 7 : 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)
1562 : {
1563 7 : return gf_isom_iff_create_image_grid_item_internal(movie, root_meta, meta_track_number, item_name, &item_id, image_props);
1564 : }
1565 :
1566 2 : 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)
1567 : {
1568 : GF_Err e;
1569 : GF_ImageItemProperties props;
1570 : u32 w=0, h=0;
1571 : u32 *imgs_ids=NULL;
1572 : u32 nb_imgs=0, nb_src_imgs;
1573 : u32 nb_cols, nb_rows;
1574 : u32 last_valid_nb_cols;
1575 : Bool first_pass = GF_TRUE;
1576 : Double ar;
1577 2 : u32 i, nb_items = gf_isom_get_meta_item_count(movie, root_meta, meta_track_number);
1578 16 : for (i=0; i<nb_items; i++) {
1579 : u32 an_item_id, item_type;
1580 12 : 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);
1581 :
1582 12 : if (!item_id) continue;
1583 12 : if (item_type==GF_ISOM_ITEM_TYPE_AUXI) continue;
1584 :
1585 : memset(&props, 0, sizeof(props));
1586 12 : gf_isom_get_meta_image_props(movie, root_meta, meta_track_number, an_item_id, &props);
1587 12 : if (!props.width || !props.height) continue;
1588 :
1589 12 : if (!w) w = props.width;
1590 12 : if (!h) h = props.height;
1591 :
1592 12 : if ((w != props.width) || (h != props.height)) {
1593 0 : if (imgs_ids) gf_free(imgs_ids);
1594 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Auto grid can only be generated for images of the same size - try using `-add-image-grid`\n"));
1595 0 : return GF_NOT_SUPPORTED;
1596 : }
1597 12 : imgs_ids = gf_realloc(imgs_ids, sizeof(u32) * (nb_imgs+1));
1598 12 : if (!imgs_ids) return GF_OUT_OF_MEM;
1599 12 : imgs_ids[nb_imgs] = an_item_id;
1600 : nb_imgs++;
1601 : }
1602 :
1603 2 : if (!nb_imgs || !w || !h) {
1604 0 : if (imgs_ids) gf_free(imgs_ids);
1605 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("No image items found\n"));
1606 : return GF_BAD_PARAM;
1607 : }
1608 :
1609 : //try roughly the same aspect ratio
1610 2 : if (image_props->auto_grid_ratio) {
1611 : ar = image_props->auto_grid_ratio;
1612 : } else {
1613 1 : ar = w;
1614 1 : ar /= h;
1615 : }
1616 : nb_src_imgs = nb_imgs;
1617 :
1618 2 : recompute_grid:
1619 : nb_cols=1;
1620 : nb_rows=1;
1621 : last_valid_nb_cols = 0;
1622 :
1623 2 : if (nb_imgs>1) {
1624 5 : while (nb_cols < nb_imgs) {
1625 5 : Double target_ar = ((Double) nb_cols) * w;
1626 5 : nb_rows = nb_imgs / nb_cols;
1627 5 : if (nb_rows * nb_cols != nb_imgs) {
1628 0 : nb_cols++;
1629 0 : continue;
1630 : }
1631 5 : target_ar /= ((Double)nb_rows) * h;
1632 5 : if (target_ar >= ar) break;
1633 : last_valid_nb_cols = nb_cols;
1634 3 : nb_cols++;
1635 : }
1636 : }
1637 2 : if ((nb_cols==nb_imgs) && last_valid_nb_cols) {
1638 : nb_cols = last_valid_nb_cols;
1639 0 : nb_rows = nb_imgs / nb_cols;
1640 : }
1641 :
1642 2 : if (first_pass && (nb_imgs>1) && ((nb_cols==1) || (nb_rows==1) ) ) {
1643 0 : if (nb_imgs % 2) {
1644 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("Not an even number of images, removing last item from grid\n"));
1645 0 : nb_imgs--;
1646 : first_pass = GF_FALSE;
1647 0 : goto recompute_grid;
1648 : }
1649 : }
1650 :
1651 : memset(&props, 0, sizeof(props));
1652 : if (image_props)
1653 : memcpy(&props, image_props, sizeof(props));
1654 2 : props.hidden = GF_FALSE;
1655 2 : props.width = nb_cols * w;
1656 2 : props.height = nb_rows * h;
1657 2 : props.num_grid_rows = nb_rows;
1658 2 : props.num_grid_columns = nb_cols;
1659 2 : 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));
1660 :
1661 2 : e = gf_isom_iff_create_image_grid_item_internal(movie, root_meta, meta_track_number, item_name, &item_id, &props);
1662 2 : if (e) {
1663 0 : gf_free(imgs_ids);
1664 0 : return e;
1665 : }
1666 :
1667 12 : for (i=0; i<nb_imgs; i++) {
1668 12 : 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);
1669 12 : if (e) goto exit;
1670 : }
1671 :
1672 : //we might want an option to avoid this?
1673 : //if (image_props->hidden)
1674 : {
1675 2 : GF_MetaBox *meta = gf_isom_get_meta(movie, root_meta, meta_track_number);
1676 14 : for (i=0; i<nb_src_imgs; i++) {
1677 : GF_ItemInfoEntryBox *iinf;
1678 12 : u32 j=0;
1679 54 : while ((iinf = (GF_ItemInfoEntryBox *)gf_list_enum(meta->item_infos->item_infos, &j))) {
1680 42 : if (iinf->item_ID == imgs_ids[i]) {
1681 12 : iinf->flags |= 0x1;
1682 12 : break;
1683 : }
1684 : }
1685 : }
1686 2 : e = gf_isom_set_meta_primary_item(movie, root_meta, meta_track_number, item_id);
1687 : }
1688 :
1689 2 : exit:
1690 2 : gf_free(imgs_ids);
1691 2 : return e;
1692 : }
1693 :
1694 : GF_EXPORT
1695 104 : 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)
1696 : {
1697 :
1698 104 : if (image_props && image_props->auto_grid)
1699 2 : return iff_create_auto_grid(movie, root_meta, meta_track_number, item_name, item_id, image_props);
1700 :
1701 102 : 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);
1702 : }
1703 :
1704 :
1705 : #endif /*GPAC_DISABLE_ISOM*/
|