MSVC: add missing source files.
[L-SMASH.git] / core / box.c
blobb20110f846b1d90c8a006a48df796323dfc01022
1 /*****************************************************************************
2 * box.c:
3 *****************************************************************************
4 * Copyright (C) 2012-2015 L-SMASH project
6 * Authors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 *****************************************************************************/
21 /* This file is available under an ISC license. */
23 #include "common/internal.h" /* must be placed first */
25 #include <stdlib.h>
26 #include <string.h>
28 #include "box.h"
29 #include "write.h"
30 #include "read.h"
31 #include "print.h"
32 #include "timeline.h"
34 #include "codecs/mp4a.h"
35 #include "codecs/mp4sys.h"
37 #include "importer/importer.h"
39 static const lsmash_class_t lsmash_box_class =
41 "box"
44 const lsmash_box_type_t static_lsmash_box_type_unspecified = LSMASH_BOX_TYPE_INITIALIZER;
46 void isom_init_box_common_orig
48 void *_box,
49 void *_parent,
50 lsmash_box_type_t box_type,
51 uint64_t precedence,
52 isom_extension_destructor_t destructor
55 isom_box_t *box = (isom_box_t *)_box;
56 isom_box_t *parent = (isom_box_t *)_parent;
57 assert( box && parent && parent->root );
58 box->class = &lsmash_box_class;
59 box->root = parent->root;
60 box->file = parent->file;
61 box->parent = parent;
62 box->precedence = precedence;
63 box->destruct = destructor;
64 box->size = 0;
65 box->type = box_type;
66 if( !lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_STSD ) && isom_is_fullbox( box ) )
68 box->version = 0;
69 box->flags = 0;
71 isom_set_box_writer( box );
74 static void isom_reorder_tail_box( isom_box_t *parent )
76 /* Reorder the appended box by 'precedence'. */
77 lsmash_entry_t *x = parent->extensions.tail;
78 assert( x && x->data );
79 uint64_t precedence = ((isom_box_t *)x->data)->precedence;
80 for( lsmash_entry_t *y = x->prev; y; y = y->prev )
82 isom_box_t *box = (isom_box_t *)y->data;
83 if( !box || precedence > box->precedence )
85 /* Exchange the entity data of adjacent two entries. */
86 y->data = x->data;
87 x->data = box;
88 x = y;
90 else
91 break;
95 int isom_add_box_to_extension_list( void *parent_box, void *child_box )
97 assert( parent_box && child_box );
98 isom_box_t *parent = (isom_box_t *)parent_box;
99 isom_box_t *child = (isom_box_t *)child_box;
100 /* Append at the end of the list. */
101 if( lsmash_add_entry( &parent->extensions, child ) < 0 )
102 return LSMASH_ERR_MEMORY_ALLOC;
103 /* Don't reorder the appended box when the file is opened for reading. */
104 if( !parent->file || (parent->file->flags & LSMASH_FILE_MODE_READ) || parent->file->fake_file_mode )
105 return 0;
106 isom_reorder_tail_box( parent );
107 return 0;
110 void isom_bs_put_basebox_common( lsmash_bs_t *bs, isom_box_t *box )
112 if( box->size > UINT32_MAX )
114 lsmash_bs_put_be32( bs, 1 );
115 lsmash_bs_put_be32( bs, box->type.fourcc );
116 lsmash_bs_put_be64( bs, box->size ); /* largesize */
118 else
120 lsmash_bs_put_be32( bs, (uint32_t)box->size );
121 lsmash_bs_put_be32( bs, box->type.fourcc );
123 if( box->type.fourcc == ISOM_BOX_TYPE_UUID.fourcc )
125 lsmash_bs_put_be32( bs, box->type.user.fourcc );
126 lsmash_bs_put_bytes( bs, 12, box->type.user.id );
130 void isom_bs_put_fullbox_common( lsmash_bs_t *bs, isom_box_t *box )
132 isom_bs_put_basebox_common( bs, box );
133 lsmash_bs_put_byte( bs, box->version );
134 lsmash_bs_put_be24( bs, box->flags );
137 void isom_bs_put_box_common( lsmash_bs_t *bs, void *box )
139 if( !box )
141 bs->error = 1;
142 return;
144 isom_box_t *parent = ((isom_box_t *)box)->parent;
145 if( parent && lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_STSD ) )
147 isom_bs_put_basebox_common( bs, (isom_box_t *)box );
148 return;
150 if( isom_is_fullbox( box ) )
151 isom_bs_put_fullbox_common( bs, (isom_box_t *)box );
152 else
153 isom_bs_put_basebox_common( bs, (isom_box_t *)box );
156 /* Return 1 if the box is fullbox, Otherwise return 0. */
157 int isom_is_fullbox( void *box )
159 isom_box_t *current = (isom_box_t *)box;
160 lsmash_box_type_t type = current->type;
161 static lsmash_box_type_t fullbox_type_table[50] = { LSMASH_BOX_TYPE_INITIALIZER };
162 if( !lsmash_check_box_type_specified( &fullbox_type_table[0] ) )
164 /* Initialize the table. */
165 int i = 0;
166 fullbox_type_table[i++] = ISOM_BOX_TYPE_SIDX;
167 fullbox_type_table[i++] = ISOM_BOX_TYPE_MVHD;
168 fullbox_type_table[i++] = ISOM_BOX_TYPE_TKHD;
169 fullbox_type_table[i++] = ISOM_BOX_TYPE_IODS;
170 fullbox_type_table[i++] = ISOM_BOX_TYPE_ESDS;
171 fullbox_type_table[i++] = QT_BOX_TYPE_ESDS;
172 fullbox_type_table[i++] = QT_BOX_TYPE_CLEF;
173 fullbox_type_table[i++] = QT_BOX_TYPE_PROF;
174 fullbox_type_table[i++] = QT_BOX_TYPE_ENOF;
175 fullbox_type_table[i++] = ISOM_BOX_TYPE_ELST;
176 fullbox_type_table[i++] = ISOM_BOX_TYPE_MDHD;
177 fullbox_type_table[i++] = ISOM_BOX_TYPE_HDLR;
178 fullbox_type_table[i++] = ISOM_BOX_TYPE_VMHD;
179 fullbox_type_table[i++] = ISOM_BOX_TYPE_SMHD;
180 fullbox_type_table[i++] = ISOM_BOX_TYPE_HMHD;
181 fullbox_type_table[i++] = ISOM_BOX_TYPE_NMHD;
182 fullbox_type_table[i++] = QT_BOX_TYPE_GMIN;
183 fullbox_type_table[i++] = ISOM_BOX_TYPE_DREF;
184 fullbox_type_table[i++] = ISOM_BOX_TYPE_STSD;
185 fullbox_type_table[i++] = ISOM_BOX_TYPE_STSL;
186 fullbox_type_table[i++] = QT_BOX_TYPE_CHAN;
187 fullbox_type_table[i++] = ISOM_BOX_TYPE_SRAT;
188 fullbox_type_table[i++] = ISOM_BOX_TYPE_STTS;
189 fullbox_type_table[i++] = ISOM_BOX_TYPE_CTTS;
190 fullbox_type_table[i++] = ISOM_BOX_TYPE_CSLG;
191 fullbox_type_table[i++] = ISOM_BOX_TYPE_STSS;
192 fullbox_type_table[i++] = QT_BOX_TYPE_STPS;
193 fullbox_type_table[i++] = ISOM_BOX_TYPE_SDTP;
194 fullbox_type_table[i++] = ISOM_BOX_TYPE_STSC;
195 fullbox_type_table[i++] = ISOM_BOX_TYPE_STSZ;
196 fullbox_type_table[i++] = ISOM_BOX_TYPE_STZ2;
197 fullbox_type_table[i++] = ISOM_BOX_TYPE_STCO;
198 fullbox_type_table[i++] = ISOM_BOX_TYPE_CO64;
199 fullbox_type_table[i++] = ISOM_BOX_TYPE_SGPD;
200 fullbox_type_table[i++] = ISOM_BOX_TYPE_SBGP;
201 fullbox_type_table[i++] = ISOM_BOX_TYPE_CHPL;
202 fullbox_type_table[i++] = ISOM_BOX_TYPE_META;
203 fullbox_type_table[i++] = QT_BOX_TYPE_KEYS;
204 fullbox_type_table[i++] = ISOM_BOX_TYPE_MEAN;
205 fullbox_type_table[i++] = ISOM_BOX_TYPE_NAME;
206 fullbox_type_table[i++] = ISOM_BOX_TYPE_MEHD;
207 fullbox_type_table[i++] = ISOM_BOX_TYPE_TREX;
208 fullbox_type_table[i++] = ISOM_BOX_TYPE_MFHD;
209 fullbox_type_table[i++] = ISOM_BOX_TYPE_TFHD;
210 fullbox_type_table[i++] = ISOM_BOX_TYPE_TFDT;
211 fullbox_type_table[i++] = ISOM_BOX_TYPE_TRUN;
212 fullbox_type_table[i++] = ISOM_BOX_TYPE_TFRA;
213 fullbox_type_table[i++] = ISOM_BOX_TYPE_MFRO;
214 fullbox_type_table[i] = LSMASH_BOX_TYPE_UNSPECIFIED;
216 for( int i = 0; lsmash_check_box_type_specified( &fullbox_type_table[i] ); i++ )
217 if( lsmash_check_box_type_identical( type, fullbox_type_table[i] ) )
218 return 1;
219 if( current->parent )
221 if( lsmash_check_box_type_identical( current->parent->type, ISOM_BOX_TYPE_DREF )
222 || (lsmash_check_box_type_identical( type, ISOM_BOX_TYPE_CPRT )
223 && lsmash_check_box_type_identical( current->parent->type, ISOM_BOX_TYPE_UDTA )) )
224 return 1;
226 return 0;
229 /* Return 1 if the sample type is LPCM audio, Otherwise return 0. */
230 int isom_is_lpcm_audio( void *box )
232 isom_box_t *current = (isom_box_t *)box;
233 lsmash_box_type_t type = current->type;
234 return lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_23NI_AUDIO )
235 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_NONE_AUDIO )
236 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_LPCM_AUDIO )
237 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_SOWT_AUDIO )
238 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_TWOS_AUDIO )
239 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_FL32_AUDIO )
240 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_FL64_AUDIO )
241 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_IN24_AUDIO )
242 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_IN32_AUDIO )
243 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_NOT_SPECIFIED )
244 || (lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_RAW_AUDIO ) && (current->manager & LSMASH_AUDIO_DESCRIPTION));
247 int isom_is_qt_audio( lsmash_codec_type_t type )
249 return lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_23NI_AUDIO )
250 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_MAC3_AUDIO )
251 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_MAC6_AUDIO )
252 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_NONE_AUDIO )
253 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_QDM2_AUDIO )
254 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_QDMC_AUDIO )
255 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_QCLP_AUDIO )
256 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_AC_3_AUDIO )
257 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_AGSM_AUDIO )
258 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ALAC_AUDIO )
259 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ALAW_AUDIO )
260 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_CDX2_AUDIO )
261 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_CDX4_AUDIO )
262 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVCA_AUDIO )
263 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVI_AUDIO )
264 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_FL32_AUDIO )
265 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_FL64_AUDIO )
266 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_IMA4_AUDIO )
267 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_IN24_AUDIO )
268 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_IN32_AUDIO )
269 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_LPCM_AUDIO )
270 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_MP4A_AUDIO )
271 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_RAW_AUDIO )
272 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_SOWT_AUDIO )
273 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_TWOS_AUDIO )
274 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ULAW_AUDIO )
275 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_VDVA_AUDIO )
276 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_FULLMP3_AUDIO )
277 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_MP3_AUDIO )
278 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ADPCM2_AUDIO )
279 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ADPCM17_AUDIO )
280 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_GSM49_AUDIO )
281 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_NOT_SPECIFIED );
284 /* Return 1 if the sample type is uncompressed Y'CbCr video, Otherwise return 0. */
285 int isom_is_uncompressed_ycbcr( lsmash_codec_type_t type )
287 return lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_2VUY_VIDEO )
288 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V210_VIDEO )
289 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V216_VIDEO )
290 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V308_VIDEO )
291 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V408_VIDEO )
292 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V410_VIDEO )
293 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_YUV2_VIDEO );
296 int isom_is_waveform_audio( lsmash_box_type_t type )
298 return lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ADPCM2_AUDIO )
299 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ADPCM17_AUDIO )
300 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_GSM49_AUDIO )
301 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_FULLMP3_AUDIO )
302 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_MP3_AUDIO );
305 size_t isom_skip_box_common( uint8_t **p_data )
307 uint8_t *orig = *p_data;
308 uint8_t *data = *p_data;
309 uint64_t size = LSMASH_GET_BE32( data );
310 data += ISOM_BASEBOX_COMMON_SIZE;
311 if( size == 1 )
313 size = LSMASH_GET_BE64( data );
314 data += 8;
316 *p_data = data;
317 return data - orig;
320 /* TODO: more secure handling */
321 static size_t isom_read_box_size_and_type_from_binary_string( uint8_t **p_data, uint64_t *size, lsmash_box_type_t *type )
323 uint8_t *orig = *p_data;
324 uint8_t *data = *p_data;
325 *size = LSMASH_GET_BE32( &data[0] );
326 type->fourcc = LSMASH_GET_BE32( &data[4] );
327 data += ISOM_BASEBOX_COMMON_SIZE;
328 if( *size == 1 )
330 *size = LSMASH_GET_BE64( data );
331 data += 8;
333 *p_data = data;
334 if( type->fourcc == ISOM_BOX_TYPE_UUID.fourcc )
336 type->user.fourcc = LSMASH_GET_BE32( &data[0] );
337 memcpy( type->user.id, &data[4], 12 );
339 return data - orig;
342 uint8_t *isom_get_child_box_position( uint8_t *parent_data, uint32_t parent_size, lsmash_box_type_t child_type, uint32_t *child_size )
344 if( !parent_data || !child_size || parent_size < ISOM_BASEBOX_COMMON_SIZE )
345 return NULL;
346 uint8_t *data = parent_data;
347 uint64_t size;
348 lsmash_box_type_t type;
349 uint32_t offset = isom_read_box_size_and_type_from_binary_string( &data, &size, &type );
350 if( size != parent_size )
351 return NULL;
352 uint8_t *end = parent_data + parent_size;
353 for( uint8_t *pos = data; pos + ISOM_BASEBOX_COMMON_SIZE <= end; )
355 offset = isom_read_box_size_and_type_from_binary_string( &pos, &size, &type );
356 if( lsmash_check_box_type_identical( type, child_type ) )
358 *child_size = size;
359 return pos - offset;
361 pos += size - offset; /* Move to the next box. */
363 return NULL;
366 static void isom_destruct_extension_binary( void *ext )
368 if( !ext )
369 return;
370 isom_box_t *box = (isom_box_t *)ext;
371 lsmash_free( box->binary );
374 int isom_add_extension_binary
376 void *parent_box,
377 lsmash_box_type_t box_type,
378 uint64_t precedence,
379 uint8_t *box_data,
380 uint32_t box_size
383 if( !parent_box || !box_data || box_size < ISOM_BASEBOX_COMMON_SIZE
384 || !lsmash_check_box_type_specified( &box_type ) )
385 return LSMASH_ERR_FUNCTION_PARAM;
386 isom_box_t *ext = lsmash_malloc_zero( sizeof(isom_box_t) );
387 if( !ext )
388 return LSMASH_ERR_MEMORY_ALLOC;
389 isom_box_t *parent = (isom_box_t *)parent_box;
390 ext->class = &lsmash_box_class;
391 ext->root = parent->root;
392 ext->file = parent->file;
393 ext->parent = parent;
394 ext->manager = LSMASH_BINARY_CODED_BOX;
395 ext->precedence = precedence;
396 ext->size = box_size;
397 ext->type = box_type;
398 ext->binary = box_data;
399 ext->destruct = isom_destruct_extension_binary;
400 if( isom_add_box_to_extension_list( parent, ext ) < 0 )
402 lsmash_free( ext );
403 return LSMASH_ERR_MEMORY_ALLOC;
405 isom_set_box_writer( ext );
406 return 0;
409 static void isom_remove_extension_box( isom_box_t *ext )
411 if( !ext )
412 return;
413 if( ext->destruct )
414 ext->destruct( ext );
415 isom_remove_all_extension_boxes( &ext->extensions );
416 lsmash_free( ext );
419 void isom_remove_all_extension_boxes( lsmash_entry_list_t *extensions )
421 lsmash_remove_entries( extensions, isom_remove_extension_box );
424 isom_box_t *isom_get_extension_box( lsmash_entry_list_t *extensions, lsmash_box_type_t box_type )
426 for( lsmash_entry_t *entry = extensions->head; entry; entry = entry->next )
428 isom_box_t *ext = (isom_box_t *)entry->data;
429 if( !ext )
430 continue;
431 if( lsmash_check_box_type_identical( ext->type, box_type ) )
432 return ext;
434 return NULL;
437 void *isom_get_extension_box_format( lsmash_entry_list_t *extensions, lsmash_box_type_t box_type )
439 for( lsmash_entry_t *entry = extensions->head; entry; entry = entry->next )
441 isom_box_t *ext = (isom_box_t *)entry->data;
442 if( !ext || (ext->manager & LSMASH_BINARY_CODED_BOX) || !lsmash_check_box_type_identical( ext->type, box_type ) )
443 continue;
444 return ext;
446 return NULL;
449 lsmash_entry_t *isom_get_entry_of_box
451 lsmash_box_t *parent,
452 const lsmash_box_path_t box_path[]
455 if( !parent )
456 return NULL;
457 lsmash_entry_t *entry = NULL;
458 const lsmash_box_path_t *path = &box_path[0];
459 while( lsmash_check_box_type_specified( &path->type ) )
461 entry = parent->extensions.head;
462 if( !entry )
463 return NULL;
464 parent = NULL;
465 uint32_t i = 1;
466 uint32_t number = path->number ? path->number : 1;
467 while( entry )
469 isom_box_t *box = entry->data;
470 if( box && lsmash_check_box_type_identical( path->type, box->type ) )
472 if( i == number )
474 /* Found a box. Move to a child box. */
475 parent = box;
476 ++path;
477 break;
479 ++i;
481 entry = entry->next;
483 if( !parent )
484 return NULL;
486 return entry;
489 /* box destructors */
490 #define REMOVE_BOX( box_name, parent_type ) \
491 isom_remove_predefined_box( box_name, offsetof( parent_type, box_name ) )
493 #define REMOVE_BOX_IN_LIST( box_name, parent_type ) \
494 isom_remove_box_in_predefined_list( box_name, offsetof( parent_type, box_name##_list ) )
496 #define REMOVE_LIST_BOX_TEMPLATE( REMOVER, box_name, parent_type, eliminator ) \
497 do \
499 lsmash_remove_list( box_name->list, eliminator ); \
500 REMOVER( box_name, parent_type ); \
501 } while( 0 )
503 #define REMOVE_LIST_BOX( box_name, ... ) CALL_FUNC_DEFAULT_ARGS( REMOVE_LIST_BOX, box_name, __VA_ARGS__ )
504 #define REMOVE_LIST_BOX_3( box_name, parent_type, eliminator ) \
505 REMOVE_LIST_BOX_TEMPLATE( REMOVE_BOX, box_name, parent_type, eliminator )
506 #define REMOVE_LIST_BOX_2( box_name, parent_type ) \
507 REMOVE_LIST_BOX_3( box_name, parent_type, NULL )
509 #define REMOVE_LIST_BOX_IN_LIST( box_name, parent_type ) \
510 REMOVE_LIST_BOX_TEMPLATE( REMOVE_BOX_IN_LIST, box_name, parent_type, NULL )
512 #define DEFINE_SIMPLE_BOX_REMOVER_TEMPLATE( REMOVER, box_name, ... ) \
513 static void isom_remove_##box_name( isom_##box_name##_t *box_name ) \
515 if( !box_name ) \
516 return; \
517 REMOVER( box_name, __VA_ARGS__ ); \
520 #define DEFINE_SIMPLE_BOX_REMOVER( func_name, box_name, ... ) \
521 DEFINE_SIMPLE_BOX_REMOVER_TEMPLATE( REMOVE_BOX, box_name, __VA_ARGS__ )
523 #define DEFINE_SIMPLE_LIST_BOX_REMOVER( func_name, box_name, ... ) \
524 DEFINE_SIMPLE_BOX_REMOVER_TEMPLATE( REMOVE_LIST_BOX, box_name, __VA_ARGS__ )
526 #define DEFINE_SIMPLE_BOX_IN_LIST_REMOVER( func_name, box_name, ... ) \
527 DEFINE_SIMPLE_BOX_REMOVER_TEMPLATE( REMOVE_BOX_IN_LIST, box_name, __VA_ARGS__ )
529 #define DEFINE_SIMPLE_LIST_BOX_IN_LIST_REMOVER( func_name, box_name, ... ) \
530 DEFINE_SIMPLE_BOX_REMOVER_TEMPLATE( REMOVE_LIST_BOX_IN_LIST, box_name, __VA_ARGS__ )
532 static void isom_remove_predefined_box( void *opaque_box, size_t offset_of_box )
534 assert( opaque_box );
535 isom_box_t *box = (isom_box_t *)opaque_box;
536 if( box->parent )
538 isom_box_t **p = (isom_box_t **)(((int8_t *)box->parent) + offset_of_box);
539 if( *p == box )
540 *p = NULL;
544 /* We always free boxes through the extension list of the parent box.
545 * Therefore, don't free boxes through any list other than the extension list. */
546 static void isom_remove_box_in_predefined_list( void *opaque_box, size_t offset_of_list )
548 assert( opaque_box );
549 isom_box_t *box = (isom_box_t *)opaque_box;
550 if( box->parent )
552 lsmash_entry_list_t *list = (lsmash_entry_list_t *)(((int8_t *)box->parent) + offset_of_list);
553 if( list )
554 for( lsmash_entry_t *entry = list->head; entry; entry = entry->next )
555 if( box == entry->data )
557 /* We don't free this box here.
558 * Because of freeing an entry of the list here, don't pass the list to free this box.
559 * Or double free. */
560 entry->data = NULL;
561 lsmash_remove_entry_direct( list, entry, NULL );
562 break;
567 /* Remove a box by the pointer containing its address.
568 * In addition, remove from the extension list of the parent box if possible.
569 * Don't call this function within a function freeing one or more entries of any extension list because of double free.
570 * Basically, don't use this function as a callback function. */
571 void isom_remove_box_by_itself( void *opaque_box )
573 if( !opaque_box )
574 return;
575 isom_box_t *box = (isom_box_t *)opaque_box;
576 if( box->parent )
578 isom_box_t *parent = box->parent;
579 for( lsmash_entry_t *entry = parent->extensions.head; entry; entry = entry->next )
580 if( box == entry->data )
582 /* Free the corresponding entry here, therefore don't call this function as a callback function
583 * if a function frees the same entry later and calls this function. */
584 lsmash_remove_entry_direct( &parent->extensions, entry, isom_remove_extension_box );
585 return;
588 isom_remove_extension_box( box );
591 void isom_remove_unknown_box( isom_unknown_box_t *unknown_box )
593 if( !unknown_box )
594 return;
595 lsmash_free( unknown_box->unknown_field );
598 static void isom_remove_file( lsmash_file_t *file )
600 if( !file )
601 return;
602 isom_remove_print_funcs( file );
603 isom_remove_timelines( file );
604 lsmash_free( file->compatible_brands );
605 lsmash_bs_cleanup( file->bs );
606 lsmash_importer_destroy( file->importer );
607 if( file->fragment )
609 lsmash_remove_list( file->fragment->pool, isom_remove_sample_pool );
610 lsmash_free( file->fragment );
612 REMOVE_BOX_IN_LIST( file, lsmash_root_t );
615 static void isom_remove_ftyp( isom_ftyp_t *ftyp )
617 if( !ftyp )
618 return;
619 lsmash_free( ftyp->compatible_brands );
620 REMOVE_BOX( ftyp, lsmash_file_t );
623 static void isom_remove_iods( isom_iods_t *iods )
625 if( !iods )
626 return;
627 mp4sys_remove_descriptor( iods->OD );
628 REMOVE_BOX( iods, isom_moov_t );
631 static void isom_remove_trak( isom_trak_t *trak )
633 if( !trak )
634 return;
635 if( trak->cache )
637 isom_remove_sample_pool( trak->cache->chunk.pool );
638 lsmash_remove_list( trak->cache->roll.pool, NULL );
639 lsmash_free( trak->cache->rap );
640 lsmash_free( trak->cache->fragment );
641 lsmash_free( trak->cache );
643 REMOVE_BOX_IN_LIST( trak, isom_moov_t );
646 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_tkhd, tkhd, isom_trak_t )
647 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_clef, clef, isom_tapt_t )
648 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_prof, prof, isom_tapt_t )
649 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_enof, enof, isom_tapt_t )
650 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_tapt, tapt, isom_trak_t )
651 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_edts, edts, isom_trak_t )
652 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_tref, tref, isom_trak_t )
653 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_elst, elst, isom_edts_t )
655 static void isom_remove_track_reference_type( isom_tref_type_t *ref )
657 if( !ref )
658 return;
659 lsmash_free( ref->track_ID );
660 isom_remove_box_in_predefined_list( ref, offsetof( isom_tref_t, ref_list ) );
663 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mdhd, mdhd, isom_mdia_t )
664 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_vmhd, vmhd, isom_minf_t )
665 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_smhd, smhd, isom_minf_t )
666 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_hmhd, hmhd, isom_minf_t )
667 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_nmhd, nmhd, isom_minf_t )
668 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_gmhd, gmhd, isom_minf_t )
669 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_gmin, gmin, isom_gmhd_t )
670 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_text, text, isom_gmhd_t )
672 static void isom_remove_hdlr( isom_hdlr_t *hdlr )
674 if( !hdlr )
675 return;
676 lsmash_free( hdlr->componentName );
677 if( hdlr->parent )
679 if( lsmash_check_box_type_identical( hdlr->parent->type, ISOM_BOX_TYPE_MDIA ) )
680 REMOVE_BOX( hdlr, isom_mdia_t );
681 else if( lsmash_check_box_type_identical( hdlr->parent->type, ISOM_BOX_TYPE_META )
682 || lsmash_check_box_type_identical( hdlr->parent->type, QT_BOX_TYPE_META ) )
683 REMOVE_BOX( hdlr, isom_meta_t );
684 else if( lsmash_check_box_type_identical( hdlr->parent->type, ISOM_BOX_TYPE_MINF ) )
685 REMOVE_BOX( hdlr, isom_minf_t );
686 else
687 assert( 0 );
688 return;
692 static void isom_remove_glbl( isom_glbl_t *glbl )
694 if( !glbl )
695 return;
696 lsmash_free( glbl->header_data );
699 static void isom_remove_esds( isom_esds_t *esds )
701 if( !esds )
702 return;
703 mp4sys_remove_descriptor( esds->ES );
706 static void isom_remove_font_record( isom_font_record_t *font_record )
708 if( !font_record )
709 return;
710 lsmash_free( font_record->font_name );
711 lsmash_free( font_record );
713 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_ftab, ftab, isom_tx3g_entry_t, isom_remove_font_record )
715 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_frma, frma, isom_wave_t )
716 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_enda, enda, isom_wave_t )
717 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mp4a, mp4a, isom_wave_t )
718 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_terminator, terminator, isom_wave_t )
720 static void isom_remove_chan( isom_chan_t *chan )
722 if( !chan )
723 return;
724 lsmash_free( chan->channelDescriptions );
727 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_stsd, stsd, isom_stbl_t )
729 static void isom_remove_visual_description( isom_sample_entry_t *description )
731 isom_visual_entry_t *visual = (isom_visual_entry_t *)description;
732 lsmash_free( visual->color_table.array );
733 isom_remove_box_in_predefined_list( visual, offsetof( isom_stsd_t, list ) );
736 static void isom_remove_audio_description( isom_sample_entry_t *description )
738 isom_remove_box_in_predefined_list( description, offsetof( isom_stsd_t, list ) );
741 static void isom_remove_hint_description( isom_sample_entry_t *description )
743 isom_hint_entry_t *hint = (isom_hint_entry_t *)description;
744 lsmash_free( hint->data );
745 isom_remove_box_in_predefined_list( hint, offsetof( isom_stsd_t, list ) );
748 static void isom_remove_metadata_description( isom_sample_entry_t *description )
750 isom_remove_box_in_predefined_list( description, offsetof( isom_stsd_t, list ) );
753 static void isom_remove_tx3g_description( isom_sample_entry_t *description )
755 isom_remove_box_in_predefined_list( description, offsetof( isom_stsd_t, list ) );
758 static void isom_remove_qt_text_description( isom_sample_entry_t *description )
760 isom_qt_text_entry_t *text = (isom_qt_text_entry_t *)description;
761 lsmash_free( text->font_name );
762 isom_remove_box_in_predefined_list( text, offsetof( isom_stsd_t, list ) );
765 static void isom_remove_mp4s_description( isom_sample_entry_t *description )
767 isom_remove_box_in_predefined_list( description, offsetof( isom_stsd_t, list ) );
770 void isom_remove_sample_description( isom_sample_entry_t *sample )
772 if( !sample )
773 return;
774 lsmash_codec_type_t sample_type = sample->type;
775 if( lsmash_check_box_type_identical( sample_type, LSMASH_CODEC_TYPE_RAW ) )
777 if( sample->manager & LSMASH_VIDEO_DESCRIPTION )
779 isom_remove_visual_description( sample );
780 return;
782 else if( sample->manager & LSMASH_AUDIO_DESCRIPTION )
784 isom_remove_audio_description( sample );
785 return;
788 static struct description_remover_table_tag
790 lsmash_codec_type_t type;
791 void (*func)( isom_sample_entry_t * );
792 } description_remover_table[160] = { { LSMASH_CODEC_TYPE_INITIALIZER, NULL } };
793 if( !description_remover_table[0].func )
795 /* Initialize the table. */
796 int i = 0;
797 #define ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( type, func ) \
798 description_remover_table[i++] = (struct description_remover_table_tag){ type, func }
799 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVC1_VIDEO, isom_remove_visual_description );
800 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVC2_VIDEO, isom_remove_visual_description );
801 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVC3_VIDEO, isom_remove_visual_description );
802 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVC4_VIDEO, isom_remove_visual_description );
803 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVCP_VIDEO, isom_remove_visual_description );
804 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_HVC1_VIDEO, isom_remove_visual_description );
805 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_HEV1_VIDEO, isom_remove_visual_description );
806 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SVC1_VIDEO, isom_remove_visual_description );
807 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MVC1_VIDEO, isom_remove_visual_description );
808 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MVC2_VIDEO, isom_remove_visual_description );
809 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MP4V_VIDEO, isom_remove_visual_description );
810 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DRAC_VIDEO, isom_remove_visual_description );
811 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_ENCV_VIDEO, isom_remove_visual_description );
812 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MJP2_VIDEO, isom_remove_visual_description );
813 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_S263_VIDEO, isom_remove_visual_description );
814 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_VC_1_VIDEO, isom_remove_visual_description );
815 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_2VUY_VIDEO, isom_remove_visual_description );
816 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_CFHD_VIDEO, isom_remove_visual_description );
817 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DV10_VIDEO, isom_remove_visual_description );
818 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVOO_VIDEO, isom_remove_visual_description );
819 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVOR_VIDEO, isom_remove_visual_description );
820 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVTV_VIDEO, isom_remove_visual_description );
821 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVVT_VIDEO, isom_remove_visual_description );
822 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_HD10_VIDEO, isom_remove_visual_description );
823 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_M105_VIDEO, isom_remove_visual_description );
824 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_PNTG_VIDEO, isom_remove_visual_description );
825 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SVQ1_VIDEO, isom_remove_visual_description );
826 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SVQ3_VIDEO, isom_remove_visual_description );
827 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR0_VIDEO, isom_remove_visual_description );
828 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR1_VIDEO, isom_remove_visual_description );
829 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR2_VIDEO, isom_remove_visual_description );
830 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR3_VIDEO, isom_remove_visual_description );
831 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR4_VIDEO, isom_remove_visual_description );
832 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_WRLE_VIDEO, isom_remove_visual_description );
833 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_APCH_VIDEO, isom_remove_visual_description );
834 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_APCN_VIDEO, isom_remove_visual_description );
835 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_APCS_VIDEO, isom_remove_visual_description );
836 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_APCO_VIDEO, isom_remove_visual_description );
837 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_AP4H_VIDEO, isom_remove_visual_description );
838 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_AP4X_VIDEO, isom_remove_visual_description );
839 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_CIVD_VIDEO, isom_remove_visual_description );
840 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DRAC_VIDEO, isom_remove_visual_description );
841 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVC_VIDEO, isom_remove_visual_description );
842 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVCP_VIDEO, isom_remove_visual_description );
843 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVPP_VIDEO, isom_remove_visual_description );
844 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DV5N_VIDEO, isom_remove_visual_description );
845 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DV5P_VIDEO, isom_remove_visual_description );
846 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVH2_VIDEO, isom_remove_visual_description );
847 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVH3_VIDEO, isom_remove_visual_description );
848 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVH5_VIDEO, isom_remove_visual_description );
849 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVH6_VIDEO, isom_remove_visual_description );
850 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVHP_VIDEO, isom_remove_visual_description );
851 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVHQ_VIDEO, isom_remove_visual_description );
852 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_FLIC_VIDEO, isom_remove_visual_description );
853 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_GIF_VIDEO, isom_remove_visual_description );
854 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_H261_VIDEO, isom_remove_visual_description );
855 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_H263_VIDEO, isom_remove_visual_description );
856 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_JPEG_VIDEO, isom_remove_visual_description );
857 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_MJPA_VIDEO, isom_remove_visual_description );
858 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_MJPB_VIDEO, isom_remove_visual_description );
859 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_PNG_VIDEO, isom_remove_visual_description );
860 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_RLE_VIDEO, isom_remove_visual_description );
861 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_RPZA_VIDEO, isom_remove_visual_description );
862 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_TGA_VIDEO, isom_remove_visual_description );
863 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_TIFF_VIDEO, isom_remove_visual_description );
864 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULRA_VIDEO, isom_remove_visual_description );
865 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULRG_VIDEO, isom_remove_visual_description );
866 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULY2_VIDEO, isom_remove_visual_description );
867 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULY0_VIDEO, isom_remove_visual_description );
868 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULH2_VIDEO, isom_remove_visual_description );
869 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULH0_VIDEO, isom_remove_visual_description );
870 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_UQY2_VIDEO, isom_remove_visual_description );
871 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V210_VIDEO, isom_remove_visual_description );
872 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V216_VIDEO, isom_remove_visual_description );
873 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V308_VIDEO, isom_remove_visual_description );
874 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V408_VIDEO, isom_remove_visual_description );
875 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V410_VIDEO, isom_remove_visual_description );
876 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_YUV2_VIDEO, isom_remove_visual_description );
877 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MP4A_AUDIO, isom_remove_audio_description );
878 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AC_3_AUDIO, isom_remove_audio_description );
879 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_ALAC_AUDIO, isom_remove_audio_description );
880 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSC_AUDIO, isom_remove_audio_description );
881 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSE_AUDIO, isom_remove_audio_description );
882 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSH_AUDIO, isom_remove_audio_description );
883 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSL_AUDIO, isom_remove_audio_description );
884 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_EC_3_AUDIO, isom_remove_audio_description );
885 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SAMR_AUDIO, isom_remove_audio_description );
886 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SAWB_AUDIO, isom_remove_audio_description );
887 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_MP4A_AUDIO, isom_remove_audio_description );
888 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_23NI_AUDIO, isom_remove_audio_description );
889 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_NONE_AUDIO, isom_remove_audio_description );
890 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_LPCM_AUDIO, isom_remove_audio_description );
891 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SOWT_AUDIO, isom_remove_audio_description );
892 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_TWOS_AUDIO, isom_remove_audio_description );
893 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_FL32_AUDIO, isom_remove_audio_description );
894 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_FL64_AUDIO, isom_remove_audio_description );
895 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_IN24_AUDIO, isom_remove_audio_description );
896 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_IN32_AUDIO, isom_remove_audio_description );
897 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_NOT_SPECIFIED, isom_remove_audio_description );
898 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DRA1_AUDIO, isom_remove_audio_description );
899 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_ENCA_AUDIO, isom_remove_audio_description );
900 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_G719_AUDIO, isom_remove_audio_description );
901 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_G726_AUDIO, isom_remove_audio_description );
902 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_M4AE_AUDIO, isom_remove_audio_description );
903 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MLPA_AUDIO, isom_remove_audio_description );
904 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SAWP_AUDIO, isom_remove_audio_description );
905 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SEVC_AUDIO, isom_remove_audio_description );
906 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SQCP_AUDIO, isom_remove_audio_description );
907 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SSMV_AUDIO, isom_remove_audio_description );
908 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_TWOS_AUDIO, isom_remove_audio_description );
909 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_FDP_HINT, isom_remove_hint_description );
910 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_M2TS_HINT, isom_remove_hint_description );
911 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_PM2T_HINT, isom_remove_hint_description );
912 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_PRTP_HINT, isom_remove_hint_description );
913 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_RM2T_HINT, isom_remove_hint_description );
914 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_RRTP_HINT, isom_remove_hint_description );
915 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_RSRP_HINT, isom_remove_hint_description );
916 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_RTP_HINT , isom_remove_hint_description );
917 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SM2T_HINT, isom_remove_hint_description );
918 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SRTP_HINT, isom_remove_hint_description );
919 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_IXSE_META, isom_remove_metadata_description );
920 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_METT_META, isom_remove_metadata_description );
921 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_METX_META, isom_remove_metadata_description );
922 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MLIX_META, isom_remove_metadata_description );
923 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_OKSD_META, isom_remove_metadata_description );
924 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SVCM_META, isom_remove_metadata_description );
925 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_TEXT_META, isom_remove_metadata_description );
926 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_URIM_META, isom_remove_metadata_description );
927 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_XML_META, isom_remove_metadata_description );
928 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_TX3G_TEXT, isom_remove_tx3g_description );
929 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_TEXT_TEXT, isom_remove_qt_text_description );
930 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MP4S_SYSTEM, isom_remove_mp4s_description );
931 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( LSMASH_CODEC_TYPE_UNSPECIFIED, NULL );
933 for( int i = 0; description_remover_table[i].func; i++ )
934 if( lsmash_check_codec_type_identical( sample_type, description_remover_table[i].type ) )
936 description_remover_table[i].func( sample );
937 return;
941 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stts, stts, isom_stbl_t )
942 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_ctts, ctts, isom_stbl_t )
943 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_cslg, cslg, isom_stbl_t )
944 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stsc, stsc, isom_stbl_t )
945 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stsz, stsz, isom_stbl_t )
946 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stz2, stz2, isom_stbl_t )
947 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stss, stss, isom_stbl_t )
948 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stps, stps, isom_stbl_t )
949 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stco, stco, isom_stbl_t )
951 static void isom_remove_sdtp( isom_sdtp_t *sdtp )
953 if( !sdtp )
954 return;
955 lsmash_remove_list( sdtp->list, NULL );
956 if( sdtp->parent )
958 if( lsmash_check_box_type_identical( sdtp->parent->type, ISOM_BOX_TYPE_STBL ) )
959 REMOVE_BOX( sdtp, isom_stbl_t );
960 else if( lsmash_check_box_type_identical( sdtp->parent->type, ISOM_BOX_TYPE_TRAF ) )
961 REMOVE_BOX( sdtp, isom_traf_t );
962 else
963 assert( 0 );
964 return;
968 static void isom_remove_sgpd( isom_sgpd_t *sgpd )
970 if( !sgpd )
971 return;
972 lsmash_remove_list( sgpd->list, NULL );
973 if( sgpd->parent )
975 if( lsmash_check_box_type_identical( sgpd->parent->type, ISOM_BOX_TYPE_STBL ) )
976 REMOVE_BOX_IN_LIST( sgpd, isom_stbl_t );
977 else if( lsmash_check_box_type_identical( sgpd->parent->type, ISOM_BOX_TYPE_TRAF ) )
978 REMOVE_BOX_IN_LIST( sgpd, isom_traf_t );
979 else
980 assert( 0 );
981 return;
985 static void isom_remove_sbgp( isom_sbgp_t *sbgp )
987 if( !sbgp )
988 return;
989 lsmash_remove_list( sbgp->list, NULL );
990 if( sbgp->parent )
992 if( lsmash_check_box_type_identical( sbgp->parent->type, ISOM_BOX_TYPE_STBL ) )
993 REMOVE_BOX_IN_LIST( sbgp, isom_stbl_t );
994 else if( lsmash_check_box_type_identical( sbgp->parent->type, ISOM_BOX_TYPE_TRAF ) )
995 REMOVE_BOX_IN_LIST( sbgp, isom_traf_t );
996 else
997 assert( 0 );
998 return;
1002 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_stbl, stbl, isom_minf_t )
1004 static void isom_remove_dref_entry( isom_dref_entry_t *data_entry )
1006 if( !data_entry )
1007 return;
1008 lsmash_free( data_entry->name );
1009 lsmash_free( data_entry->location );
1010 isom_remove_box_in_predefined_list( data_entry, offsetof( isom_dref_t, list ) );
1013 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_dref, dref, isom_dinf_t )
1014 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_dinf, dinf, isom_minf_t )
1015 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_minf, minf, isom_mdia_t )
1016 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mdia, mdia, isom_trak_t )
1018 static void isom_remove_chpl_entry( isom_chpl_entry_t *data )
1020 if( !data )
1021 return;
1022 lsmash_free( data->chapter_name );
1023 lsmash_free( data );
1025 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_chpl, chpl, isom_udta_t, isom_remove_chpl_entry )
1027 static void isom_remove_keys_entry( isom_keys_entry_t *data )
1029 if( !data )
1030 return;
1031 lsmash_free( data->key_value );
1032 lsmash_free( data );
1034 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_keys, keys, isom_meta_t, isom_remove_keys_entry )
1036 static void isom_remove_mean( isom_mean_t *mean )
1038 if( !mean )
1039 return;
1040 lsmash_free( mean->meaning_string );
1041 REMOVE_BOX( mean, isom_metaitem_t );
1044 static void isom_remove_name( isom_name_t *name )
1046 if( !name )
1047 return;
1048 lsmash_free( name->name );
1049 REMOVE_BOX( name, isom_metaitem_t );
1052 static void isom_remove_data( isom_data_t *data )
1054 if( !data )
1055 return;
1056 lsmash_free( data->value );
1057 REMOVE_BOX( data, isom_metaitem_t );
1060 DEFINE_SIMPLE_BOX_IN_LIST_REMOVER( isom_remove_metaitem, metaitem, isom_ilst_t )
1061 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_ilst, ilst, isom_meta_t )
1063 static void isom_remove_meta( isom_meta_t *meta )
1065 if( !meta )
1066 return;
1067 if( meta->parent )
1069 if( lsmash_check_box_type_identical( meta->parent->type, LSMASH_BOX_TYPE_UNSPECIFIED ) )
1070 REMOVE_BOX( meta, lsmash_file_t );
1071 else if( lsmash_check_box_type_identical( meta->parent->type, ISOM_BOX_TYPE_MOOV ) )
1072 REMOVE_BOX( meta, isom_moov_t );
1073 else if( lsmash_check_box_type_identical( meta->parent->type, ISOM_BOX_TYPE_TRAK ) )
1074 REMOVE_BOX( meta, isom_trak_t );
1075 else if( lsmash_check_box_type_identical( meta->parent->type, ISOM_BOX_TYPE_UDTA ) )
1076 REMOVE_BOX( meta, isom_udta_t );
1077 else
1078 assert( 0 );
1079 return;
1083 static void isom_remove_cprt( isom_cprt_t *cprt )
1085 if( !cprt )
1086 return;
1087 lsmash_free( cprt->notice );
1088 REMOVE_BOX_IN_LIST( cprt, isom_udta_t );
1091 static void isom_remove_udta( isom_udta_t *udta )
1093 if( !udta )
1094 return;
1095 if( udta->parent )
1097 if( lsmash_check_box_type_identical( udta->parent->type, ISOM_BOX_TYPE_MOOV ) )
1098 REMOVE_BOX( udta, isom_moov_t );
1099 else if( lsmash_check_box_type_identical( udta->parent->type, ISOM_BOX_TYPE_TRAK ) )
1100 REMOVE_BOX( udta, isom_trak_t );
1101 else
1102 assert( 0 );
1103 return;
1107 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_WLOC, WLOC, isom_udta_t )
1108 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_LOOP, LOOP, isom_udta_t )
1109 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_SelO, SelO, isom_udta_t )
1110 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_AllF, AllF, isom_udta_t )
1112 static void isom_remove_ctab( isom_ctab_t *ctab )
1114 if( !ctab )
1115 return;
1116 lsmash_free( ctab->color_table.array );
1117 if( ctab->parent && lsmash_check_box_type_identical( ctab->parent->type, ISOM_BOX_TYPE_MOOV ) )
1118 REMOVE_BOX( ctab, isom_moov_t );
1121 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mvex, mvex, isom_moov_t )
1122 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mvhd, mvhd, isom_moov_t )
1123 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mehd, mehd, isom_mvex_t )
1124 DEFINE_SIMPLE_BOX_IN_LIST_REMOVER( isom_remove_trex, trex, isom_mvex_t )
1125 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_moov, moov, lsmash_file_t )
1126 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mdat, mdat, lsmash_file_t )
1127 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mfhd, mfhd, isom_moof_t )
1128 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_tfhd, tfhd, isom_traf_t )
1129 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_tfdt, tfdt, isom_traf_t )
1131 static void isom_remove_trun( isom_trun_t *trun )
1133 if( !trun )
1134 return;
1135 lsmash_remove_list( trun->optional, NULL );
1136 REMOVE_BOX_IN_LIST( trun, isom_traf_t );
1139 DEFINE_SIMPLE_BOX_IN_LIST_REMOVER( isom_remove_traf, traf, isom_moof_t )
1140 DEFINE_SIMPLE_BOX_IN_LIST_REMOVER( isom_remove_moof, moof, lsmash_file_t )
1142 static void isom_remove_free( isom_free_t *skip )
1144 if( !skip )
1145 return;
1146 lsmash_free( skip->data );
1147 isom_remove_predefined_box( skip, offsetof( lsmash_file_t, free ) );
1149 #define isom_remove_skip isom_remove_free
1151 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mfra, mfra, lsmash_file_t )
1152 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mfro, mfro, isom_mfra_t )
1153 DEFINE_SIMPLE_LIST_BOX_IN_LIST_REMOVER( isom_remove_tfra, tfra, isom_mfra_t )
1154 DEFINE_SIMPLE_LIST_BOX_IN_LIST_REMOVER( isom_remove_sidx, sidx, lsmash_file_t )
1156 static void isom_remove_styp( isom_styp_t *styp )
1158 if( !styp )
1159 return;
1160 lsmash_free( styp->compatible_brands );
1161 REMOVE_BOX_IN_LIST( styp, lsmash_file_t );
1164 /* box size updater */
1165 uint64_t isom_update_box_size( void *opaque_box )
1167 assert( opaque_box );
1168 isom_box_t *box = (isom_box_t *)opaque_box;
1169 if( box->manager & LSMASH_WRITTEN_BOX )
1170 /* No need to calculate the size of this box since the size is already decided and fixed. */
1171 return box->size;
1172 uint64_t size = 0;
1173 if( box->write )
1175 /* Calculate the size of this box excluding its children with a fake bytestream writer. */
1177 lsmash_bs_t fake_bs = { NULL };
1178 if( box->write( &fake_bs, box ) == 0 )
1179 size = lsmash_bs_get_valid_data_size( &fake_bs );
1181 /* Calculate the size of the children if no error. */
1182 if( size >= ISOM_BASEBOX_COMMON_SIZE )
1184 for( lsmash_entry_t *entry = box->extensions.head; entry; entry = entry->next )
1185 if( entry->data )
1186 size += isom_update_box_size( entry->data );
1187 /* Check large size. */
1188 if( size > UINT32_MAX )
1189 size += 8;
1191 else
1192 /* TODO: add error handling. */
1193 size = 0;
1195 box->size = size;
1196 return size;
1199 /* box adding functions */
1200 #define ATTACH_EXACTLY_ONE_BOX_TO_PARENT( box_name, parent_type ) \
1201 do \
1203 isom_box_t **p = (isom_box_t **)(((int8_t *)box_name->parent) \
1204 + offsetof( parent_type, box_name )); \
1205 if( *p == NULL ) \
1206 *p = (isom_box_t *)box_name; \
1207 } while( 0 )
1209 #define INIT_BOX_COMMON0( box_name, parent, box_type, precedence ) \
1210 const isom_extension_destructor_t isom_remove_##box_name = NULL; \
1211 isom_init_box_common( box_name, parent, box_type, precedence, isom_remove_##box_name )
1212 #define INIT_BOX_COMMON1( box_name, parent, box_type, precedence ) \
1213 isom_init_box_common( box_name, parent, box_type, precedence, isom_remove_##box_name )
1215 #define CREATE_BOX( box_name, parent, box_type, precedence, has_destructor ) \
1216 if( !(parent) ) \
1217 return NULL; \
1218 isom_##box_name##_t *box_name = lsmash_malloc_zero( sizeof(isom_##box_name##_t) ); \
1219 if( !box_name ) \
1220 return NULL; \
1221 INIT_BOX_COMMON ## has_destructor( box_name, parent, box_type, precedence ); \
1222 if( isom_add_box_to_extension_list( parent, box_name ) < 0 ) \
1224 lsmash_free( box_name ); \
1225 return NULL; \
1227 #define CREATE_LIST_BOX( box_name, parent, box_type, precedence, has_destructor ) \
1228 CREATE_BOX( box_name, parent, box_type, precedence, has_destructor ); \
1229 box_name->list = lsmash_create_entry_list(); \
1230 if( !box_name->list ) \
1232 lsmash_remove_entry_tail( &(parent)->extensions, isom_remove_##box_name ); \
1233 return NULL; \
1236 #define ADD_BOX_TEMPLATE( box_name, parent, box_type, precedence, BOX_CREATOR ) \
1237 BOX_CREATOR( box_name, parent, box_type, precedence, 1 ); \
1238 if( !(parent)->box_name ) \
1239 (parent)->box_name = box_name
1240 #define ADD_BOX_IN_LIST_TEMPLATE( box_name, parent, box_type, precedence, BOX_CREATOR ) \
1241 BOX_CREATOR( box_name, parent, box_type, precedence, 1 ); \
1242 if( lsmash_add_entry( &(parent)->box_name##_list, box_name ) < 0 ) \
1244 lsmash_remove_entry_tail( &(parent)->extensions, isom_remove_##box_name ); \
1245 return NULL; \
1248 #define ADD_BOX( box_name, parent, box_type, precedence ) \
1249 ADD_BOX_TEMPLATE( box_name, parent, box_type, precedence, CREATE_BOX )
1250 #define ADD_BOX_IN_LIST( box_name, parent, box_type, precedence ) \
1251 ADD_BOX_IN_LIST_TEMPLATE( box_name, parent, box_type, precedence, CREATE_BOX )
1252 #define ADD_LIST_BOX( box_name, parent, box_type, precedence ) \
1253 ADD_BOX_TEMPLATE( box_name, parent, box_type, precedence, CREATE_LIST_BOX )
1254 #define ADD_LIST_BOX_IN_LIST( box_name, parent, box_type, precedence ) \
1255 ADD_BOX_IN_LIST_TEMPLATE( box_name, parent, box_type, precedence, CREATE_LIST_BOX )
1257 #define DEFINE_SIMPLE_BOX_ADDER_TEMPLATE( ... ) CALL_FUNC_DEFAULT_ARGS( DEFINE_SIMPLE_BOX_ADDER_TEMPLATE, __VA_ARGS__ )
1258 #define DEFINE_SIMPLE_BOX_ADDER_TEMPLATE_6( ADDER, box_name, parent_name, box_type, precedence, parent_type ) \
1259 isom_##box_name##_t *isom_add_##box_name( parent_type *parent_name ) \
1261 ADDER( box_name, parent_name, box_type, precedence ); \
1262 return box_name; \
1264 #define DEFINE_SIMPLE_BOX_ADDER_TEMPLATE_5( ADDER, box_name, parent_name, box_type, precedence ) \
1265 DEFINE_SIMPLE_BOX_ADDER_TEMPLATE_6( ADDER, box_name, parent_name, box_type, precedence, isom_##parent_name##_t )
1267 #define DEFINE_SIMPLE_BOX_ADDER( func_name, ... ) \
1268 DEFINE_SIMPLE_BOX_ADDER_TEMPLATE( ADD_BOX, __VA_ARGS__ )
1269 #define DEFINE_SIMPLE_BOX_IN_LIST_ADDER( func_name, ... ) \
1270 DEFINE_SIMPLE_BOX_ADDER_TEMPLATE( ADD_BOX_IN_LIST, __VA_ARGS__ )
1271 #define DEFINE_SIMPLE_LIST_BOX_ADDER( func_name, ... ) \
1272 DEFINE_SIMPLE_BOX_ADDER_TEMPLATE( ADD_LIST_BOX, __VA_ARGS__ )
1274 #define DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( func_name, box_name, parent_name, box_type, precedence, has_destructor, parent_type ) \
1275 isom_##box_name##_t *isom_add_##box_name( parent_type *parent_name ) \
1277 CREATE_BOX( box_name, parent_name, box_type, precedence, has_destructor ); \
1278 return box_name; \
1281 lsmash_file_t *isom_add_file( lsmash_root_t *root )
1283 lsmash_file_t *file = lsmash_malloc_zero( sizeof(lsmash_file_t) );
1284 if( !file )
1285 return NULL;
1286 file->class = &lsmash_box_class;
1287 file->root = root;
1288 file->file = file;
1289 file->parent = (isom_box_t *)root;
1290 file->destruct = (isom_extension_destructor_t)isom_remove_file;
1291 file->size = 0;
1292 file->type = LSMASH_BOX_TYPE_UNSPECIFIED;
1293 if( isom_add_box_to_extension_list( root, file ) < 0 )
1295 lsmash_free( file );
1296 return NULL;
1298 if( lsmash_add_entry( &root->file_list, file ) < 0 )
1300 lsmash_remove_entry_tail( &root->extensions, isom_remove_file );
1301 return NULL;
1303 return file;
1306 isom_tref_type_t *isom_add_track_reference_type( isom_tref_t *tref, isom_track_reference_type type )
1308 if( !tref )
1309 return NULL;
1310 isom_tref_type_t *ref = lsmash_malloc_zero( sizeof(isom_tref_type_t) );
1311 if( !ref )
1312 return NULL;
1313 /* Initialize common fields. */
1314 ref->root = tref->root;
1315 ref->file = tref->file;
1316 ref->parent = (isom_box_t *)tref;
1317 ref->size = 0;
1318 ref->type = lsmash_form_iso_box_type( type );
1319 ref->precedence = LSMASH_BOX_PRECEDENCE_ISOM_TREF_TYPE;
1320 ref->destruct = (isom_extension_destructor_t)isom_remove_track_reference_type;
1321 isom_set_box_writer( (isom_box_t *)ref );
1322 if( isom_add_box_to_extension_list( tref, ref ) < 0 )
1324 lsmash_free( ref );
1325 return NULL;
1327 if( lsmash_add_entry( &tref->ref_list, ref ) < 0 )
1329 lsmash_remove_entry_tail( &tref->extensions, isom_remove_track_reference_type );
1330 return NULL;
1332 return ref;
1335 DEFINE_SIMPLE_BOX_ADDER( isom_add_terminator, terminator, wave, QT_BOX_TYPE_TERMINATOR, LSMASH_BOX_PRECEDENCE_QTFF_TERMINATOR )
1336 DEFINE_SIMPLE_BOX_ADDER( isom_add_frma, frma, wave, QT_BOX_TYPE_FRMA, LSMASH_BOX_PRECEDENCE_QTFF_FRMA )
1337 DEFINE_SIMPLE_BOX_ADDER( isom_add_enda, enda, wave, QT_BOX_TYPE_ENDA, LSMASH_BOX_PRECEDENCE_QTFF_ENDA )
1338 DEFINE_SIMPLE_BOX_ADDER( isom_add_mp4a, mp4a, wave, QT_BOX_TYPE_MP4A, LSMASH_BOX_PRECEDENCE_QTFF_MP4A )
1339 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_ftab, ftab, tx3g, ISOM_BOX_TYPE_FTAB, LSMASH_BOX_PRECEDENCE_ISOM_FTAB, isom_tx3g_entry_t )
1340 DEFINE_SIMPLE_BOX_ADDER( isom_add_ftyp, ftyp, file, ISOM_BOX_TYPE_FTYP, LSMASH_BOX_PRECEDENCE_ISOM_FTYP, lsmash_file_t )
1341 DEFINE_SIMPLE_BOX_ADDER( isom_add_moov, moov, file, ISOM_BOX_TYPE_MOOV, LSMASH_BOX_PRECEDENCE_ISOM_MOOV, lsmash_file_t )
1342 DEFINE_SIMPLE_BOX_ADDER( isom_add_mvhd, mvhd, moov, ISOM_BOX_TYPE_MVHD, LSMASH_BOX_PRECEDENCE_ISOM_MVHD )
1343 DEFINE_SIMPLE_BOX_ADDER( isom_add_iods, iods, moov, ISOM_BOX_TYPE_IODS, LSMASH_BOX_PRECEDENCE_ISOM_IODS )
1345 isom_ctab_t *isom_add_ctab( void *parent_box )
1347 /* According to QuickTime File Format Specification, this box is placed inside Movie Box if present.
1348 * However, sometimes this box occurs inside an image description entry or the end of Sample Description Box. */
1349 if( !parent_box )
1350 return NULL;
1351 isom_box_t *parent = (isom_box_t *)parent_box;
1352 CREATE_BOX( ctab, parent, QT_BOX_TYPE_CTAB, LSMASH_BOX_PRECEDENCE_QTFF_CTAB, 1 );
1353 if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_MOOV ) )
1354 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( ctab, isom_moov_t );
1355 return ctab;
1358 isom_trak_t *isom_add_trak( isom_moov_t *moov )
1360 if( !moov || !moov->file )
1361 return NULL;
1362 CREATE_BOX( trak, moov, ISOM_BOX_TYPE_TRAK, LSMASH_BOX_PRECEDENCE_ISOM_TRAK, 1 );
1363 isom_fragment_t *fragment = NULL;
1364 isom_cache_t *cache = lsmash_malloc_zero( sizeof(isom_cache_t) );
1365 if( !cache )
1366 goto fail;
1367 if( moov->file->fragment )
1369 fragment = lsmash_malloc_zero( sizeof(isom_fragment_t) );
1370 if( !fragment )
1371 goto fail;
1372 cache->fragment = fragment;
1374 if( lsmash_add_entry( &moov->trak_list, trak ) < 0 )
1375 goto fail;
1376 trak->cache = cache;
1377 return trak;
1378 fail:
1379 lsmash_free( fragment );
1380 lsmash_free( cache );
1381 lsmash_remove_entry_tail( &moov->extensions, isom_remove_trak );
1382 return NULL;
1385 DEFINE_SIMPLE_BOX_ADDER ( isom_add_tkhd, tkhd, trak, ISOM_BOX_TYPE_TKHD, LSMASH_BOX_PRECEDENCE_ISOM_TKHD )
1386 DEFINE_SIMPLE_BOX_ADDER ( isom_add_tapt, tapt, trak, QT_BOX_TYPE_TAPT, LSMASH_BOX_PRECEDENCE_QTFF_TAPT )
1387 DEFINE_SIMPLE_BOX_ADDER ( isom_add_clef, clef, tapt, QT_BOX_TYPE_CLEF, LSMASH_BOX_PRECEDENCE_QTFF_CLEF )
1388 DEFINE_SIMPLE_BOX_ADDER ( isom_add_prof, prof, tapt, QT_BOX_TYPE_PROF, LSMASH_BOX_PRECEDENCE_QTFF_PROF )
1389 DEFINE_SIMPLE_BOX_ADDER ( isom_add_enof, enof, tapt, QT_BOX_TYPE_ENOF, LSMASH_BOX_PRECEDENCE_QTFF_ENOF )
1390 DEFINE_SIMPLE_BOX_ADDER ( isom_add_edts, edts, trak, ISOM_BOX_TYPE_EDTS, LSMASH_BOX_PRECEDENCE_ISOM_EDTS )
1391 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_elst, elst, edts, ISOM_BOX_TYPE_ELST, LSMASH_BOX_PRECEDENCE_ISOM_ELST )
1392 DEFINE_SIMPLE_BOX_ADDER ( isom_add_tref, tref, trak, ISOM_BOX_TYPE_TREF, LSMASH_BOX_PRECEDENCE_ISOM_TREF )
1393 DEFINE_SIMPLE_BOX_ADDER ( isom_add_mdia, mdia, trak, ISOM_BOX_TYPE_MDIA, LSMASH_BOX_PRECEDENCE_ISOM_MDIA )
1394 DEFINE_SIMPLE_BOX_ADDER ( isom_add_mdhd, mdhd, mdia, ISOM_BOX_TYPE_MDHD, LSMASH_BOX_PRECEDENCE_ISOM_MDHD )
1396 isom_hdlr_t *isom_add_hdlr( void *parent_box )
1398 if( !parent_box )
1399 return NULL;
1400 isom_box_t *parent = (isom_box_t *)parent_box;
1401 CREATE_BOX( hdlr, parent, ISOM_BOX_TYPE_HDLR, LSMASH_BOX_PRECEDENCE_ISOM_HDLR, 1 );
1402 if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_MDIA ) )
1403 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( hdlr, isom_mdia_t );
1404 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_META )
1405 || lsmash_check_box_type_identical( parent->type, QT_BOX_TYPE_META ) )
1406 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( hdlr, isom_meta_t );
1407 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_MINF ) )
1408 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( hdlr, isom_minf_t );
1409 else
1410 assert( 0 );
1411 return hdlr;
1414 DEFINE_SIMPLE_BOX_ADDER( isom_add_minf, minf, mdia, ISOM_BOX_TYPE_MINF, LSMASH_BOX_PRECEDENCE_ISOM_MINF )
1415 DEFINE_SIMPLE_BOX_ADDER( isom_add_vmhd, vmhd, minf, ISOM_BOX_TYPE_VMHD, LSMASH_BOX_PRECEDENCE_ISOM_VMHD )
1416 DEFINE_SIMPLE_BOX_ADDER( isom_add_smhd, smhd, minf, ISOM_BOX_TYPE_SMHD, LSMASH_BOX_PRECEDENCE_ISOM_SMHD )
1417 DEFINE_SIMPLE_BOX_ADDER( isom_add_hmhd, hmhd, minf, ISOM_BOX_TYPE_HMHD, LSMASH_BOX_PRECEDENCE_ISOM_HMHD )
1418 DEFINE_SIMPLE_BOX_ADDER( isom_add_nmhd, nmhd, minf, ISOM_BOX_TYPE_NMHD, LSMASH_BOX_PRECEDENCE_ISOM_NMHD )
1419 DEFINE_SIMPLE_BOX_ADDER( isom_add_gmhd, gmhd, minf, QT_BOX_TYPE_GMHD, LSMASH_BOX_PRECEDENCE_QTFF_GMHD )
1420 DEFINE_SIMPLE_BOX_ADDER( isom_add_gmin, gmin, gmhd, QT_BOX_TYPE_GMIN, LSMASH_BOX_PRECEDENCE_QTFF_GMIN )
1421 DEFINE_SIMPLE_BOX_ADDER( isom_add_text, text, gmhd, QT_BOX_TYPE_TEXT, LSMASH_BOX_PRECEDENCE_QTFF_TEXT )
1423 isom_dinf_t *isom_add_dinf( void *parent_box )
1425 if( !parent_box )
1426 return NULL;
1427 isom_box_t *parent = (isom_box_t *)parent_box;
1428 CREATE_BOX( dinf, parent, ISOM_BOX_TYPE_DINF, LSMASH_BOX_PRECEDENCE_ISOM_DINF, 1 );
1429 if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_MINF ) )
1430 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( dinf, isom_minf_t );
1431 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_META )
1432 || lsmash_check_box_type_identical( parent->type, QT_BOX_TYPE_META ) )
1433 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( dinf, isom_meta_t );
1434 else
1435 assert( 0 );
1436 return dinf;
1439 isom_dref_entry_t *isom_add_dref_entry( isom_dref_t *dref, lsmash_box_type_t type )
1441 if( !dref )
1442 return NULL;
1443 isom_dref_entry_t *data = lsmash_malloc_zero( sizeof(isom_dref_entry_t) );
1444 if( !data )
1445 return NULL;
1446 isom_init_box_common( data, dref, type, LSMASH_BOX_PRECEDENCE_ISOM_DREF_ENTRY, isom_remove_dref_entry );
1447 if( isom_add_box_to_extension_list( dref, data ) < 0 )
1449 lsmash_free( data );
1450 return NULL;
1452 if( lsmash_add_entry( &dref->list, data ) < 0 )
1454 lsmash_remove_entry_tail( &dref->extensions, isom_remove_dref_entry );
1455 return NULL;
1457 return data;
1460 DEFINE_SIMPLE_BOX_ADDER( isom_add_dref, dref, dinf, ISOM_BOX_TYPE_DREF, LSMASH_BOX_PRECEDENCE_ISOM_DREF )
1461 DEFINE_SIMPLE_BOX_ADDER( isom_add_stbl, stbl, minf, ISOM_BOX_TYPE_STBL, LSMASH_BOX_PRECEDENCE_ISOM_STBL )
1462 DEFINE_SIMPLE_BOX_ADDER( isom_add_stsd, stsd, stbl, ISOM_BOX_TYPE_STSD, LSMASH_BOX_PRECEDENCE_ISOM_STSD )
1464 static int isom_add_sample_description_entry
1466 isom_stsd_t *stsd,
1467 void *description,
1468 void (*destructor)( isom_sample_entry_t * )
1471 if( isom_add_box_to_extension_list( stsd, description ) < 0 )
1473 lsmash_free( description );
1474 return LSMASH_ERR_MEMORY_ALLOC;
1476 if( lsmash_add_entry( &stsd->list, description ) < 0 )
1478 lsmash_remove_entry_tail( &stsd->extensions, destructor );
1479 return LSMASH_ERR_MEMORY_ALLOC;
1481 return 0;
1484 isom_visual_entry_t *isom_add_visual_description( isom_stsd_t *stsd, lsmash_codec_type_t sample_type )
1486 assert( stsd );
1487 isom_visual_entry_t *visual = lsmash_malloc_zero( sizeof(isom_visual_entry_t) );
1488 if( !visual )
1489 return NULL;
1490 isom_init_box_common( visual, stsd, sample_type, LSMASH_BOX_PRECEDENCE_HM, isom_remove_visual_description );
1491 visual->manager |= LSMASH_VIDEO_DESCRIPTION;
1492 return isom_add_sample_description_entry( stsd, visual, isom_remove_visual_description ) ? NULL : visual;
1495 isom_audio_entry_t *isom_add_audio_description( isom_stsd_t *stsd, lsmash_codec_type_t sample_type )
1497 assert( stsd );
1498 isom_audio_entry_t *audio = lsmash_malloc_zero( sizeof(isom_audio_entry_t) );
1499 if( !audio )
1500 return NULL;
1501 isom_init_box_common( audio, stsd, sample_type, LSMASH_BOX_PRECEDENCE_HM, isom_remove_audio_description );
1502 audio->manager |= LSMASH_AUDIO_DESCRIPTION;
1503 return isom_add_sample_description_entry( stsd, audio, isom_remove_audio_description ) ? NULL : audio;
1506 isom_qt_text_entry_t *isom_add_qt_text_description( isom_stsd_t *stsd )
1508 assert( stsd );
1509 isom_qt_text_entry_t *text = lsmash_malloc_zero( sizeof(isom_qt_text_entry_t) );
1510 if( !text )
1511 return NULL;
1512 isom_init_box_common( text, stsd, QT_CODEC_TYPE_TEXT_TEXT, LSMASH_BOX_PRECEDENCE_HM, isom_remove_qt_text_description );
1513 return isom_add_sample_description_entry( stsd, text, isom_remove_qt_text_description ) ? NULL : text;
1516 isom_tx3g_entry_t *isom_add_tx3g_description( isom_stsd_t *stsd )
1518 assert( stsd );
1519 isom_tx3g_entry_t *tx3g = lsmash_malloc_zero( sizeof(isom_tx3g_entry_t) );
1520 if( !tx3g )
1521 return NULL;
1522 isom_init_box_common( tx3g, stsd, ISOM_CODEC_TYPE_TX3G_TEXT, LSMASH_BOX_PRECEDENCE_HM, isom_remove_tx3g_description );
1523 return isom_add_sample_description_entry( stsd, tx3g, isom_remove_tx3g_description ) ? NULL : tx3g;
1526 isom_esds_t *isom_add_esds( void *parent_box )
1528 isom_box_t *parent = (isom_box_t *)parent_box;
1529 int is_qt = lsmash_check_box_type_identical( parent->type, QT_BOX_TYPE_WAVE );
1530 lsmash_box_type_t box_type = is_qt ? QT_BOX_TYPE_ESDS : ISOM_BOX_TYPE_ESDS;
1531 uint64_t precedence = is_qt ? LSMASH_BOX_PRECEDENCE_QTFF_ESDS : LSMASH_BOX_PRECEDENCE_ISOM_ESDS;
1532 CREATE_BOX( esds, parent, box_type, precedence, 1 );
1533 return esds;
1536 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_glbl, glbl, parent_box, QT_BOX_TYPE_GLBL, LSMASH_BOX_PRECEDENCE_QTFF_GLBL, 1, void )
1537 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_clap, clap, visual, ISOM_BOX_TYPE_CLAP, LSMASH_BOX_PRECEDENCE_ISOM_CLAP, 0, isom_visual_entry_t )
1538 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_pasp, pasp, visual, ISOM_BOX_TYPE_PASP, LSMASH_BOX_PRECEDENCE_ISOM_PASP, 0, isom_visual_entry_t )
1539 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_colr, colr, visual, ISOM_BOX_TYPE_COLR, LSMASH_BOX_PRECEDENCE_ISOM_COLR, 0, isom_visual_entry_t )
1540 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_gama, gama, visual, QT_BOX_TYPE_GAMA, LSMASH_BOX_PRECEDENCE_QTFF_GAMA, 0, isom_visual_entry_t )
1541 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_fiel, fiel, visual, QT_BOX_TYPE_FIEL, LSMASH_BOX_PRECEDENCE_QTFF_FIEL, 0, isom_visual_entry_t )
1542 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_cspc, cspc, visual, QT_BOX_TYPE_CSPC, LSMASH_BOX_PRECEDENCE_QTFF_CSPC, 0, isom_visual_entry_t )
1543 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_sgbt, sgbt, visual, QT_BOX_TYPE_SGBT, LSMASH_BOX_PRECEDENCE_QTFF_SGBT, 0, isom_visual_entry_t )
1544 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_stsl, stsl, visual, ISOM_BOX_TYPE_STSL, LSMASH_BOX_PRECEDENCE_ISOM_STSL, 0, isom_visual_entry_t )
1545 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_btrt, btrt, visual, ISOM_BOX_TYPE_BTRT, LSMASH_BOX_PRECEDENCE_ISOM_BTRT, 0, isom_visual_entry_t )
1546 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_wave, wave, audio, QT_BOX_TYPE_WAVE, LSMASH_BOX_PRECEDENCE_QTFF_WAVE, 0, isom_audio_entry_t )
1547 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_chan, chan, audio, QT_BOX_TYPE_CHAN, LSMASH_BOX_PRECEDENCE_QTFF_CHAN, 1, isom_audio_entry_t )
1548 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_srat, srat, audio, ISOM_BOX_TYPE_SRAT, LSMASH_BOX_PRECEDENCE_ISOM_SRAT, 0, isom_audio_entry_t )
1550 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_stts, stts, stbl, ISOM_BOX_TYPE_STTS, LSMASH_BOX_PRECEDENCE_ISOM_STTS )
1551 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_ctts, ctts, stbl, ISOM_BOX_TYPE_CTTS, LSMASH_BOX_PRECEDENCE_ISOM_CTTS )
1552 DEFINE_SIMPLE_BOX_ADDER ( isom_add_cslg, cslg, stbl, ISOM_BOX_TYPE_CSLG, LSMASH_BOX_PRECEDENCE_ISOM_CSLG )
1553 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_stsc, stsc, stbl, ISOM_BOX_TYPE_STSC, LSMASH_BOX_PRECEDENCE_ISOM_STSC )
1554 DEFINE_SIMPLE_BOX_ADDER ( isom_add_stsz, stsz, stbl, ISOM_BOX_TYPE_STSZ, LSMASH_BOX_PRECEDENCE_ISOM_STSZ ) /* We don't create a list here. */
1555 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_stz2, stz2, stbl, ISOM_BOX_TYPE_STZ2, LSMASH_BOX_PRECEDENCE_ISOM_STZ2 )
1556 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_stss, stss, stbl, ISOM_BOX_TYPE_STSS, LSMASH_BOX_PRECEDENCE_ISOM_STSS )
1557 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_stps, stps, stbl, QT_BOX_TYPE_STPS, LSMASH_BOX_PRECEDENCE_QTFF_STPS )
1559 isom_stco_t *isom_add_stco( isom_stbl_t *stbl )
1561 ADD_LIST_BOX( stco, stbl, ISOM_BOX_TYPE_STCO, LSMASH_BOX_PRECEDENCE_ISOM_STCO );
1562 stco->large_presentation = 0;
1563 return stco;
1566 isom_stco_t *isom_add_co64( isom_stbl_t *stbl )
1568 ADD_LIST_BOX( stco, stbl, ISOM_BOX_TYPE_CO64, LSMASH_BOX_PRECEDENCE_ISOM_CO64 );
1569 stco->large_presentation = 1;
1570 return stco;
1573 isom_sdtp_t *isom_add_sdtp( isom_box_t *parent )
1575 if( !parent )
1576 return NULL;
1577 if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_STBL ) )
1579 isom_stbl_t *stbl = (isom_stbl_t *)parent;
1580 ADD_LIST_BOX( sdtp, stbl, ISOM_BOX_TYPE_SDTP, LSMASH_BOX_PRECEDENCE_ISOM_SDTP );
1581 return sdtp;
1583 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_TRAF ) )
1585 isom_traf_t *traf = (isom_traf_t *)parent;
1586 ADD_LIST_BOX( sdtp, traf, ISOM_BOX_TYPE_SDTP, LSMASH_BOX_PRECEDENCE_ISOM_SDTP );
1587 return sdtp;
1589 assert( 0 );
1590 return NULL;
1593 isom_sgpd_t *isom_add_sgpd( void *parent_box )
1595 if( !parent_box )
1596 return NULL;
1597 isom_box_t *parent = (isom_box_t *)parent_box;
1598 if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_STBL ) )
1600 isom_stbl_t *stbl = (isom_stbl_t *)parent;
1601 ADD_LIST_BOX_IN_LIST( sgpd, stbl, ISOM_BOX_TYPE_SGPD, LSMASH_BOX_PRECEDENCE_ISOM_SGPD );
1602 return sgpd;
1604 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_TRAF ) )
1606 isom_traf_t *traf = (isom_traf_t *)parent;
1607 ADD_LIST_BOX_IN_LIST( sgpd, traf, ISOM_BOX_TYPE_SGPD, LSMASH_BOX_PRECEDENCE_ISOM_SGPD );
1608 return sgpd;
1610 assert( 0 );
1611 return NULL;
1614 isom_sbgp_t *isom_add_sbgp( void *parent_box )
1616 if( !parent_box )
1617 return NULL;
1618 isom_box_t *parent = (isom_box_t *)parent_box;
1619 if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_STBL ) )
1621 isom_stbl_t *stbl = (isom_stbl_t *)parent;
1622 ADD_LIST_BOX_IN_LIST( sbgp, stbl, ISOM_BOX_TYPE_SBGP, LSMASH_BOX_PRECEDENCE_ISOM_SBGP );
1623 return sbgp;
1625 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_TRAF ) )
1627 isom_traf_t *traf = (isom_traf_t *)parent;
1628 ADD_LIST_BOX_IN_LIST( sbgp, traf, ISOM_BOX_TYPE_SBGP, LSMASH_BOX_PRECEDENCE_ISOM_SBGP );
1629 return sbgp;
1631 assert( 0 );
1632 return NULL;
1635 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_chpl, chpl, udta, ISOM_BOX_TYPE_CHPL, LSMASH_BOX_PRECEDENCE_ISOM_CHPL )
1637 isom_metaitem_t *isom_add_metaitem( isom_ilst_t *ilst, lsmash_itunes_metadata_item item )
1639 if( !ilst )
1640 return NULL;
1641 lsmash_box_type_t type = lsmash_form_iso_box_type( item );
1642 ADD_BOX_IN_LIST( metaitem, ilst, type, LSMASH_BOX_PRECEDENCE_ISOM_METAITEM );
1643 return metaitem;
1646 DEFINE_SIMPLE_BOX_ADDER ( isom_add_mean, mean, metaitem, ISOM_BOX_TYPE_MEAN, LSMASH_BOX_PRECEDENCE_ISOM_MEAN )
1647 DEFINE_SIMPLE_BOX_ADDER ( isom_add_name, name, metaitem, ISOM_BOX_TYPE_NAME, LSMASH_BOX_PRECEDENCE_ISOM_NAME )
1648 DEFINE_SIMPLE_BOX_ADDER ( isom_add_data, data, metaitem, ISOM_BOX_TYPE_DATA, LSMASH_BOX_PRECEDENCE_ISOM_DATA )
1649 DEFINE_SIMPLE_BOX_ADDER ( isom_add_ilst, ilst, meta, ISOM_BOX_TYPE_ILST, LSMASH_BOX_PRECEDENCE_ISOM_ILST )
1650 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_keys, keys, meta, QT_BOX_TYPE_KEYS, LSMASH_BOX_PRECEDENCE_QTFF_KEYS )
1652 isom_meta_t *isom_add_meta( void *parent_box )
1654 if( !parent_box )
1655 return NULL;
1656 isom_box_t *parent = (isom_box_t *)parent_box;
1657 CREATE_BOX( meta, parent, ISOM_BOX_TYPE_META, LSMASH_BOX_PRECEDENCE_ISOM_META, 1 );
1658 if( parent->file == (lsmash_file_t *)parent )
1659 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( meta, lsmash_file_t );
1660 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_MOOV ) )
1661 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( meta, isom_moov_t );
1662 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_TRAK ) )
1663 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( meta, isom_trak_t );
1664 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_UDTA ) )
1665 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( meta, isom_udta_t );
1666 else
1667 assert( 0 );
1668 return meta;
1671 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_cprt, cprt, udta, ISOM_BOX_TYPE_CPRT, LSMASH_BOX_PRECEDENCE_ISOM_CPRT )
1673 isom_udta_t *isom_add_udta( void *parent_box )
1675 if( !parent_box )
1676 return NULL;
1677 isom_box_t *parent = (isom_box_t *)parent_box;
1678 if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_MOOV ) )
1680 isom_moov_t *moov = (isom_moov_t *)parent;
1681 ADD_BOX( udta, moov, ISOM_BOX_TYPE_UDTA, LSMASH_BOX_PRECEDENCE_ISOM_UDTA );
1682 return udta;
1684 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_TRAK ) )
1686 isom_trak_t *trak = (isom_trak_t *)parent;
1687 ADD_BOX( udta, trak, ISOM_BOX_TYPE_UDTA, LSMASH_BOX_PRECEDENCE_ISOM_UDTA );
1688 return udta;
1690 assert( 0 );
1691 return NULL;
1694 DEFINE_SIMPLE_BOX_ADDER ( isom_add_WLOC, WLOC, udta, QT_BOX_TYPE_WLOC, LSMASH_BOX_PRECEDENCE_QTFF_WLOC )
1695 DEFINE_SIMPLE_BOX_ADDER ( isom_add_LOOP, LOOP, udta, QT_BOX_TYPE_LOOP, LSMASH_BOX_PRECEDENCE_QTFF_LOOP )
1696 DEFINE_SIMPLE_BOX_ADDER ( isom_add_SelO, SelO, udta, QT_BOX_TYPE_SELO, LSMASH_BOX_PRECEDENCE_QTFF_SELO )
1697 DEFINE_SIMPLE_BOX_ADDER ( isom_add_AllF, AllF, udta, QT_BOX_TYPE_ALLF, LSMASH_BOX_PRECEDENCE_QTFF_ALLF )
1698 DEFINE_SIMPLE_BOX_ADDER ( isom_add_mvex, mvex, moov, ISOM_BOX_TYPE_MVEX, LSMASH_BOX_PRECEDENCE_ISOM_MVEX )
1699 DEFINE_SIMPLE_BOX_ADDER ( isom_add_mehd, mehd, mvex, ISOM_BOX_TYPE_MEHD, LSMASH_BOX_PRECEDENCE_ISOM_MEHD )
1700 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_trex, trex, mvex, ISOM_BOX_TYPE_TREX, LSMASH_BOX_PRECEDENCE_ISOM_TREX )
1701 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_moof, moof, file, ISOM_BOX_TYPE_MOOF, LSMASH_BOX_PRECEDENCE_ISOM_MOOF, lsmash_file_t )
1702 DEFINE_SIMPLE_BOX_ADDER ( isom_add_mfhd, mfhd, moof, ISOM_BOX_TYPE_MFHD, LSMASH_BOX_PRECEDENCE_ISOM_MFHD )
1703 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_traf, traf, moof, ISOM_BOX_TYPE_TRAF, LSMASH_BOX_PRECEDENCE_ISOM_TRAF )
1704 DEFINE_SIMPLE_BOX_ADDER ( isom_add_tfhd, tfhd, traf, ISOM_BOX_TYPE_TFHD, LSMASH_BOX_PRECEDENCE_ISOM_TFHD )
1705 DEFINE_SIMPLE_BOX_ADDER ( isom_add_tfdt, tfdt, traf, ISOM_BOX_TYPE_TFDT, LSMASH_BOX_PRECEDENCE_ISOM_TFDT )
1706 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_trun, trun, traf, ISOM_BOX_TYPE_TRUN, LSMASH_BOX_PRECEDENCE_ISOM_TRUN )
1707 DEFINE_SIMPLE_BOX_ADDER ( isom_add_mfra, mfra, file, ISOM_BOX_TYPE_MFRA, LSMASH_BOX_PRECEDENCE_ISOM_MFRA, lsmash_file_t )
1708 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_tfra, tfra, mfra, ISOM_BOX_TYPE_TFRA, LSMASH_BOX_PRECEDENCE_ISOM_TFRA )
1709 DEFINE_SIMPLE_BOX_ADDER ( isom_add_mfro, mfro, mfra, ISOM_BOX_TYPE_MFRO, LSMASH_BOX_PRECEDENCE_ISOM_MFRO )
1711 isom_mdat_t *isom_add_mdat( lsmash_file_t *file )
1713 assert( !file->mdat );
1714 CREATE_BOX( mdat, file, ISOM_BOX_TYPE_MDAT, LSMASH_BOX_PRECEDENCE_ISOM_MDAT, 1 );
1715 file->mdat = mdat;
1716 return mdat;
1719 isom_free_t *isom_add_free( void *parent_box )
1721 if( !parent_box )
1722 return NULL;
1723 isom_box_t *parent = (isom_box_t *)parent_box;
1724 if( parent->file == (lsmash_file_t *)parent )
1726 lsmash_file_t *file = (lsmash_file_t *)parent;
1727 CREATE_BOX( skip, file, ISOM_BOX_TYPE_FREE, LSMASH_BOX_PRECEDENCE_ISOM_FREE, 1 );
1728 if( !file->free )
1729 file->free = skip;
1730 return skip;
1732 CREATE_BOX( skip, parent, ISOM_BOX_TYPE_FREE, LSMASH_BOX_PRECEDENCE_ISOM_FREE, 1 );
1733 return skip;
1736 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_styp, styp, file, ISOM_BOX_TYPE_STYP, LSMASH_BOX_PRECEDENCE_ISOM_STYP, lsmash_file_t )
1738 isom_sidx_t *isom_add_sidx( lsmash_file_t *file )
1740 ADD_LIST_BOX_IN_LIST( sidx, file, ISOM_BOX_TYPE_SIDX, LSMASH_BOX_PRECEDENCE_ISOM_SIDX );
1741 return sidx;
1744 #undef ATTACH_EXACTLY_ONE_BOX_TO_PARENT
1745 #undef CREATE_BOX
1746 #undef CREATE_LIST_BOX
1747 #undef ADD_BOX_TEMPLATE
1748 #undef ADD_BOX_IN_LIST_TEMPLATE
1749 #undef ADD_BOX
1750 #undef ADD_BOX_IN_LIST
1751 #undef ADD_LIST_BOX
1752 #undef ADD_LIST_BOX_IN_LIST
1753 #undef DEFINE_SIMPLE_BOX_ADDER_TEMPLATE
1754 #undef DEFINE_SIMPLE_BOX_ADDER_TEMPLATE_6
1755 #undef DEFINE_SIMPLE_BOX_ADDER_TEMPLATE_5
1756 #undef DEFINE_SIMPLE_BOX_ADDER
1757 #undef DEFINE_SIMPLE_BOX_IN_LIST_ADDER
1758 #undef DEFINE_SIMPLE_LIST_BOX_ADDER
1760 static int fake_file_read
1762 void *opaque,
1763 uint8_t *buf,
1764 int size
1767 fake_file_stream_t *stream = (fake_file_stream_t *)opaque;
1768 int read_size;
1769 if( stream->pos + size > stream->size )
1770 read_size = stream->size - stream->pos;
1771 else
1772 read_size = size;
1773 memcpy( buf, stream->data + stream->pos, read_size );
1774 stream->pos += read_size;
1775 return read_size;
1778 static int64_t fake_file_seek
1780 void *opaque,
1781 int64_t offset,
1782 int whence
1785 fake_file_stream_t *stream = (fake_file_stream_t *)opaque;
1786 if( whence == SEEK_SET )
1787 stream->pos = offset;
1788 else if( whence == SEEK_CUR )
1789 stream->pos += offset;
1790 else if( whence == SEEK_END )
1791 stream->pos = stream->size + offset;
1792 return stream->pos;
1795 /* Public functions */
1796 lsmash_root_t *lsmash_create_root( void )
1798 lsmash_root_t *root = lsmash_malloc_zero( sizeof(lsmash_root_t) );
1799 if( !root )
1800 return NULL;
1801 root->root = root;
1802 return root;
1805 void lsmash_destroy_root( lsmash_root_t *root )
1807 isom_remove_box_by_itself( root );
1810 lsmash_extended_box_type_t lsmash_form_extended_box_type( uint32_t fourcc, const uint8_t id[12] )
1812 return (lsmash_extended_box_type_t){ fourcc, { id[0], id[1], id[2], id[3], id[4], id[5],
1813 id[6], id[7], id[8], id[9], id[10], id[11] } };
1816 lsmash_box_type_t lsmash_form_box_type
1818 lsmash_compact_box_type_t type,
1819 lsmash_extended_box_type_t user
1822 return (lsmash_box_type_t){ type, user };
1825 lsmash_box_type_t lsmash_form_iso_box_type( uint32_t fourcc )
1827 return (lsmash_box_type_t){ fourcc, lsmash_form_extended_box_type( fourcc, LSMASH_ISO_12_BYTES ) };
1830 lsmash_box_type_t lsmash_form_qtff_box_type( uint32_t fourcc )
1832 return (lsmash_box_type_t){ fourcc, lsmash_form_extended_box_type( fourcc, LSMASH_QTFF_12_BYTES ) };
1835 #define CHECK_BOX_TYPE_IDENTICAL( a, b ) \
1836 a.fourcc == b.fourcc \
1837 && a.user.fourcc == b.user.fourcc \
1838 && a.user.id[0] == b.user.id[0] \
1839 && a.user.id[1] == b.user.id[1] \
1840 && a.user.id[2] == b.user.id[2] \
1841 && a.user.id[3] == b.user.id[3] \
1842 && a.user.id[4] == b.user.id[4] \
1843 && a.user.id[5] == b.user.id[5] \
1844 && a.user.id[6] == b.user.id[6] \
1845 && a.user.id[7] == b.user.id[7] \
1846 && a.user.id[8] == b.user.id[8] \
1847 && a.user.id[9] == b.user.id[9] \
1848 && a.user.id[10] == b.user.id[10] \
1849 && a.user.id[11] == b.user.id[11]
1851 int lsmash_check_box_type_identical( lsmash_box_type_t a, lsmash_box_type_t b )
1853 return CHECK_BOX_TYPE_IDENTICAL( a, b );
1856 int lsmash_check_codec_type_identical( lsmash_codec_type_t a, lsmash_codec_type_t b )
1858 return CHECK_BOX_TYPE_IDENTICAL( a, b );
1861 int lsmash_check_box_type_specified( const lsmash_box_type_t *box_type )
1863 assert( box_type );
1864 if( !box_type )
1865 return 0;
1866 return !!(box_type->fourcc
1867 | box_type->user.fourcc
1868 | box_type->user.id[0] | box_type->user.id[1] | box_type->user.id[2] | box_type->user.id[3]
1869 | box_type->user.id[4] | box_type->user.id[5] | box_type->user.id[6] | box_type->user.id[7]
1870 | box_type->user.id[8] | box_type->user.id[9] | box_type->user.id[10] | box_type->user.id[11]);
1873 lsmash_box_t *lsmash_get_box
1875 lsmash_box_t *parent,
1876 const lsmash_box_path_t box_path[]
1879 lsmash_entry_t *entry = isom_get_entry_of_box( parent, box_path );
1880 return (lsmash_box_t *)(entry ? entry->data : NULL);
1883 lsmash_box_t *lsmash_create_box
1885 lsmash_box_type_t type,
1886 uint8_t *data,
1887 uint32_t size,
1888 uint64_t precedence
1891 if( !lsmash_check_box_type_specified( &type ) )
1892 return NULL;
1893 isom_unknown_box_t *box = lsmash_malloc_zero( sizeof(isom_unknown_box_t) );
1894 if( !box )
1895 return NULL;
1896 if( size && data )
1898 box->unknown_size = size;
1899 box->unknown_field = lsmash_memdup( data, size );
1900 if( !box->unknown_field )
1902 lsmash_free( box );
1903 return NULL;
1906 else
1908 box->unknown_size = 0;
1909 box->unknown_field = NULL;
1910 size = 0;
1912 box->class = &lsmash_box_class;
1913 box->root = NULL;
1914 box->file = NULL;
1915 box->parent = NULL;
1916 box->destruct = (isom_extension_destructor_t)isom_remove_unknown_box;
1917 box->manager = LSMASH_UNKNOWN_BOX;
1918 box->precedence = precedence;
1919 box->size = ISOM_BASEBOX_COMMON_SIZE + size + (type.fourcc == ISOM_BOX_TYPE_UUID.fourcc ? 16 : 0);
1920 box->type = type;
1921 isom_set_box_writer( (isom_box_t *)box );
1922 return (lsmash_box_t *)box;
1925 int lsmash_add_box
1927 lsmash_box_t *parent,
1928 lsmash_box_t *box
1931 if( !parent )
1932 /* You cannot add any box without a box being its parent. */
1933 return LSMASH_ERR_FUNCTION_PARAM;
1934 if( !box || box->size < ISOM_BASEBOX_COMMON_SIZE )
1935 return LSMASH_ERR_FUNCTION_PARAM;
1936 if( parent->root == (lsmash_root_t *)parent )
1938 /* Only files can be added into any ROOT.
1939 * For backward compatibility, use the active file as the parent. */
1940 if( parent->file )
1941 parent = (isom_box_t *)parent->file;
1942 else
1943 return LSMASH_ERR_FUNCTION_PARAM;
1945 /* Add a box as a child box. */
1946 box->root = parent->root;
1947 box->file = parent->file;
1948 box->parent = parent;
1949 return isom_add_box_to_extension_list( parent, box );
1952 int lsmash_add_box_ex
1954 lsmash_box_t *parent,
1955 lsmash_box_t **p_box
1958 if( !parent )
1959 /* You cannot add any box without a box being its parent. */
1960 return LSMASH_ERR_FUNCTION_PARAM;
1961 isom_unknown_box_t *box = (isom_unknown_box_t *)*p_box;
1962 if( !box || box->size < ISOM_BASEBOX_COMMON_SIZE )
1963 return LSMASH_ERR_FUNCTION_PARAM;
1964 if( !(box->manager & LSMASH_UNKNOWN_BOX) )
1965 /* Simply add the box. */
1966 return lsmash_add_box( parent, *p_box );
1967 /* Check if the size of the box to be added is valid. */
1968 if( box->size != ISOM_BASEBOX_COMMON_SIZE + box->unknown_size + (box->type.fourcc == ISOM_BOX_TYPE_UUID.fourcc ? 16 : 0) )
1969 return LSMASH_ERR_FUNCTION_PARAM;
1970 if( !parent->file || parent->file == (lsmash_file_t *)box )
1971 return LSMASH_ERR_FUNCTION_PARAM;
1972 if( parent->root == (lsmash_root_t *)parent )
1973 /* Only files can be added into any ROOT.
1974 * For backward compatibility, use the active file as the parent. */
1975 parent = (isom_box_t *)parent->file;
1976 /* Switch to the fake-file stream mode. */
1977 lsmash_file_t *file = parent->file;
1978 lsmash_bs_t *bs_backup = file->bs;
1979 lsmash_bs_t *bs = lsmash_bs_create();
1980 if( !bs )
1981 return LSMASH_ERR_MEMORY_ALLOC;
1982 uint8_t *buf = lsmash_malloc( box->size );
1983 if( !buf )
1985 lsmash_bs_cleanup( bs );
1986 return LSMASH_ERR_MEMORY_ALLOC;
1988 fake_file_stream_t fake_file =
1990 .size = box->size,
1991 .data = buf,
1992 .pos = 0
1994 bs->stream = &fake_file;
1995 bs->read = fake_file_read;
1996 bs->write = NULL;
1997 bs->seek = fake_file_seek;
1998 file->bs = bs;
1999 file->fake_file_mode = 1;
2000 /* Make the byte string representing the given box. */
2001 LSMASH_SET_BE32( &buf[0], box->size );
2002 LSMASH_SET_BE32( &buf[4], box->type.fourcc );
2003 if( box->type.fourcc == ISOM_BOX_TYPE_UUID.fourcc )
2005 LSMASH_SET_BE32( &buf[8], box->type.user.fourcc );
2006 memcpy( &buf[12], box->type.user.id, 12 );
2008 memcpy( buf + (uintptr_t)(box->size - box->unknown_size), box->unknown_field, box->unknown_size );
2009 /* Add a box as a child box and try to expand into struct format. */
2010 lsmash_box_t dummy = { 0 };
2011 int ret = isom_read_box( file, &dummy, parent, 0, 0 );
2012 lsmash_free( buf );
2013 lsmash_bs_cleanup( bs );
2014 file->bs = bs_backup; /* Switch back to the normal file stream mode. */
2015 file->fake_file_mode = 0;
2016 if( ret < 0 )
2017 return ret;
2018 /* Reorder the added box by 'precedence'. */
2019 *p_box = (lsmash_box_t *)parent->extensions.tail->data;
2020 (*p_box)->precedence = box->precedence;
2021 isom_reorder_tail_box( parent );
2022 /* Do also its children by the same way. */
2023 lsmash_entry_list_t extensions = box->extensions;
2024 lsmash_init_entry_list( &box->extensions ); /* to avoid freeing the children */
2025 isom_remove_box_by_itself( box );
2026 for( lsmash_entry_t *entry = extensions.head; entry; entry = entry->next )
2028 if( !entry->data )
2029 continue;
2030 lsmash_box_t *child = (lsmash_box_t *)entry->data;
2031 if( lsmash_add_box_ex( *p_box, &child ) == 0 )
2033 (*p_box)->size += child->size;
2034 /* Avoid freeing at the end of this function. */
2035 entry->data = NULL;
2038 isom_remove_all_extension_boxes( &extensions );
2039 return 0;
2042 void lsmash_destroy_box
2044 lsmash_box_t *box
2047 isom_remove_box_by_itself( box );
2050 void lsmash_destroy_children
2052 lsmash_box_t *box
2055 if( box )
2056 isom_remove_all_extension_boxes( &box->extensions );
2059 int lsmash_get_box_precedence
2061 lsmash_box_t *box,
2062 uint64_t *precedence
2065 if( !box || !precedence )
2066 return LSMASH_ERR_FUNCTION_PARAM;
2067 *precedence = box->precedence;
2068 return 0;
2071 lsmash_box_t *lsmash_root_as_box
2073 lsmash_root_t *root
2076 return (lsmash_box_t *)root;
2079 lsmash_box_t *lsmash_file_as_box
2081 lsmash_file_t *file
2084 return (lsmash_box_t *)file;
2087 int lsmash_write_top_level_box
2089 lsmash_box_t *box
2092 if( !box || (isom_box_t *)box->file != box->parent )
2093 return LSMASH_ERR_FUNCTION_PARAM;
2094 int ret = isom_write_box( box->file->bs, box );
2095 if( ret < 0 )
2096 return ret;
2097 box->file->size += box->size;
2098 return 0;
2101 uint8_t *lsmash_export_box
2103 lsmash_box_t *box,
2104 uint32_t *size
2107 if( !box || !size )
2108 return NULL;
2109 lsmash_bs_t *bs = lsmash_bs_create();
2110 if( !bs )
2111 return NULL;
2112 if( isom_write_box( bs, box ) < 0 )
2114 lsmash_bs_cleanup( bs );
2115 return NULL;
2117 *size = bs->buffer.store;
2118 uint8_t *data = bs->buffer.data;
2119 bs->buffer.data = NULL;
2120 lsmash_bs_cleanup( bs );
2121 return data;