write: Fix type size for mdcv luminance
[L-SMASH.git] / core / box.c
blobb15a1a21bb99a937740d35bf727d3fe40d702fc8
1 /*****************************************************************************
2 * box.c
3 *****************************************************************************
4 * Copyright (C) 2012-2017 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 "box_default.h"
30 #include "write.h"
31 #include "read.h"
32 #include "print.h"
33 #include "timeline.h"
35 #include "codecs/mp4a.h"
36 #include "codecs/mp4sys.h"
38 #include "importer/importer.h"
40 static const lsmash_class_t lsmash_box_class =
42 "box"
45 const lsmash_box_type_t static_lsmash_box_type_unspecified = LSMASH_BOX_TYPE_INITIALIZER;
47 void isom_init_box_common_orig
49 void *_box,
50 void *_parent,
51 lsmash_box_type_t box_type,
52 uint64_t precedence,
53 isom_extension_destructor_t destructor
56 isom_box_t *box = (isom_box_t *)_box;
57 isom_box_t *parent = (isom_box_t *)_parent;
58 assert( box && parent && parent->root );
59 box->class = &lsmash_box_class;
60 box->root = parent->root;
61 box->file = parent->file;
62 box->parent = parent;
63 box->precedence = precedence;
64 box->destruct = destructor;
65 box->size = 0;
66 box->type = box_type;
67 if( !lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_STSD ) && isom_is_fullbox( box ) )
69 box->version = 0;
70 box->flags = 0;
72 isom_set_box_writer( box );
75 static void isom_reorder_tail_box( isom_box_t *parent )
77 /* Reorder the appended box by 'precedence'. */
78 lsmash_entry_t *x = parent->extensions.tail;
79 assert( x && x->data );
80 uint64_t precedence = ((isom_box_t *)x->data)->precedence;
81 for( lsmash_entry_t *y = x->prev; y; y = y->prev )
83 isom_box_t *box = (isom_box_t *)y->data;
84 if( LSMASH_IS_NON_EXISTING_BOX( box ) || precedence > box->precedence )
86 /* Exchange the entity data of adjacent two entries. */
87 y->data = x->data;
88 x->data = box;
89 x = y;
91 else
92 break;
96 int isom_add_box_to_extension_list( void *parent_box, void *child_box )
98 isom_box_t *parent = (isom_box_t *)parent_box;
99 isom_box_t *child = (isom_box_t *)child_box;
100 assert( LSMASH_IS_EXISTING_BOX( parent ) && LSMASH_IS_EXISTING_BOX( child ) );
101 /* Append at the end of the list. */
102 if( lsmash_list_add_entry( &parent->extensions, child ) < 0 )
103 return LSMASH_ERR_MEMORY_ALLOC;
104 /* Don't reorder the appended box when the file is opened for reading. */
105 if( LSMASH_IS_NON_EXISTING_BOX( parent->file )
106 || (parent->file->flags & LSMASH_FILE_MODE_READ)
107 || parent->file->fake_file_mode )
108 return 0;
109 isom_reorder_tail_box( parent );
110 return 0;
113 void isom_bs_put_basebox_common( lsmash_bs_t *bs, isom_box_t *box )
115 if( box->size > UINT32_MAX )
117 lsmash_bs_put_be32( bs, 1 );
118 lsmash_bs_put_be32( bs, box->type.fourcc );
119 lsmash_bs_put_be64( bs, box->size ); /* largesize */
121 else
123 lsmash_bs_put_be32( bs, (uint32_t)box->size );
124 lsmash_bs_put_be32( bs, box->type.fourcc );
126 if( box->type.fourcc == ISOM_BOX_TYPE_UUID.fourcc )
128 lsmash_bs_put_be32( bs, box->type.user.fourcc );
129 lsmash_bs_put_bytes( bs, 12, box->type.user.id );
133 void isom_bs_put_fullbox_common( lsmash_bs_t *bs, isom_box_t *box )
135 isom_bs_put_basebox_common( bs, box );
136 lsmash_bs_put_byte( bs, box->version );
137 lsmash_bs_put_be24( bs, box->flags );
140 void isom_bs_put_box_common( lsmash_bs_t *bs, void *box )
142 if( !box )
144 bs->error = 1;
145 return;
147 isom_box_t *parent = ((isom_box_t *)box)->parent;
148 if( parent && lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_STSD ) )
150 isom_bs_put_basebox_common( bs, (isom_box_t *)box );
151 return;
153 if( isom_is_fullbox( box ) )
154 isom_bs_put_fullbox_common( bs, (isom_box_t *)box );
155 else
156 isom_bs_put_basebox_common( bs, (isom_box_t *)box );
159 /* Return 1 if the box is fullbox, Otherwise return 0. */
160 int isom_is_fullbox( const void *box )
162 const isom_box_t *current = (const isom_box_t *)box;
163 lsmash_box_type_t type = current->type;
164 static lsmash_box_type_t fullbox_type_table[50] = { LSMASH_BOX_TYPE_INITIALIZER };
165 if( !lsmash_check_box_type_specified( &fullbox_type_table[0] ) )
167 /* Initialize the table. */
168 int i = 0;
169 fullbox_type_table[i++] = ISOM_BOX_TYPE_SIDX;
170 fullbox_type_table[i++] = ISOM_BOX_TYPE_MVHD;
171 fullbox_type_table[i++] = ISOM_BOX_TYPE_TKHD;
172 fullbox_type_table[i++] = ISOM_BOX_TYPE_IODS;
173 fullbox_type_table[i++] = ISOM_BOX_TYPE_ESDS;
174 fullbox_type_table[i++] = QT_BOX_TYPE_ESDS;
175 fullbox_type_table[i++] = QT_BOX_TYPE_CLEF;
176 fullbox_type_table[i++] = QT_BOX_TYPE_PROF;
177 fullbox_type_table[i++] = QT_BOX_TYPE_ENOF;
178 fullbox_type_table[i++] = ISOM_BOX_TYPE_ELST;
179 fullbox_type_table[i++] = ISOM_BOX_TYPE_MDHD;
180 fullbox_type_table[i++] = ISOM_BOX_TYPE_HDLR;
181 fullbox_type_table[i++] = ISOM_BOX_TYPE_VMHD;
182 fullbox_type_table[i++] = ISOM_BOX_TYPE_SMHD;
183 fullbox_type_table[i++] = ISOM_BOX_TYPE_HMHD;
184 fullbox_type_table[i++] = ISOM_BOX_TYPE_NMHD;
185 fullbox_type_table[i++] = QT_BOX_TYPE_GMIN;
186 fullbox_type_table[i++] = ISOM_BOX_TYPE_DREF;
187 fullbox_type_table[i++] = ISOM_BOX_TYPE_STSD;
188 fullbox_type_table[i++] = ISOM_BOX_TYPE_STSL;
189 fullbox_type_table[i++] = QT_BOX_TYPE_CHAN;
190 fullbox_type_table[i++] = ISOM_BOX_TYPE_SRAT;
191 fullbox_type_table[i++] = ISOM_BOX_TYPE_STTS;
192 fullbox_type_table[i++] = ISOM_BOX_TYPE_CTTS;
193 fullbox_type_table[i++] = ISOM_BOX_TYPE_CSLG;
194 fullbox_type_table[i++] = ISOM_BOX_TYPE_STSS;
195 fullbox_type_table[i++] = QT_BOX_TYPE_STPS;
196 fullbox_type_table[i++] = ISOM_BOX_TYPE_SDTP;
197 fullbox_type_table[i++] = ISOM_BOX_TYPE_STSC;
198 fullbox_type_table[i++] = ISOM_BOX_TYPE_STSZ;
199 fullbox_type_table[i++] = ISOM_BOX_TYPE_STZ2;
200 fullbox_type_table[i++] = ISOM_BOX_TYPE_STCO;
201 fullbox_type_table[i++] = ISOM_BOX_TYPE_CO64;
202 fullbox_type_table[i++] = ISOM_BOX_TYPE_SGPD;
203 fullbox_type_table[i++] = ISOM_BOX_TYPE_SBGP;
204 fullbox_type_table[i++] = ISOM_BOX_TYPE_CHPL;
205 fullbox_type_table[i++] = ISOM_BOX_TYPE_META;
206 fullbox_type_table[i++] = QT_BOX_TYPE_KEYS;
207 fullbox_type_table[i++] = ISOM_BOX_TYPE_MEAN;
208 fullbox_type_table[i++] = ISOM_BOX_TYPE_NAME;
209 fullbox_type_table[i++] = ISOM_BOX_TYPE_MEHD;
210 fullbox_type_table[i++] = ISOM_BOX_TYPE_TREX;
211 fullbox_type_table[i++] = ISOM_BOX_TYPE_MFHD;
212 fullbox_type_table[i++] = ISOM_BOX_TYPE_TFHD;
213 fullbox_type_table[i++] = ISOM_BOX_TYPE_TFDT;
214 fullbox_type_table[i++] = ISOM_BOX_TYPE_TRUN;
215 fullbox_type_table[i++] = ISOM_BOX_TYPE_TFRA;
216 fullbox_type_table[i++] = ISOM_BOX_TYPE_MFRO;
217 fullbox_type_table[i] = LSMASH_BOX_TYPE_UNSPECIFIED;
219 for( int i = 0; lsmash_check_box_type_specified( &fullbox_type_table[i] ); i++ )
220 if( lsmash_check_box_type_identical( type, fullbox_type_table[i] ) )
221 return 1;
222 if( current->parent )
224 if( lsmash_check_box_type_identical( current->parent->type, ISOM_BOX_TYPE_DREF )
225 || (lsmash_check_box_type_identical( type, ISOM_BOX_TYPE_CPRT )
226 && lsmash_check_box_type_identical( current->parent->type, ISOM_BOX_TYPE_UDTA )) )
227 return 1;
229 return 0;
232 /* Return 1 if the sample type is LPCM audio, Otherwise return 0. */
233 int isom_is_lpcm_audio( const void *box )
235 const isom_box_t *current = (const isom_box_t *)box;
236 lsmash_box_type_t type = current->type;
237 return lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_23NI_AUDIO )
238 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_NONE_AUDIO )
239 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_LPCM_AUDIO )
240 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_SOWT_AUDIO )
241 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_TWOS_AUDIO )
242 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_FL32_AUDIO )
243 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_FL64_AUDIO )
244 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_IN24_AUDIO )
245 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_IN32_AUDIO )
246 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_NOT_SPECIFIED )
247 || (lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_RAW_AUDIO ) && (current->manager & LSMASH_AUDIO_DESCRIPTION));
250 int isom_is_qt_audio( lsmash_codec_type_t type )
252 return lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_23NI_AUDIO )
253 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_MAC3_AUDIO )
254 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_MAC6_AUDIO )
255 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_NONE_AUDIO )
256 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_QDM2_AUDIO )
257 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_QDMC_AUDIO )
258 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_QCLP_AUDIO )
259 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_AC_3_AUDIO )
260 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_AGSM_AUDIO )
261 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ALAC_AUDIO )
262 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ALAW_AUDIO )
263 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_CDX2_AUDIO )
264 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_CDX4_AUDIO )
265 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVCA_AUDIO )
266 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVI_AUDIO )
267 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_FL32_AUDIO )
268 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_FL64_AUDIO )
269 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_IMA4_AUDIO )
270 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_IN24_AUDIO )
271 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_IN32_AUDIO )
272 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_LPCM_AUDIO )
273 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_MP4A_AUDIO )
274 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_RAW_AUDIO )
275 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_SOWT_AUDIO )
276 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_TWOS_AUDIO )
277 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ULAW_AUDIO )
278 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_VDVA_AUDIO )
279 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_FULLMP3_AUDIO )
280 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_MP3_AUDIO )
281 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ADPCM2_AUDIO )
282 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ADPCM17_AUDIO )
283 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_GSM49_AUDIO )
284 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_NOT_SPECIFIED );
287 /* Return 1 if the sample type is uncompressed Y'CbCr video, Otherwise return 0. */
288 int isom_is_uncompressed_ycbcr( lsmash_codec_type_t type )
290 return lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_2VUY_VIDEO )
291 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V210_VIDEO )
292 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V216_VIDEO )
293 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V308_VIDEO )
294 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V408_VIDEO )
295 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V410_VIDEO )
296 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_YUV2_VIDEO );
299 int isom_is_waveform_audio( lsmash_box_type_t type )
301 return lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ADPCM2_AUDIO )
302 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ADPCM17_AUDIO )
303 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_GSM49_AUDIO )
304 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_FULLMP3_AUDIO )
305 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_MP3_AUDIO );
308 size_t isom_skip_box_common( uint8_t **p_data )
310 uint8_t *orig = *p_data;
311 uint8_t *data = *p_data;
312 uint64_t size = LSMASH_GET_BE32( data );
313 data += ISOM_BASEBOX_COMMON_SIZE;
314 if( size == 1 )
316 /* 'size = LSMASH_GET_BE64( data );' is a dead assignment here. */
317 data += 8;
319 *p_data = data;
320 return data - orig;
323 /* TODO: more secure handling */
324 static size_t isom_read_box_size_and_type_from_binary_string( uint8_t **p_data, uint64_t *size, lsmash_box_type_t *type )
326 uint8_t *orig = *p_data;
327 uint8_t *data = *p_data;
328 *size = LSMASH_GET_BE32( &data[0] );
329 type->fourcc = LSMASH_GET_BE32( &data[4] );
330 data += ISOM_BASEBOX_COMMON_SIZE;
331 if( *size == 1 )
333 *size = LSMASH_GET_BE64( data );
334 data += 8;
336 *p_data = data;
337 if( type->fourcc == ISOM_BOX_TYPE_UUID.fourcc )
339 type->user.fourcc = LSMASH_GET_BE32( &data[0] );
340 memcpy( type->user.id, &data[4], 12 );
342 return data - orig;
345 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 )
347 if( !parent_data || !child_size || parent_size < ISOM_BASEBOX_COMMON_SIZE )
348 return NULL;
349 uint8_t *data = parent_data;
350 uint64_t size;
351 lsmash_box_type_t type;
352 (void)isom_read_box_size_and_type_from_binary_string( &data, &size, &type );
353 if( size != parent_size )
354 return NULL;
355 uint8_t *end = parent_data + parent_size;
356 for( uint8_t *pos = data; pos + ISOM_BASEBOX_COMMON_SIZE <= end; )
358 uint32_t offset = isom_read_box_size_and_type_from_binary_string( &pos, &size, &type );
359 if( lsmash_check_box_type_identical( type, child_type ) )
361 *child_size = size;
362 return pos - offset;
364 pos += size - offset; /* Move to the next box. */
366 return NULL;
369 static void isom_destruct_extension_binary( void *ext )
371 if( !ext )
372 return;
373 isom_box_t *box = (isom_box_t *)ext;
374 lsmash_free( box->binary );
377 int isom_add_extension_binary
379 void *parent_box,
380 lsmash_box_type_t box_type,
381 uint64_t precedence,
382 uint8_t *box_data,
383 uint32_t box_size
386 if( !parent_box || !box_data || box_size < ISOM_BASEBOX_COMMON_SIZE
387 || !lsmash_check_box_type_specified( &box_type ) )
388 return LSMASH_ERR_FUNCTION_PARAM;
389 isom_box_t *ext = lsmash_malloc_zero( sizeof(isom_box_t) );
390 if( !ext )
391 return LSMASH_ERR_MEMORY_ALLOC;
392 isom_box_t *parent = (isom_box_t *)parent_box;
393 ext->class = &lsmash_box_class;
394 ext->root = parent->root;
395 ext->file = parent->file;
396 ext->parent = parent;
397 ext->manager = LSMASH_BINARY_CODED_BOX;
398 ext->precedence = precedence;
399 ext->size = box_size;
400 ext->type = box_type;
401 ext->binary = box_data;
402 ext->destruct = isom_destruct_extension_binary;
403 if( isom_add_box_to_extension_list( parent, ext ) < 0 )
405 lsmash_free( ext );
406 return LSMASH_ERR_MEMORY_ALLOC;
408 isom_set_box_writer( ext );
409 return 0;
412 void isom_remove_extension_box( isom_box_t *ext )
414 if( LSMASH_IS_NON_EXISTING_BOX( ext ) )
415 return;
416 if( ext->destruct )
417 ext->destruct( ext );
418 isom_remove_all_extension_boxes( &ext->extensions );
419 lsmash_free( ext );
422 void isom_remove_all_extension_boxes( lsmash_entry_list_t *extensions )
424 lsmash_list_remove_entries( extensions );
427 isom_box_t *isom_get_extension_box( lsmash_entry_list_t *extensions, lsmash_box_type_t box_type )
429 for( lsmash_entry_t *entry = extensions->head; entry; entry = entry->next )
431 isom_box_t *ext = (isom_box_t *)entry->data;
432 if( LSMASH_IS_NON_EXISTING_BOX( ext ) )
433 continue;
434 if( lsmash_check_box_type_identical( ext->type, box_type ) )
435 return ext;
437 return (isom_box_t *)isom_non_existing_unknown();
440 void *isom_get_extension_box_format( lsmash_entry_list_t *extensions, lsmash_box_type_t box_type )
442 for( lsmash_entry_t *entry = extensions->head; entry; entry = entry->next )
444 isom_box_t *ext = (isom_box_t *)entry->data;
445 if( LSMASH_IS_NON_EXISTING_BOX( ext )
446 || (ext->manager & LSMASH_BINARY_CODED_BOX)
447 || !lsmash_check_box_type_identical( ext->type, box_type ) )
448 continue;
449 return ext;
451 return isom_non_existing_unknown();
454 lsmash_entry_t *isom_get_entry_of_box
456 lsmash_box_t *parent,
457 const lsmash_box_path_t box_path[]
460 if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
461 return NULL;
462 lsmash_entry_t *entry = NULL;
463 const lsmash_box_path_t *path = &box_path[0];
464 while( lsmash_check_box_type_specified( &path->type ) )
466 entry = parent->extensions.head;
467 if( !entry )
468 return NULL;
469 parent = NULL;
470 uint32_t i = 1;
471 uint32_t number = path->number ? path->number : 1;
472 while( entry )
474 isom_box_t *box = entry->data;
475 if( box && lsmash_check_box_type_identical( path->type, box->type ) )
477 if( i == number )
479 /* Found a box. Move to a child box. */
480 parent = box;
481 ++path;
482 break;
484 ++i;
486 entry = entry->next;
488 if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
489 return NULL;
491 return entry;
494 /* box destructors
495 * TODO: To eliminate REMOVE_LIST_BOX_2(), an eliminator should be determined when initializing
496 * the list to which the eliminator belongs. */
497 #define REMOVE_BOX( box_name ) \
498 isom_remove_predefined_box( box_name )
500 #define REMOVE_BOX_IN_LIST( box_name ) \
501 isom_remove_box_in_predefined_list( box_name )
503 #define REMOVE_LIST_BOX_TEMPLATE( REMOVER, box_name ) \
504 do \
506 lsmash_list_destroy( box_name->list ); \
507 REMOVER( box_name ); \
508 } while( 0 )
510 #define REMOVE_LIST_BOX( box_name ) \
511 REMOVE_LIST_BOX_TEMPLATE( REMOVE_BOX, box_name )
513 #define REMOVE_LIST_BOX_IN_LIST( box_name ) \
514 REMOVE_LIST_BOX_TEMPLATE( REMOVE_BOX_IN_LIST, box_name )
516 #define DEFINE_SIMPLE_BOX_REMOVER_TEMPLATE( ... ) \
517 CALL_FUNC_DEFAULT_ARGS( DEFINE_SIMPLE_BOX_REMOVER_TEMPLATE, __VA_ARGS__ )
518 #define DEFINE_SIMPLE_BOX_REMOVER_TEMPLATE_3( REMOVER, box_name, ... ) \
519 static void isom_remove_##box_name( isom_##box_name##_t *box_name ) \
521 REMOVER( box_name, __VA_ARGS__ ); \
523 #define DEFINE_SIMPLE_BOX_REMOVER_TEMPLATE_2( REMOVER, box_name ) \
524 static void isom_remove_##box_name( isom_##box_name##_t *box_name ) \
526 REMOVER( box_name ); \
529 #define DEFINE_SIMPLE_BOX_REMOVER( func_name, box_name ) \
530 DEFINE_SIMPLE_BOX_REMOVER_TEMPLATE( REMOVE_BOX, box_name )
532 #define DEFINE_SIMPLE_BOX_IN_LIST_REMOVER( func_name, box_name ) \
533 DEFINE_SIMPLE_BOX_REMOVER_TEMPLATE( REMOVE_BOX_IN_LIST, box_name )
535 #define DEFINE_SIMPLE_LIST_BOX_REMOVER( func_name, box_name ) \
536 DEFINE_SIMPLE_BOX_REMOVER_TEMPLATE( REMOVE_LIST_BOX, box_name )
538 #define DEFINE_SIMPLE_LIST_BOX_IN_LIST_REMOVER( func_name, box_name ) \
539 DEFINE_SIMPLE_BOX_REMOVER_TEMPLATE( REMOVE_LIST_BOX_IN_LIST, box_name )
541 static void isom_remove_predefined_box( void *opaque_box )
543 isom_box_t *box = (isom_box_t *)opaque_box;
544 if( LSMASH_IS_EXISTING_BOX( box )
545 && LSMASH_IS_EXISTING_BOX( box->parent ) )
547 isom_box_t **p = (isom_box_t **)(((int8_t *)box->parent) + box->offset_in_parent);
548 if( *p == box )
549 *p = box->nonexist_ptr;
553 /* We always free boxes through the extension list of the parent box.
554 * Therefore, don't free boxes through any list other than the extension list. */
555 static void isom_remove_box_in_predefined_list( void *opaque_box )
557 isom_box_t *box = (isom_box_t *)opaque_box;
558 if( LSMASH_IS_EXISTING_BOX( box )
559 && LSMASH_IS_EXISTING_BOX( box->parent ) )
561 lsmash_entry_list_t *list = (lsmash_entry_list_t *)(((int8_t *)box->parent) + box->offset_in_parent);
562 if( list )
563 for( lsmash_entry_t *entry = list->head; entry; entry = entry->next )
564 if( box == entry->data )
566 /* We don't free this box here.
567 * Because of freeing an entry of the list here, don't pass the list to free this box.
568 * Or double free. */
569 entry->data = NULL;
570 lsmash_list_remove_entry_direct( list, entry );
571 break;
576 /* Remove a box by the pointer containing its address.
577 * In addition, remove from the extension list of the parent box if possible.
578 * Don't call this function within a function freeing one or more entries of any extension list because of double free.
579 * Basically, don't use this function as a callback function. */
580 void isom_remove_box_by_itself( void *opaque_box )
582 isom_box_t *box = (isom_box_t *)opaque_box;
583 if( LSMASH_IS_NON_EXISTING_BOX( box ) )
584 return;
585 if( LSMASH_IS_EXISTING_BOX( box->parent ) )
587 isom_box_t *parent = box->parent;
588 for( lsmash_entry_t *entry = parent->extensions.head; entry; entry = entry->next )
589 if( box == entry->data )
591 /* Free the corresponding entry here, therefore don't call this function as a callback function
592 * if a function frees the same entry later and calls this function. */
593 lsmash_list_remove_entry_direct( &parent->extensions, entry );
594 return;
597 isom_remove_extension_box( box );
600 void isom_remove_unknown_box( isom_unknown_box_t *unknown_box )
602 lsmash_free( unknown_box->unknown_field );
605 static void isom_remove_file_abstract( isom_file_abstract_t *file_abstract )
607 if( LSMASH_IS_NON_EXISTING_BOX( file_abstract ) )
608 return;
609 isom_printer_destory_list( file_abstract );
610 isom_remove_timelines( file_abstract );
611 lsmash_free( file_abstract->compatible_brands );
612 lsmash_bs_cleanup( file_abstract->bs );
613 lsmash_importer_destroy( file_abstract->importer );
614 if( file_abstract->fragment )
616 lsmash_list_destroy( file_abstract->fragment->pool );
617 lsmash_free( file_abstract->fragment );
619 REMOVE_BOX_IN_LIST( file_abstract );
622 static void isom_remove_ftyp( isom_ftyp_t *ftyp )
624 lsmash_free( ftyp->compatible_brands );
625 REMOVE_BOX( ftyp );
628 static void isom_remove_iods( isom_iods_t *iods )
630 if( LSMASH_IS_NON_EXISTING_BOX( iods ) )
631 return;
632 mp4sys_remove_descriptor( iods->OD );
633 REMOVE_BOX( iods );
636 static void isom_remove_trak( isom_trak_t *trak )
638 if( trak->cache )
640 isom_remove_sample_pool( trak->cache->chunk.pool );
641 lsmash_list_destroy( trak->cache->roll.pool );
642 lsmash_free( trak->cache->rap );
643 lsmash_free( trak->cache->fragment );
644 lsmash_free( trak->cache );
646 REMOVE_BOX_IN_LIST( trak );
649 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_tkhd, tkhd )
650 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_clef, clef )
651 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_prof, prof )
652 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_enof, enof )
653 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_tapt, tapt )
654 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_edts, edts )
655 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_tref, tref )
656 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_elst, elst )
658 static void isom_remove_track_reference_type( isom_tref_type_t *ref )
660 lsmash_free( ref->track_ID );
661 isom_remove_box_in_predefined_list( ref );
664 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mdhd, mdhd )
665 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_vmhd, vmhd )
666 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_smhd, smhd )
667 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_hmhd, hmhd )
668 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_nmhd, nmhd )
669 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_gmhd, gmhd )
670 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_gmin, gmin )
671 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_text, text )
673 static void isom_remove_hdlr( isom_hdlr_t *hdlr )
675 lsmash_free( hdlr->componentName );
676 REMOVE_BOX( hdlr );
679 static void isom_remove_glbl( isom_glbl_t *glbl )
681 lsmash_free( glbl->header_data );
684 static void isom_remove_esds( isom_esds_t *esds )
686 if( LSMASH_IS_NON_EXISTING_BOX( esds ) )
687 return;
688 mp4sys_remove_descriptor( esds->ES );
691 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_ftab, ftab )
693 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_frma, frma )
694 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_enda, enda )
695 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mp4a, mp4a )
696 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_terminator, terminator )
698 static void isom_remove_chan( isom_chan_t *chan )
700 lsmash_free( chan->channelDescriptions );
703 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_stsd, stsd )
705 static void isom_remove_visual_description( isom_sample_entry_t *description )
707 isom_visual_entry_t *visual = (isom_visual_entry_t *)description;
708 lsmash_free( visual->color_table.array );
709 isom_remove_box_in_predefined_list( visual );
712 static void isom_remove_audio_description( isom_sample_entry_t *description )
714 isom_remove_box_in_predefined_list( description );
717 static void isom_remove_hint_description( isom_sample_entry_t *description )
719 isom_hint_entry_t *hint = (isom_hint_entry_t *)description;
720 isom_remove_box_in_predefined_list( hint );
723 static void isom_remove_metadata_description( isom_sample_entry_t *description )
725 isom_remove_box_in_predefined_list( description );
728 static void isom_remove_tx3g_description( isom_sample_entry_t *description )
730 isom_remove_box_in_predefined_list( description );
733 static void isom_remove_qt_text_description( isom_sample_entry_t *description )
735 isom_qt_text_entry_t *text = (isom_qt_text_entry_t *)description;
736 lsmash_free( text->font_name );
737 isom_remove_box_in_predefined_list( text );
740 static void isom_remove_mp4s_description( isom_sample_entry_t *description )
742 isom_remove_box_in_predefined_list( description );
745 void isom_remove_sample_description( isom_sample_entry_t *sample )
747 if( LSMASH_IS_NON_EXISTING_BOX( sample ) )
748 return;
749 lsmash_codec_type_t sample_type = sample->type;
750 if( lsmash_check_box_type_identical( sample_type, LSMASH_CODEC_TYPE_RAW ) )
752 if( sample->manager & LSMASH_VIDEO_DESCRIPTION )
754 isom_remove_visual_description( sample );
755 return;
757 else if( sample->manager & LSMASH_AUDIO_DESCRIPTION )
759 isom_remove_audio_description( sample );
760 return;
763 static struct description_remover_table_tag
765 lsmash_codec_type_t type;
766 void (*func)( isom_sample_entry_t * );
767 } description_remover_table[160] = { { LSMASH_CODEC_TYPE_INITIALIZER, NULL } };
768 if( !description_remover_table[0].func )
770 /* Initialize the table. */
771 int i = 0;
772 #define ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( type, func ) \
773 description_remover_table[i++] = (struct description_remover_table_tag){ type, func }
774 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVC1_VIDEO, isom_remove_visual_description );
775 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVC2_VIDEO, isom_remove_visual_description );
776 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVC3_VIDEO, isom_remove_visual_description );
777 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVC4_VIDEO, isom_remove_visual_description );
778 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVCP_VIDEO, isom_remove_visual_description );
779 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_HVC1_VIDEO, isom_remove_visual_description );
780 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_HEV1_VIDEO, isom_remove_visual_description );
781 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SVC1_VIDEO, isom_remove_visual_description );
782 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MVC1_VIDEO, isom_remove_visual_description );
783 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MVC2_VIDEO, isom_remove_visual_description );
784 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MP4V_VIDEO, isom_remove_visual_description );
785 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DRAC_VIDEO, isom_remove_visual_description );
786 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_ENCV_VIDEO, isom_remove_visual_description );
787 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MJP2_VIDEO, isom_remove_visual_description );
788 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_S263_VIDEO, isom_remove_visual_description );
789 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_VC_1_VIDEO, isom_remove_visual_description );
790 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_2VUY_VIDEO, isom_remove_visual_description );
791 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_CFHD_VIDEO, isom_remove_visual_description );
792 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DV10_VIDEO, isom_remove_visual_description );
793 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVOO_VIDEO, isom_remove_visual_description );
794 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVOR_VIDEO, isom_remove_visual_description );
795 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVTV_VIDEO, isom_remove_visual_description );
796 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVVT_VIDEO, isom_remove_visual_description );
797 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_HD10_VIDEO, isom_remove_visual_description );
798 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_M105_VIDEO, isom_remove_visual_description );
799 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_PNTG_VIDEO, isom_remove_visual_description );
800 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SVQ1_VIDEO, isom_remove_visual_description );
801 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SVQ3_VIDEO, isom_remove_visual_description );
802 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR0_VIDEO, isom_remove_visual_description );
803 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR1_VIDEO, isom_remove_visual_description );
804 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR2_VIDEO, isom_remove_visual_description );
805 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR3_VIDEO, isom_remove_visual_description );
806 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR4_VIDEO, isom_remove_visual_description );
807 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_WRLE_VIDEO, isom_remove_visual_description );
808 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_APCH_VIDEO, isom_remove_visual_description );
809 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_APCN_VIDEO, isom_remove_visual_description );
810 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_APCS_VIDEO, isom_remove_visual_description );
811 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_APCO_VIDEO, isom_remove_visual_description );
812 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_AP4H_VIDEO, isom_remove_visual_description );
813 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_AP4X_VIDEO, isom_remove_visual_description );
814 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_CIVD_VIDEO, isom_remove_visual_description );
815 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DRAC_VIDEO, isom_remove_visual_description );
816 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVC_VIDEO, isom_remove_visual_description );
817 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVCP_VIDEO, isom_remove_visual_description );
818 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVPP_VIDEO, isom_remove_visual_description );
819 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DV5N_VIDEO, isom_remove_visual_description );
820 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DV5P_VIDEO, isom_remove_visual_description );
821 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVH2_VIDEO, isom_remove_visual_description );
822 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVH3_VIDEO, isom_remove_visual_description );
823 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVH5_VIDEO, isom_remove_visual_description );
824 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVH6_VIDEO, isom_remove_visual_description );
825 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVHP_VIDEO, isom_remove_visual_description );
826 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVHQ_VIDEO, isom_remove_visual_description );
827 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_FLIC_VIDEO, isom_remove_visual_description );
828 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_GIF_VIDEO, isom_remove_visual_description );
829 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_H261_VIDEO, isom_remove_visual_description );
830 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_H263_VIDEO, isom_remove_visual_description );
831 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_JPEG_VIDEO, isom_remove_visual_description );
832 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_MJPA_VIDEO, isom_remove_visual_description );
833 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_MJPB_VIDEO, isom_remove_visual_description );
834 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_PNG_VIDEO, isom_remove_visual_description );
835 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_RLE_VIDEO, isom_remove_visual_description );
836 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_RPZA_VIDEO, isom_remove_visual_description );
837 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_TGA_VIDEO, isom_remove_visual_description );
838 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_TIFF_VIDEO, isom_remove_visual_description );
839 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULRA_VIDEO, isom_remove_visual_description );
840 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULRG_VIDEO, isom_remove_visual_description );
841 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULY2_VIDEO, isom_remove_visual_description );
842 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULY0_VIDEO, isom_remove_visual_description );
843 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULH2_VIDEO, isom_remove_visual_description );
844 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULH0_VIDEO, isom_remove_visual_description );
845 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_UQY2_VIDEO, isom_remove_visual_description );
846 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V210_VIDEO, isom_remove_visual_description );
847 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V216_VIDEO, isom_remove_visual_description );
848 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V308_VIDEO, isom_remove_visual_description );
849 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V408_VIDEO, isom_remove_visual_description );
850 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V410_VIDEO, isom_remove_visual_description );
851 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_YUV2_VIDEO, isom_remove_visual_description );
852 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MP4A_AUDIO, isom_remove_audio_description );
853 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AC_3_AUDIO, isom_remove_audio_description );
854 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_ALAC_AUDIO, isom_remove_audio_description );
855 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSEL_AUDIO, isom_remove_audio_description );
856 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSDL_AUDIO, isom_remove_audio_description );
857 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSC_AUDIO, isom_remove_audio_description );
858 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSE_AUDIO, isom_remove_audio_description );
859 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSH_AUDIO, isom_remove_audio_description );
860 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSL_AUDIO, isom_remove_audio_description );
861 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSX_AUDIO, isom_remove_audio_description );
862 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_EC_3_AUDIO, isom_remove_audio_description );
863 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SAMR_AUDIO, isom_remove_audio_description );
864 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SAWB_AUDIO, isom_remove_audio_description );
865 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_MP4A_AUDIO, isom_remove_audio_description );
866 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_23NI_AUDIO, isom_remove_audio_description );
867 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_NONE_AUDIO, isom_remove_audio_description );
868 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_LPCM_AUDIO, isom_remove_audio_description );
869 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SOWT_AUDIO, isom_remove_audio_description );
870 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_TWOS_AUDIO, isom_remove_audio_description );
871 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_FL32_AUDIO, isom_remove_audio_description );
872 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_FL64_AUDIO, isom_remove_audio_description );
873 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_IN24_AUDIO, isom_remove_audio_description );
874 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_IN32_AUDIO, isom_remove_audio_description );
875 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_NOT_SPECIFIED, isom_remove_audio_description );
876 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DRA1_AUDIO, isom_remove_audio_description );
877 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_ENCA_AUDIO, isom_remove_audio_description );
878 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_G719_AUDIO, isom_remove_audio_description );
879 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_G726_AUDIO, isom_remove_audio_description );
880 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_M4AE_AUDIO, isom_remove_audio_description );
881 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MLPA_AUDIO, isom_remove_audio_description );
882 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SAWP_AUDIO, isom_remove_audio_description );
883 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SEVC_AUDIO, isom_remove_audio_description );
884 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SQCP_AUDIO, isom_remove_audio_description );
885 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SSMV_AUDIO, isom_remove_audio_description );
886 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_TWOS_AUDIO, isom_remove_audio_description );
887 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_FDP_HINT, isom_remove_hint_description );
888 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_M2TS_HINT, isom_remove_hint_description );
889 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_PM2T_HINT, isom_remove_hint_description );
890 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_PRTP_HINT, isom_remove_hint_description );
891 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_RM2T_HINT, isom_remove_hint_description );
892 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_RRTP_HINT, isom_remove_hint_description );
893 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_RSRP_HINT, isom_remove_hint_description );
894 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_RTP_HINT , isom_remove_hint_description );
895 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SM2T_HINT, isom_remove_hint_description );
896 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SRTP_HINT, isom_remove_hint_description );
897 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_IXSE_META, isom_remove_metadata_description );
898 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_METT_META, isom_remove_metadata_description );
899 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_METX_META, isom_remove_metadata_description );
900 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MLIX_META, isom_remove_metadata_description );
901 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_OKSD_META, isom_remove_metadata_description );
902 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SVCM_META, isom_remove_metadata_description );
903 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_TEXT_META, isom_remove_metadata_description );
904 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_URIM_META, isom_remove_metadata_description );
905 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_XML_META, isom_remove_metadata_description );
906 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_TX3G_TEXT, isom_remove_tx3g_description );
907 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_TEXT_TEXT, isom_remove_qt_text_description );
908 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MP4S_SYSTEM, isom_remove_mp4s_description );
909 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( LSMASH_CODEC_TYPE_UNSPECIFIED, NULL );
911 for( int i = 0; description_remover_table[i].func; i++ )
912 if( lsmash_check_codec_type_identical( sample_type, description_remover_table[i].type ) )
914 description_remover_table[i].func( sample );
915 return;
919 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stts, stts )
920 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_ctts, ctts )
921 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_cslg, cslg )
922 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stsc, stsc )
923 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stsz, stsz )
924 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stz2, stz2 )
925 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stss, stss )
926 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stps, stps )
927 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stco, stco )
929 static void isom_remove_sdtp( isom_sdtp_t *sdtp )
931 if( LSMASH_IS_NON_EXISTING_BOX( sdtp ) )
932 return;
933 lsmash_list_destroy( sdtp->list );
934 REMOVE_BOX( sdtp );
937 static void isom_remove_sgpd( isom_sgpd_t *sgpd )
939 if( LSMASH_IS_NON_EXISTING_BOX( sgpd ) )
940 return;
941 lsmash_list_destroy( sgpd->list );
942 REMOVE_BOX_IN_LIST( sgpd );
945 static void isom_remove_sbgp( isom_sbgp_t *sbgp )
947 if( LSMASH_IS_NON_EXISTING_BOX( sbgp ) )
948 return;
949 lsmash_list_destroy( sbgp->list );
950 REMOVE_BOX_IN_LIST( sbgp );
953 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_stbl, stbl )
955 static void isom_remove_dref_entry( isom_dref_entry_t *data_entry )
957 lsmash_free( data_entry->name );
958 lsmash_free( data_entry->location );
959 isom_remove_box_in_predefined_list( data_entry );
962 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_dref, dref )
963 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_dinf, dinf )
964 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_minf, minf )
965 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mdia, mdia )
966 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_chpl, chpl )
967 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_keys, keys )
969 static void isom_remove_mean( isom_mean_t *mean )
971 lsmash_free( mean->meaning_string );
972 REMOVE_BOX( mean );
975 static void isom_remove_name( isom_name_t *name )
977 lsmash_free( name->name );
978 REMOVE_BOX( name );
981 static void isom_remove_data( isom_data_t *data )
983 lsmash_free( data->value );
984 REMOVE_BOX( data );
987 DEFINE_SIMPLE_BOX_IN_LIST_REMOVER( isom_remove_metaitem, metaitem )
988 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_ilst, ilst )
989 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_meta, meta )
991 static void isom_remove_cprt( isom_cprt_t *cprt )
993 lsmash_free( cprt->notice );
994 REMOVE_BOX_IN_LIST( cprt );
997 static void isom_remove_rtp( isom_rtp_t *rtp )
999 lsmash_free( rtp->sdptext );
1000 REMOVE_BOX( rtp );
1003 static void isom_remove_sdp( isom_sdp_t *sdp )
1005 lsmash_free( sdp->sdptext );
1006 REMOVE_BOX( sdp );
1009 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_udta, udta )
1010 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_WLOC, WLOC )
1011 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_LOOP, LOOP )
1012 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_SelO, SelO )
1013 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_AllF, AllF )
1014 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_hnti, hnti )
1016 static void isom_remove_ctab( isom_ctab_t *ctab )
1018 lsmash_free( ctab->color_table.array );
1019 REMOVE_BOX( ctab );
1022 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mvex, mvex )
1023 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mvhd, mvhd )
1024 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mehd, mehd )
1025 DEFINE_SIMPLE_BOX_IN_LIST_REMOVER( isom_remove_trex, trex )
1026 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_moov, moov )
1027 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mdat, mdat )
1028 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mfhd, mfhd )
1029 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_tfhd, tfhd )
1030 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_tfdt, tfdt )
1032 static void isom_remove_trun( isom_trun_t *trun )
1034 lsmash_list_destroy( trun->optional );
1035 REMOVE_BOX_IN_LIST( trun );
1038 DEFINE_SIMPLE_BOX_IN_LIST_REMOVER( isom_remove_traf, traf )
1039 DEFINE_SIMPLE_BOX_IN_LIST_REMOVER( isom_remove_moof, moof )
1041 static void isom_remove_free( isom_free_t *skip )
1043 lsmash_free( skip->data );
1045 #define isom_remove_skip isom_remove_free
1047 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mfra, mfra )
1048 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mfro, mfro )
1049 DEFINE_SIMPLE_LIST_BOX_IN_LIST_REMOVER( isom_remove_tfra, tfra )
1050 DEFINE_SIMPLE_LIST_BOX_IN_LIST_REMOVER( isom_remove_sidx, sidx )
1052 static void isom_remove_styp( isom_styp_t *styp )
1054 lsmash_free( styp->compatible_brands );
1055 REMOVE_BOX_IN_LIST( styp );
1058 #define isom_remove_elst_entry lsmash_free
1059 #define isom_remove_stts_entry lsmash_free
1060 #define isom_remove_ctts_entry lsmash_free
1061 #define isom_remove_stsz_entry lsmash_free
1062 #define isom_remove_stz2_entry lsmash_free
1063 #define isom_remove_stss_entry lsmash_free
1064 #define isom_remove_stps_entry lsmash_free
1065 #define isom_remove_sdtp_entry lsmash_free
1066 #define isom_remove_stsc_entry lsmash_free
1067 #define isom_remove_stco_entry lsmash_free
1068 #define isom_remove_co64_entry lsmash_free
1069 #define isom_remove_sgpd_entry lsmash_free
1070 #define isom_remove_sbgp_entry lsmash_free
1071 #define isom_remove_trun_entry lsmash_free
1072 #define isom_remove_tfra_entry lsmash_free
1073 #define isom_remove_sidx_entry lsmash_free
1075 static void isom_remove_ftab_entry( isom_font_record_t *font_record )
1077 if( !font_record )
1078 return;
1079 lsmash_free( font_record->font_name );
1080 lsmash_free( font_record );
1083 static void isom_remove_chpl_entry( isom_chpl_entry_t *data )
1085 if( !data )
1086 return;
1087 lsmash_free( data->chapter_name );
1088 lsmash_free( data );
1091 static void isom_remove_keys_entry( isom_keys_entry_t *data )
1093 if( !data )
1094 return;
1095 lsmash_free( data->key_value );
1096 lsmash_free( data );
1099 /* box size updater */
1100 uint64_t isom_update_box_size( void *opaque_box )
1102 isom_box_t *box = (isom_box_t *)opaque_box;
1103 assert( LSMASH_IS_EXISTING_BOX( box ) );
1104 if( box->manager & LSMASH_WRITTEN_BOX )
1105 /* No need to calculate the size of this box since the size is already decided and fixed. */
1106 return box->size;
1107 uint64_t size = 0;
1108 if( box->write )
1110 /* Calculate the size of this box excluding its children with a fake bytestream writer. */
1112 lsmash_bs_t fake_bs = { NULL };
1113 if( box->write( &fake_bs, box ) == 0 )
1114 size = lsmash_bs_get_valid_data_size( &fake_bs );
1116 /* Calculate the size of the children if no error. */
1117 if( size >= ISOM_BASEBOX_COMMON_SIZE )
1119 for( lsmash_entry_t *entry = box->extensions.head; entry; entry = entry->next )
1120 if( entry->data )
1121 size += isom_update_box_size( entry->data );
1122 /* Check large size. */
1123 if( size > UINT32_MAX )
1124 size += 8;
1126 else
1127 /* TODO: add error handling. */
1128 size = 0;
1130 box->size = size;
1131 return size;
1134 /* box adding functions */
1135 #define ATTACH_EXACTLY_ONE_BOX_TO_PARENT( box_name, parent_type ) \
1136 do \
1138 size_t offset_in_parent = offsetof( parent_type, box_name ); \
1139 isom_box_t **p = (isom_box_t **)(((int8_t *)box_name->parent) \
1140 + offset_in_parent); \
1141 assert( *p ); \
1142 if( LSMASH_IS_NON_EXISTING_BOX( *p ) ) \
1144 *p = (isom_box_t *)box_name; \
1145 (*p)->offset_in_parent = offset_in_parent; \
1147 } while( 0 )
1149 #define ADD_BOX_TO_PREDEFINED_LIST( box_name, parent_name ) \
1150 if( lsmash_list_add_entry( &parent_name->box_name##_list, box_name ) < 0 ) \
1152 lsmash_list_remove_entry_tail( &parent_name->extensions ); \
1153 return isom_non_existing_##box_name(); \
1155 box_name->offset_in_parent = offsetof( isom_##parent_name##_t, box_name##_list )
1157 #define INIT_BOX_COMMON0( box_name, parent_name, box_type, precedence ) \
1158 const isom_extension_destructor_t isom_remove_##box_name = NULL; \
1159 isom_init_box_common( box_name, parent_name, box_type, precedence, isom_remove_##box_name )
1160 #define INIT_BOX_COMMON1( box_name, parent_name, box_type, precedence ) \
1161 isom_init_box_common( box_name, parent_name, box_type, precedence, isom_remove_##box_name )
1163 #define CREATE_BOX( box_name, parent_name, box_type, precedence, has_destructor ) \
1164 if( LSMASH_IS_NON_EXISTING_BOX( (isom_box_t *)parent_name ) ) \
1165 return isom_non_existing_##box_name(); \
1166 isom_##box_name##_t *box_name = ALLOCATE_BOX( box_name ); \
1167 if( LSMASH_IS_NON_EXISTING_BOX( box_name ) ) \
1168 return box_name; \
1169 INIT_BOX_COMMON ## has_destructor( box_name, parent_name, box_type, precedence ); \
1170 if( isom_add_box_to_extension_list( parent_name, box_name ) < 0 ) \
1172 lsmash_free( box_name ); \
1173 return isom_non_existing_##box_name(); \
1175 #define CREATE_LIST_BOX( box_name, parent_name, box_type, precedence, has_destructor ) \
1176 CREATE_BOX( box_name, parent_name, box_type, precedence, has_destructor ); \
1177 box_name->list = lsmash_list_create( isom_remove_##box_name##_entry ); \
1178 if( !box_name->list ) \
1180 lsmash_list_remove_entry_tail( &parent_name->extensions ); \
1181 return isom_non_existing_##box_name(); \
1184 #define ADD_BOX_TEMPLATE( box_name, parent_name, box_type, precedence, BOX_CREATOR ) \
1185 BOX_CREATOR( box_name, parent_name, box_type, precedence, 1 ); \
1186 if( LSMASH_IS_NON_EXISTING_BOX( parent_name->box_name ) ) \
1188 parent_name->box_name = box_name; \
1189 box_name->offset_in_parent = offsetof( isom_##parent_name##_t, box_name ); \
1190 } do {} while( 0 )
1191 #define ADD_BOX_IN_LIST_TEMPLATE( box_name, parent_name, box_type, precedence, BOX_CREATOR ) \
1192 BOX_CREATOR( box_name, parent_name, box_type, precedence, 1 ); \
1193 ADD_BOX_TO_PREDEFINED_LIST( box_name, parent_name )
1195 #define ADD_BOX( box_name, parent_name, box_type, precedence ) \
1196 ADD_BOX_TEMPLATE( box_name, parent_name, box_type, precedence, CREATE_BOX )
1197 #define ADD_BOX_IN_LIST( box_name, parent_name, box_type, precedence ) \
1198 ADD_BOX_IN_LIST_TEMPLATE( box_name, parent_name, box_type, precedence, CREATE_BOX )
1199 #define ADD_LIST_BOX( box_name, parent_name, box_type, precedence ) \
1200 ADD_BOX_TEMPLATE( box_name, parent_name, box_type, precedence, CREATE_LIST_BOX )
1201 #define ADD_LIST_BOX_IN_LIST( box_name, parent_name, box_type, precedence ) \
1202 ADD_BOX_IN_LIST_TEMPLATE( box_name, parent_name, box_type, precedence, CREATE_LIST_BOX )
1204 #define DEFINE_SIMPLE_BOX_ADDER_TEMPLATE( ... ) CALL_FUNC_DEFAULT_ARGS( DEFINE_SIMPLE_BOX_ADDER_TEMPLATE, __VA_ARGS__ )
1205 #define DEFINE_SIMPLE_BOX_ADDER_TEMPLATE_6( ADDER, box_name, parent_name, box_type, precedence, postprocess ) \
1206 isom_##box_name##_t *isom_add_##box_name( isom_##parent_name##_t *parent_name ) \
1208 ADDER( box_name, parent_name, box_type, precedence ); \
1209 do { postprocess } while( 0 ); \
1210 return box_name; \
1212 #define DEFINE_SIMPLE_BOX_ADDER_TEMPLATE_5( ADDER, box_name, parent_name, box_type, precedence ) \
1213 DEFINE_SIMPLE_BOX_ADDER_TEMPLATE_6( ADDER, box_name, parent_name, box_type, precedence, )
1215 #define DEFINE_SIMPLE_BOX_ADDER( func_name, ... ) \
1216 DEFINE_SIMPLE_BOX_ADDER_TEMPLATE( ADD_BOX, __VA_ARGS__ )
1217 #define DEFINE_SIMPLE_BOX_IN_LIST_ADDER( func_name, ... ) \
1218 DEFINE_SIMPLE_BOX_ADDER_TEMPLATE( ADD_BOX_IN_LIST, __VA_ARGS__ )
1219 #define DEFINE_SIMPLE_LIST_BOX_ADDER( func_name, ... ) \
1220 DEFINE_SIMPLE_BOX_ADDER_TEMPLATE( ADD_LIST_BOX, __VA_ARGS__ )
1222 #define DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( func_name, box_name, parent_name, box_type, precedence, has_destructor, parent_type ) \
1223 isom_##box_name##_t *isom_add_##box_name( parent_type *parent_name ) \
1225 CREATE_BOX( box_name, parent_name, box_type, precedence, has_destructor ); \
1226 return box_name; \
1229 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_file_abstract, file_abstract, root_abstract, LSMASH_BOX_TYPE_UNSPECIFIED, 0,
1230 file_abstract->file = file_abstract; )
1232 isom_tref_type_t *isom_add_track_reference_type( isom_tref_t *tref, isom_track_reference_type type )
1234 if( LSMASH_IS_NON_EXISTING_BOX( tref ) )
1235 return isom_non_existing_tref_type();
1236 isom_tref_type_t *tref_type = ALLOCATE_BOX( tref_type );
1237 if( LSMASH_IS_NON_EXISTING_BOX( tref_type ) )
1238 return tref_type;
1239 /* Initialize common fields. */
1240 tref_type->class = &lsmash_box_class;
1241 tref_type->root = tref->root;
1242 tref_type->file = tref->file;
1243 tref_type->parent = (isom_box_t *)tref;
1244 tref_type->precedence = LSMASH_BOX_PRECEDENCE_ISOM_TREF_TYPE;
1245 tref_type->destruct = (isom_extension_destructor_t)isom_remove_track_reference_type;
1246 tref_type->size = 0;
1247 tref_type->type = lsmash_form_iso_box_type( type );
1248 isom_set_box_writer( (isom_box_t *)tref_type );
1249 if( isom_add_box_to_extension_list( tref, tref_type ) < 0 )
1251 lsmash_free( tref_type );
1252 return isom_non_existing_tref_type();
1254 if( lsmash_list_add_entry( &tref->ref_list, tref_type ) < 0 )
1256 lsmash_list_remove_entry_tail( &tref->extensions );
1257 return isom_non_existing_tref_type();
1259 tref_type->offset_in_parent = offsetof( isom_tref_t, ref_list );
1260 return tref_type;
1263 DEFINE_SIMPLE_BOX_ADDER( isom_add_terminator, terminator, wave, QT_BOX_TYPE_TERMINATOR, LSMASH_BOX_PRECEDENCE_QTFF_TERMINATOR )
1264 DEFINE_SIMPLE_BOX_ADDER( isom_add_frma, frma, wave, QT_BOX_TYPE_FRMA, LSMASH_BOX_PRECEDENCE_QTFF_FRMA )
1265 DEFINE_SIMPLE_BOX_ADDER( isom_add_enda, enda, wave, QT_BOX_TYPE_ENDA, LSMASH_BOX_PRECEDENCE_QTFF_ENDA )
1266 DEFINE_SIMPLE_BOX_ADDER( isom_add_mp4a, mp4a, wave, QT_BOX_TYPE_MP4A, LSMASH_BOX_PRECEDENCE_QTFF_MP4A )
1267 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_ftab, ftab, tx3g_entry, ISOM_BOX_TYPE_FTAB, LSMASH_BOX_PRECEDENCE_ISOM_FTAB )
1268 DEFINE_SIMPLE_BOX_ADDER( isom_add_ftyp, ftyp, file_abstract, ISOM_BOX_TYPE_FTYP, LSMASH_BOX_PRECEDENCE_ISOM_FTYP )
1269 DEFINE_SIMPLE_BOX_ADDER( isom_add_moov, moov, file_abstract, ISOM_BOX_TYPE_MOOV, LSMASH_BOX_PRECEDENCE_ISOM_MOOV )
1270 DEFINE_SIMPLE_BOX_ADDER( isom_add_mvhd, mvhd, moov, ISOM_BOX_TYPE_MVHD, LSMASH_BOX_PRECEDENCE_ISOM_MVHD )
1271 DEFINE_SIMPLE_BOX_ADDER( isom_add_iods, iods, moov, ISOM_BOX_TYPE_IODS, LSMASH_BOX_PRECEDENCE_ISOM_IODS )
1273 isom_ctab_t *isom_add_ctab( void *parent_box )
1275 /* According to QuickTime File Format Specification, this box is placed inside Movie Box if present.
1276 * However, sometimes this box occurs inside an image description entry or the end of Sample Description Box. */
1277 isom_box_t *parent = (isom_box_t *)parent_box;
1278 if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
1279 return isom_non_existing_ctab();
1280 CREATE_BOX( ctab, parent, QT_BOX_TYPE_CTAB, LSMASH_BOX_PRECEDENCE_QTFF_CTAB, 1 );
1281 if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_MOOV ) )
1282 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( ctab, isom_moov_t );
1283 return ctab;
1286 isom_trak_t *isom_add_trak( isom_moov_t *moov )
1288 if( LSMASH_IS_NON_EXISTING_BOX( moov )
1289 || LSMASH_IS_NON_EXISTING_BOX( moov->file ) )
1290 return isom_non_existing_trak();
1291 CREATE_BOX( trak, moov, ISOM_BOX_TYPE_TRAK, LSMASH_BOX_PRECEDENCE_ISOM_TRAK, 1 );
1292 isom_fragment_t *fragment = NULL;
1293 isom_cache_t *cache = lsmash_malloc_zero( sizeof(isom_cache_t) );
1294 if( !cache )
1295 goto fail;
1296 if( moov->file->fragment )
1298 fragment = lsmash_malloc_zero( sizeof(isom_fragment_t) );
1299 if( !fragment )
1300 goto fail;
1301 cache->fragment = fragment;
1302 fragment->largest_cts = LSMASH_TIMESTAMP_UNDEFINED;
1303 fragment->subsegment.largest_cts = LSMASH_TIMESTAMP_UNDEFINED;
1304 fragment->subsegment.smallest_cts = LSMASH_TIMESTAMP_UNDEFINED;
1305 fragment->subsegment.first_sample_cts = LSMASH_TIMESTAMP_UNDEFINED;
1306 fragment->subsegment.first_ed_cts = LSMASH_TIMESTAMP_UNDEFINED;
1307 fragment->subsegment.first_rp_cts = LSMASH_TIMESTAMP_UNDEFINED;
1309 if( lsmash_list_add_entry( &moov->trak_list, trak ) < 0 )
1310 goto fail;
1311 trak->offset_in_parent = offsetof( isom_moov_t, trak_list );
1312 trak->cache = cache;
1313 return trak;
1314 fail:
1315 lsmash_free( fragment );
1316 lsmash_free( cache );
1317 lsmash_list_remove_entry_tail( &moov->extensions );
1318 return isom_non_existing_trak();
1321 DEFINE_SIMPLE_BOX_ADDER ( isom_add_tkhd, tkhd, trak, ISOM_BOX_TYPE_TKHD, LSMASH_BOX_PRECEDENCE_ISOM_TKHD )
1322 DEFINE_SIMPLE_BOX_ADDER ( isom_add_tapt, tapt, trak, QT_BOX_TYPE_TAPT, LSMASH_BOX_PRECEDENCE_QTFF_TAPT )
1323 DEFINE_SIMPLE_BOX_ADDER ( isom_add_clef, clef, tapt, QT_BOX_TYPE_CLEF, LSMASH_BOX_PRECEDENCE_QTFF_CLEF )
1324 DEFINE_SIMPLE_BOX_ADDER ( isom_add_prof, prof, tapt, QT_BOX_TYPE_PROF, LSMASH_BOX_PRECEDENCE_QTFF_PROF )
1325 DEFINE_SIMPLE_BOX_ADDER ( isom_add_enof, enof, tapt, QT_BOX_TYPE_ENOF, LSMASH_BOX_PRECEDENCE_QTFF_ENOF )
1326 DEFINE_SIMPLE_BOX_ADDER ( isom_add_edts, edts, trak, ISOM_BOX_TYPE_EDTS, LSMASH_BOX_PRECEDENCE_ISOM_EDTS )
1327 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_elst, elst, edts, ISOM_BOX_TYPE_ELST, LSMASH_BOX_PRECEDENCE_ISOM_ELST )
1328 DEFINE_SIMPLE_BOX_ADDER ( isom_add_tref, tref, trak, ISOM_BOX_TYPE_TREF, LSMASH_BOX_PRECEDENCE_ISOM_TREF )
1329 DEFINE_SIMPLE_BOX_ADDER ( isom_add_mdia, mdia, trak, ISOM_BOX_TYPE_MDIA, LSMASH_BOX_PRECEDENCE_ISOM_MDIA )
1330 DEFINE_SIMPLE_BOX_ADDER ( isom_add_mdhd, mdhd, mdia, ISOM_BOX_TYPE_MDHD, LSMASH_BOX_PRECEDENCE_ISOM_MDHD )
1332 isom_hdlr_t *isom_add_hdlr( void *parent_box )
1334 isom_box_t *parent = (isom_box_t *)parent_box;
1335 if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
1336 return isom_non_existing_hdlr();
1337 CREATE_BOX( hdlr, parent, ISOM_BOX_TYPE_HDLR, LSMASH_BOX_PRECEDENCE_ISOM_HDLR, 1 );
1338 if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_MDIA ) )
1339 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( hdlr, isom_mdia_t );
1340 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_META )
1341 || lsmash_check_box_type_identical( parent->type, QT_BOX_TYPE_META ) )
1342 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( hdlr, isom_meta_t );
1343 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_MINF ) )
1344 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( hdlr, isom_minf_t );
1345 else
1346 assert( 0 );
1347 return hdlr;
1350 DEFINE_SIMPLE_BOX_ADDER( isom_add_minf, minf, mdia, ISOM_BOX_TYPE_MINF, LSMASH_BOX_PRECEDENCE_ISOM_MINF )
1351 DEFINE_SIMPLE_BOX_ADDER( isom_add_vmhd, vmhd, minf, ISOM_BOX_TYPE_VMHD, LSMASH_BOX_PRECEDENCE_ISOM_VMHD )
1352 DEFINE_SIMPLE_BOX_ADDER( isom_add_smhd, smhd, minf, ISOM_BOX_TYPE_SMHD, LSMASH_BOX_PRECEDENCE_ISOM_SMHD )
1353 DEFINE_SIMPLE_BOX_ADDER( isom_add_hmhd, hmhd, minf, ISOM_BOX_TYPE_HMHD, LSMASH_BOX_PRECEDENCE_ISOM_HMHD )
1354 DEFINE_SIMPLE_BOX_ADDER( isom_add_nmhd, nmhd, minf, ISOM_BOX_TYPE_NMHD, LSMASH_BOX_PRECEDENCE_ISOM_NMHD )
1355 DEFINE_SIMPLE_BOX_ADDER( isom_add_gmhd, gmhd, minf, QT_BOX_TYPE_GMHD, LSMASH_BOX_PRECEDENCE_QTFF_GMHD )
1356 DEFINE_SIMPLE_BOX_ADDER( isom_add_gmin, gmin, gmhd, QT_BOX_TYPE_GMIN, LSMASH_BOX_PRECEDENCE_QTFF_GMIN )
1357 DEFINE_SIMPLE_BOX_ADDER( isom_add_text, text, gmhd, QT_BOX_TYPE_TEXT, LSMASH_BOX_PRECEDENCE_QTFF_TEXT )
1359 isom_dinf_t *isom_add_dinf( void *parent_box )
1361 isom_box_t *parent = (isom_box_t *)parent_box;
1362 if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
1363 return isom_non_existing_dinf();
1364 CREATE_BOX( dinf, parent, ISOM_BOX_TYPE_DINF, LSMASH_BOX_PRECEDENCE_ISOM_DINF, 1 );
1365 if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_MINF ) )
1366 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( dinf, isom_minf_t );
1367 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_META )
1368 || lsmash_check_box_type_identical( parent->type, QT_BOX_TYPE_META ) )
1369 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( dinf, isom_meta_t );
1370 else
1371 assert( 0 );
1372 return dinf;
1375 isom_dref_entry_t *isom_add_dref_entry( isom_dref_t *dref, lsmash_box_type_t type )
1377 if( LSMASH_IS_NON_EXISTING_BOX( dref ) )
1378 return isom_non_existing_dref_entry();
1379 isom_dref_entry_t *dref_entry = ALLOCATE_BOX( dref_entry );
1380 if( LSMASH_IS_NON_EXISTING_BOX( dref_entry ) )
1381 return dref_entry;
1382 isom_init_box_common( dref_entry, dref, type, LSMASH_BOX_PRECEDENCE_ISOM_DREF_ENTRY, isom_remove_dref_entry );
1383 if( isom_add_box_to_extension_list( dref, dref_entry ) < 0 )
1385 lsmash_free( dref_entry );
1386 return isom_non_existing_dref_entry();
1388 if( lsmash_list_add_entry( &dref->list, dref_entry ) < 0 )
1390 lsmash_list_remove_entry_tail( &dref->extensions );
1391 return isom_non_existing_dref_entry();
1393 dref_entry->offset_in_parent = offsetof( isom_dref_t, list );
1394 return dref_entry;
1397 DEFINE_SIMPLE_BOX_ADDER( isom_add_dref, dref, dinf, ISOM_BOX_TYPE_DREF, LSMASH_BOX_PRECEDENCE_ISOM_DREF )
1398 DEFINE_SIMPLE_BOX_ADDER( isom_add_stbl, stbl, minf, ISOM_BOX_TYPE_STBL, LSMASH_BOX_PRECEDENCE_ISOM_STBL )
1399 DEFINE_SIMPLE_BOX_ADDER( isom_add_stsd, stsd, stbl, ISOM_BOX_TYPE_STSD, LSMASH_BOX_PRECEDENCE_ISOM_STSD )
1401 static void *isom_add_sample_description_entry
1403 isom_stsd_t *stsd,
1404 void *description
1407 assert( description );
1408 if( isom_add_box_to_extension_list( stsd, description ) < 0 )
1410 isom_remove_box_by_itself( description );
1411 return description;
1413 if( lsmash_list_add_entry( &stsd->list, description ) < 0 )
1415 lsmash_list_remove_entry_tail( &stsd->extensions );
1416 return description;
1418 ((isom_box_t *)description)->offset_in_parent = offsetof( isom_stsd_t, list );
1419 return description;
1422 isom_visual_entry_t *isom_add_visual_description( isom_stsd_t *stsd, lsmash_codec_type_t sample_type )
1424 assert( LSMASH_IS_EXISTING_BOX( stsd ) );
1425 isom_visual_entry_t *visual = ALLOCATE_BOX( visual_entry );
1426 if( LSMASH_IS_NON_EXISTING_BOX( visual ) )
1427 return visual;
1428 isom_init_box_common( visual, stsd, sample_type, LSMASH_BOX_PRECEDENCE_HM, isom_remove_visual_description );
1429 visual->manager |= LSMASH_VIDEO_DESCRIPTION;
1430 return isom_add_sample_description_entry( stsd, visual );
1433 isom_audio_entry_t *isom_add_audio_description( isom_stsd_t *stsd, lsmash_codec_type_t sample_type )
1435 assert( LSMASH_IS_EXISTING_BOX( stsd ) );
1436 isom_audio_entry_t *audio = ALLOCATE_BOX( audio_entry );
1437 if( LSMASH_IS_NON_EXISTING_BOX( audio ) )
1438 return audio;
1439 isom_init_box_common( audio, stsd, sample_type, LSMASH_BOX_PRECEDENCE_HM, isom_remove_audio_description );
1440 audio->manager |= LSMASH_AUDIO_DESCRIPTION;
1441 return isom_add_sample_description_entry( stsd, audio );
1444 isom_hint_entry_t *isom_add_hint_description( isom_stsd_t *stsd, lsmash_codec_type_t sample_type )
1446 assert( stsd );
1447 isom_hint_entry_t *hint = ALLOCATE_BOX( hint_entry );
1448 if ( LSMASH_IS_NON_EXISTING_BOX( hint ) )
1449 return hint;
1450 isom_init_box_common( hint, stsd, sample_type, LSMASH_BOX_PRECEDENCE_HM, isom_remove_hint_description );
1451 return isom_add_sample_description_entry( stsd, hint );
1454 isom_qt_text_entry_t *isom_add_qt_text_description( isom_stsd_t *stsd )
1456 assert( LSMASH_IS_EXISTING_BOX( stsd ) );
1457 isom_qt_text_entry_t *text = ALLOCATE_BOX( qt_text_entry );
1458 if( LSMASH_IS_NON_EXISTING_BOX( text ) )
1459 return text;
1460 isom_init_box_common( text, stsd, QT_CODEC_TYPE_TEXT_TEXT, LSMASH_BOX_PRECEDENCE_HM, isom_remove_qt_text_description );
1461 return isom_add_sample_description_entry( stsd, text );
1464 isom_tx3g_entry_t *isom_add_tx3g_description( isom_stsd_t *stsd )
1466 assert( LSMASH_IS_EXISTING_BOX( stsd ) );
1467 isom_tx3g_entry_t *tx3g = ALLOCATE_BOX( tx3g_entry );
1468 if( LSMASH_IS_NON_EXISTING_BOX( tx3g ) )
1469 return tx3g;
1470 isom_init_box_common( tx3g, stsd, ISOM_CODEC_TYPE_TX3G_TEXT, LSMASH_BOX_PRECEDENCE_HM, isom_remove_tx3g_description );
1471 return isom_add_sample_description_entry( stsd, tx3g );
1474 isom_esds_t *isom_add_esds( void *parent_box )
1476 isom_box_t *parent = (isom_box_t *)parent_box;
1477 int is_qt = lsmash_check_box_type_identical( parent->type, QT_BOX_TYPE_WAVE );
1478 lsmash_box_type_t box_type = is_qt ? QT_BOX_TYPE_ESDS : ISOM_BOX_TYPE_ESDS;
1479 uint64_t precedence = is_qt ? LSMASH_BOX_PRECEDENCE_QTFF_ESDS : LSMASH_BOX_PRECEDENCE_ISOM_ESDS;
1480 CREATE_BOX( esds, parent, box_type, precedence, 1 );
1481 return esds;
1484 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_glbl, glbl, parent_box, QT_BOX_TYPE_GLBL, LSMASH_BOX_PRECEDENCE_QTFF_GLBL, 1, void )
1485 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_clap, clap, visual, ISOM_BOX_TYPE_CLAP, LSMASH_BOX_PRECEDENCE_ISOM_CLAP, 0, isom_visual_entry_t )
1486 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_pasp, pasp, visual, ISOM_BOX_TYPE_PASP, LSMASH_BOX_PRECEDENCE_ISOM_PASP, 0, isom_visual_entry_t )
1487 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_colr, colr, visual, ISOM_BOX_TYPE_COLR, LSMASH_BOX_PRECEDENCE_ISOM_COLR, 0, isom_visual_entry_t )
1488 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_gama, gama, visual, QT_BOX_TYPE_GAMA, LSMASH_BOX_PRECEDENCE_QTFF_GAMA, 0, isom_visual_entry_t )
1489 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_fiel, fiel, visual, QT_BOX_TYPE_FIEL, LSMASH_BOX_PRECEDENCE_QTFF_FIEL, 0, isom_visual_entry_t )
1490 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_clli, clli, visual, QT_BOX_TYPE_CLLI, LSMASH_BOX_PRECEDENCE_QTFF_CLLI, 0, isom_visual_entry_t )
1491 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_mdcv, mdcv, visual, QT_BOX_TYPE_MDCV, LSMASH_BOX_PRECEDENCE_QTFF_MDCV, 0, isom_visual_entry_t )
1492 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_cspc, cspc, visual, QT_BOX_TYPE_CSPC, LSMASH_BOX_PRECEDENCE_QTFF_CSPC, 0, isom_visual_entry_t )
1493 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_sgbt, sgbt, visual, QT_BOX_TYPE_SGBT, LSMASH_BOX_PRECEDENCE_QTFF_SGBT, 0, isom_visual_entry_t )
1494 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_stsl, stsl, visual, ISOM_BOX_TYPE_STSL, LSMASH_BOX_PRECEDENCE_ISOM_STSL, 0, isom_visual_entry_t )
1495 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_btrt, btrt, visual, ISOM_BOX_TYPE_BTRT, LSMASH_BOX_PRECEDENCE_ISOM_BTRT, 0, isom_visual_entry_t )
1496 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_wave, wave, audio, QT_BOX_TYPE_WAVE, LSMASH_BOX_PRECEDENCE_QTFF_WAVE, 0, isom_audio_entry_t )
1497 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_chan, chan, audio, QT_BOX_TYPE_CHAN, LSMASH_BOX_PRECEDENCE_QTFF_CHAN, 1, isom_audio_entry_t )
1498 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_srat, srat, audio, ISOM_BOX_TYPE_SRAT, LSMASH_BOX_PRECEDENCE_ISOM_SRAT, 0, isom_audio_entry_t )
1499 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_tims, tims, hint, ISOM_BOX_TYPE_TIMS, LSMASH_BOX_PRECEDENCE_ISOM_TIMS, 0, isom_hint_entry_t )
1500 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_tsro, tsro, hint, ISOM_BOX_TYPE_TSRO, LSMASH_BOX_PRECEDENCE_ISOM_TSRO, 0, isom_hint_entry_t )
1501 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_tssy, tssy, hint, ISOM_BOX_TYPE_TSSY, LSMASH_BOX_PRECEDENCE_ISOM_TSSY, 0, isom_hint_entry_t )
1503 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_stts, stts, stbl, ISOM_BOX_TYPE_STTS, LSMASH_BOX_PRECEDENCE_ISOM_STTS )
1504 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_ctts, ctts, stbl, ISOM_BOX_TYPE_CTTS, LSMASH_BOX_PRECEDENCE_ISOM_CTTS )
1505 DEFINE_SIMPLE_BOX_ADDER ( isom_add_cslg, cslg, stbl, ISOM_BOX_TYPE_CSLG, LSMASH_BOX_PRECEDENCE_ISOM_CSLG )
1506 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_stsc, stsc, stbl, ISOM_BOX_TYPE_STSC, LSMASH_BOX_PRECEDENCE_ISOM_STSC )
1507 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. */
1508 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_stz2, stz2, stbl, ISOM_BOX_TYPE_STZ2, LSMASH_BOX_PRECEDENCE_ISOM_STZ2 )
1509 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_stss, stss, stbl, ISOM_BOX_TYPE_STSS, LSMASH_BOX_PRECEDENCE_ISOM_STSS )
1510 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_stps, stps, stbl, QT_BOX_TYPE_STPS, LSMASH_BOX_PRECEDENCE_QTFF_STPS )
1512 isom_stco_t *isom_add_stco( isom_stbl_t *stbl )
1514 ADD_LIST_BOX( stco, stbl, ISOM_BOX_TYPE_STCO, LSMASH_BOX_PRECEDENCE_ISOM_STCO );
1515 stco->large_presentation = 0;
1516 return stco;
1519 isom_stco_t *isom_add_co64( isom_stbl_t *stbl )
1521 ADD_LIST_BOX( stco, stbl, ISOM_BOX_TYPE_CO64, LSMASH_BOX_PRECEDENCE_ISOM_CO64 );
1522 stco->large_presentation = 1;
1523 return stco;
1526 isom_sdtp_t *isom_add_sdtp( isom_box_t *parent )
1528 if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
1529 return isom_non_existing_sdtp();
1530 if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_STBL ) )
1532 isom_stbl_t *stbl = (isom_stbl_t *)parent;
1533 ADD_LIST_BOX( sdtp, stbl, ISOM_BOX_TYPE_SDTP, LSMASH_BOX_PRECEDENCE_ISOM_SDTP );
1534 return sdtp;
1536 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_TRAF ) )
1538 isom_traf_t *traf = (isom_traf_t *)parent;
1539 ADD_LIST_BOX( sdtp, traf, ISOM_BOX_TYPE_SDTP, LSMASH_BOX_PRECEDENCE_ISOM_SDTP );
1540 return sdtp;
1542 assert( 0 );
1543 return isom_non_existing_sdtp();
1546 isom_sgpd_t *isom_add_sgpd( void *parent_box )
1548 isom_box_t *parent = (isom_box_t *)parent_box;
1549 if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
1550 return isom_non_existing_sgpd();
1551 if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_STBL ) )
1553 isom_stbl_t *stbl = (isom_stbl_t *)parent;
1554 ADD_LIST_BOX_IN_LIST( sgpd, stbl, ISOM_BOX_TYPE_SGPD, LSMASH_BOX_PRECEDENCE_ISOM_SGPD );
1555 return sgpd;
1557 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_TRAF ) )
1559 isom_traf_t *traf = (isom_traf_t *)parent;
1560 ADD_LIST_BOX_IN_LIST( sgpd, traf, ISOM_BOX_TYPE_SGPD, LSMASH_BOX_PRECEDENCE_ISOM_SGPD );
1561 return sgpd;
1563 assert( 0 );
1564 return isom_non_existing_sgpd();
1567 isom_sbgp_t *isom_add_sbgp( void *parent_box )
1569 isom_box_t *parent = (isom_box_t *)parent_box;
1570 if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
1571 return isom_non_existing_sbgp();
1572 if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_STBL ) )
1574 isom_stbl_t *stbl = (isom_stbl_t *)parent;
1575 ADD_LIST_BOX_IN_LIST( sbgp, stbl, ISOM_BOX_TYPE_SBGP, LSMASH_BOX_PRECEDENCE_ISOM_SBGP );
1576 return sbgp;
1578 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_TRAF ) )
1580 isom_traf_t *traf = (isom_traf_t *)parent;
1581 ADD_LIST_BOX_IN_LIST( sbgp, traf, ISOM_BOX_TYPE_SBGP, LSMASH_BOX_PRECEDENCE_ISOM_SBGP );
1582 return sbgp;
1584 assert( 0 );
1585 return isom_non_existing_sbgp();
1588 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_chpl, chpl, udta, ISOM_BOX_TYPE_CHPL, LSMASH_BOX_PRECEDENCE_ISOM_CHPL )
1590 isom_metaitem_t *isom_add_metaitem( isom_ilst_t *ilst, lsmash_itunes_metadata_item item )
1592 if( LSMASH_IS_NON_EXISTING_BOX( ilst ) )
1593 return isom_non_existing_metaitem();
1594 lsmash_box_type_t type = lsmash_form_iso_box_type( item );
1595 ADD_BOX_IN_LIST( metaitem, ilst, type, LSMASH_BOX_PRECEDENCE_ISOM_METAITEM );
1596 return metaitem;
1599 DEFINE_SIMPLE_BOX_ADDER ( isom_add_mean, mean, metaitem, ISOM_BOX_TYPE_MEAN, LSMASH_BOX_PRECEDENCE_ISOM_MEAN )
1600 DEFINE_SIMPLE_BOX_ADDER ( isom_add_name, name, metaitem, ISOM_BOX_TYPE_NAME, LSMASH_BOX_PRECEDENCE_ISOM_NAME )
1601 DEFINE_SIMPLE_BOX_ADDER ( isom_add_data, data, metaitem, ISOM_BOX_TYPE_DATA, LSMASH_BOX_PRECEDENCE_ISOM_DATA )
1602 DEFINE_SIMPLE_BOX_ADDER ( isom_add_ilst, ilst, meta, ISOM_BOX_TYPE_ILST, LSMASH_BOX_PRECEDENCE_ISOM_ILST )
1603 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_keys, keys, meta, QT_BOX_TYPE_KEYS, LSMASH_BOX_PRECEDENCE_QTFF_KEYS )
1605 isom_meta_t *isom_add_meta( void *parent_box )
1607 isom_box_t *parent = (isom_box_t *)parent_box;
1608 if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
1609 return isom_non_existing_meta();
1610 CREATE_BOX( meta, parent, ISOM_BOX_TYPE_META, LSMASH_BOX_PRECEDENCE_ISOM_META, 1 );
1611 if( parent->file == (lsmash_file_t *)parent )
1612 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( meta, lsmash_file_t );
1613 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_MOOV ) )
1614 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( meta, isom_moov_t );
1615 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_TRAK ) )
1616 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( meta, isom_trak_t );
1617 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_UDTA ) )
1618 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( meta, isom_udta_t );
1619 else
1620 assert( 0 );
1621 return meta;
1624 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_cprt, cprt, udta, ISOM_BOX_TYPE_CPRT, LSMASH_BOX_PRECEDENCE_ISOM_CPRT )
1625 DEFINE_SIMPLE_BOX_ADDER( isom_add_hnti, hnti, udta, ISOM_BOX_TYPE_HNTI, LSMASH_BOX_PRECEDENCE_ISOM_HNTI )
1626 DEFINE_SIMPLE_BOX_ADDER( isom_add_rtp, rtp, hnti, ISOM_BOX_TYPE_RTP, LSMASH_BOX_PRECEDENCE_ISOM_RTP )
1627 DEFINE_SIMPLE_BOX_ADDER( isom_add_sdp, sdp, hnti, ISOM_BOX_TYPE_SDP, LSMASH_BOX_PRECEDENCE_ISOM_SDP )
1629 isom_udta_t *isom_add_udta( void *parent_box )
1631 isom_box_t *parent = (isom_box_t *)parent_box;
1632 if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
1633 return isom_non_existing_udta();
1634 if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_MOOV ) )
1636 isom_moov_t *moov = (isom_moov_t *)parent;
1637 ADD_BOX( udta, moov, ISOM_BOX_TYPE_UDTA, LSMASH_BOX_PRECEDENCE_ISOM_UDTA );
1638 return udta;
1640 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_TRAK ) )
1642 isom_trak_t *trak = (isom_trak_t *)parent;
1643 ADD_BOX( udta, trak, ISOM_BOX_TYPE_UDTA, LSMASH_BOX_PRECEDENCE_ISOM_UDTA );
1644 return udta;
1646 assert( 0 );
1647 return isom_non_existing_udta();
1650 DEFINE_SIMPLE_BOX_ADDER ( isom_add_WLOC, WLOC, udta, QT_BOX_TYPE_WLOC, LSMASH_BOX_PRECEDENCE_QTFF_WLOC )
1651 DEFINE_SIMPLE_BOX_ADDER ( isom_add_LOOP, LOOP, udta, QT_BOX_TYPE_LOOP, LSMASH_BOX_PRECEDENCE_QTFF_LOOP )
1652 DEFINE_SIMPLE_BOX_ADDER ( isom_add_SelO, SelO, udta, QT_BOX_TYPE_SELO, LSMASH_BOX_PRECEDENCE_QTFF_SELO )
1653 DEFINE_SIMPLE_BOX_ADDER ( isom_add_AllF, AllF, udta, QT_BOX_TYPE_ALLF, LSMASH_BOX_PRECEDENCE_QTFF_ALLF )
1654 DEFINE_SIMPLE_BOX_ADDER ( isom_add_mvex, mvex, moov, ISOM_BOX_TYPE_MVEX, LSMASH_BOX_PRECEDENCE_ISOM_MVEX )
1655 DEFINE_SIMPLE_BOX_ADDER ( isom_add_mehd, mehd, mvex, ISOM_BOX_TYPE_MEHD, LSMASH_BOX_PRECEDENCE_ISOM_MEHD )
1656 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_trex, trex, mvex, ISOM_BOX_TYPE_TREX, LSMASH_BOX_PRECEDENCE_ISOM_TREX )
1657 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_moof, moof, file_abstract, ISOM_BOX_TYPE_MOOF, LSMASH_BOX_PRECEDENCE_ISOM_MOOF )
1658 DEFINE_SIMPLE_BOX_ADDER ( isom_add_mfhd, mfhd, moof, ISOM_BOX_TYPE_MFHD, LSMASH_BOX_PRECEDENCE_ISOM_MFHD )
1659 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_traf, traf, moof, ISOM_BOX_TYPE_TRAF, LSMASH_BOX_PRECEDENCE_ISOM_TRAF )
1660 DEFINE_SIMPLE_BOX_ADDER ( isom_add_tfhd, tfhd, traf, ISOM_BOX_TYPE_TFHD, LSMASH_BOX_PRECEDENCE_ISOM_TFHD )
1661 DEFINE_SIMPLE_BOX_ADDER ( isom_add_tfdt, tfdt, traf, ISOM_BOX_TYPE_TFDT, LSMASH_BOX_PRECEDENCE_ISOM_TFDT )
1662 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_trun, trun, traf, ISOM_BOX_TYPE_TRUN, LSMASH_BOX_PRECEDENCE_ISOM_TRUN )
1663 DEFINE_SIMPLE_BOX_ADDER ( isom_add_mfra, mfra, file_abstract, ISOM_BOX_TYPE_MFRA, LSMASH_BOX_PRECEDENCE_ISOM_MFRA )
1664 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_tfra, tfra, mfra, ISOM_BOX_TYPE_TFRA, LSMASH_BOX_PRECEDENCE_ISOM_TFRA )
1665 DEFINE_SIMPLE_BOX_ADDER ( isom_add_mfro, mfro, mfra, ISOM_BOX_TYPE_MFRO, LSMASH_BOX_PRECEDENCE_ISOM_MFRO )
1667 isom_mdat_t *isom_add_mdat( isom_file_abstract_t *file )
1669 assert( LSMASH_IS_NON_EXISTING_BOX( file->mdat ) );
1670 CREATE_BOX( mdat, file, ISOM_BOX_TYPE_MDAT, LSMASH_BOX_PRECEDENCE_ISOM_MDAT, 1 );
1671 file->mdat = mdat;
1672 return mdat;
1675 isom_free_t *isom_add_free( void *parent_box )
1677 isom_box_t *parent = (isom_box_t *)parent_box;
1678 if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
1679 return isom_non_existing_skip();
1680 CREATE_BOX( skip, parent, ISOM_BOX_TYPE_FREE, LSMASH_BOX_PRECEDENCE_ISOM_FREE, 1 );
1681 return skip;
1684 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_styp, styp, file_abstract, ISOM_BOX_TYPE_STYP, LSMASH_BOX_PRECEDENCE_ISOM_STYP )
1686 isom_sidx_t *isom_add_sidx( isom_file_abstract_t *file_abstract )
1688 ADD_LIST_BOX_IN_LIST( sidx, file_abstract, ISOM_BOX_TYPE_SIDX, LSMASH_BOX_PRECEDENCE_ISOM_SIDX );
1689 return sidx;
1692 #undef ATTACH_EXACTLY_ONE_BOX_TO_PARENT
1693 #undef CREATE_BOX
1694 #undef CREATE_LIST_BOX
1695 #undef ADD_BOX_TEMPLATE
1696 #undef ADD_BOX_IN_LIST_TEMPLATE
1697 #undef ADD_BOX
1698 #undef ADD_BOX_IN_LIST
1699 #undef ADD_LIST_BOX
1700 #undef ADD_LIST_BOX_IN_LIST
1701 #undef DEFINE_SIMPLE_BOX_ADDER_TEMPLATE
1702 #undef DEFINE_SIMPLE_BOX_ADDER_TEMPLATE_6
1703 #undef DEFINE_SIMPLE_BOX_ADDER_TEMPLATE_5
1704 #undef DEFINE_SIMPLE_BOX_ADDER
1705 #undef DEFINE_SIMPLE_BOX_IN_LIST_ADDER
1706 #undef DEFINE_SIMPLE_LIST_BOX_ADDER
1708 static int fake_file_read
1710 void *opaque,
1711 uint8_t *buf,
1712 int size
1715 fake_file_stream_t *stream = (fake_file_stream_t *)opaque;
1716 int read_size;
1717 if( stream->pos + size > stream->size )
1718 read_size = stream->size - stream->pos;
1719 else
1720 read_size = size;
1721 memcpy( buf, stream->data + stream->pos, read_size );
1722 stream->pos += read_size;
1723 return read_size;
1726 static int64_t fake_file_seek
1728 void *opaque,
1729 int64_t offset,
1730 int whence
1733 fake_file_stream_t *stream = (fake_file_stream_t *)opaque;
1734 if( whence == SEEK_SET )
1735 stream->pos = offset;
1736 else if( whence == SEEK_CUR )
1737 stream->pos += offset;
1738 else if( whence == SEEK_END )
1739 stream->pos = stream->size + offset;
1740 return stream->pos;
1743 /* Public functions */
1744 lsmash_root_t *lsmash_create_root( void )
1746 lsmash_root_t *root = ALLOCATE_BOX( root_abstract );
1747 if( LSMASH_IS_NON_EXISTING_BOX( root ) )
1748 return NULL;
1749 root->root = root;
1750 return root;
1753 void lsmash_destroy_root( lsmash_root_t *root )
1755 isom_remove_box_by_itself( root );
1758 lsmash_extended_box_type_t lsmash_form_extended_box_type( uint32_t fourcc, const uint8_t id[12] )
1760 return (lsmash_extended_box_type_t){ fourcc, { id[0], id[1], id[2], id[3], id[4], id[5],
1761 id[6], id[7], id[8], id[9], id[10], id[11] } };
1764 lsmash_box_type_t lsmash_form_box_type
1766 lsmash_compact_box_type_t type,
1767 lsmash_extended_box_type_t user
1770 return (lsmash_box_type_t){ type, user };
1773 lsmash_box_type_t lsmash_form_iso_box_type( uint32_t fourcc )
1775 return (lsmash_box_type_t){ fourcc, lsmash_form_extended_box_type( fourcc, LSMASH_ISO_12_BYTES ) };
1778 lsmash_box_type_t lsmash_form_qtff_box_type( uint32_t fourcc )
1780 return (lsmash_box_type_t){ fourcc, lsmash_form_extended_box_type( fourcc, LSMASH_QTFF_12_BYTES ) };
1783 #define CHECK_BOX_TYPE_IDENTICAL( a, b ) \
1784 a.fourcc == b.fourcc \
1785 && a.user.fourcc == b.user.fourcc \
1786 && a.user.id[0] == b.user.id[0] \
1787 && a.user.id[1] == b.user.id[1] \
1788 && a.user.id[2] == b.user.id[2] \
1789 && a.user.id[3] == b.user.id[3] \
1790 && a.user.id[4] == b.user.id[4] \
1791 && a.user.id[5] == b.user.id[5] \
1792 && a.user.id[6] == b.user.id[6] \
1793 && a.user.id[7] == b.user.id[7] \
1794 && a.user.id[8] == b.user.id[8] \
1795 && a.user.id[9] == b.user.id[9] \
1796 && a.user.id[10] == b.user.id[10] \
1797 && a.user.id[11] == b.user.id[11]
1799 int lsmash_check_box_type_identical( lsmash_box_type_t a, lsmash_box_type_t b )
1801 return CHECK_BOX_TYPE_IDENTICAL( a, b );
1804 int lsmash_check_codec_type_identical( lsmash_codec_type_t a, lsmash_codec_type_t b )
1806 return CHECK_BOX_TYPE_IDENTICAL( a, b );
1809 int lsmash_check_box_type_specified( const lsmash_box_type_t *box_type )
1811 assert( box_type );
1812 if( !box_type )
1813 return 0;
1814 return !!(box_type->fourcc
1815 | box_type->user.fourcc
1816 | box_type->user.id[0] | box_type->user.id[1] | box_type->user.id[2] | box_type->user.id[3]
1817 | box_type->user.id[4] | box_type->user.id[5] | box_type->user.id[6] | box_type->user.id[7]
1818 | box_type->user.id[8] | box_type->user.id[9] | box_type->user.id[10] | box_type->user.id[11]);
1821 lsmash_box_t *lsmash_get_box
1823 lsmash_box_t *parent,
1824 const lsmash_box_path_t box_path[]
1827 lsmash_entry_t *entry = isom_get_entry_of_box( parent, box_path );
1828 return (lsmash_box_t *)(entry ? entry->data : NULL);
1831 lsmash_box_t *lsmash_create_box
1833 lsmash_box_type_t type,
1834 uint8_t *data,
1835 uint32_t size,
1836 uint64_t precedence
1839 if( !lsmash_check_box_type_specified( &type ) )
1840 return NULL;
1841 isom_unknown_box_t *box = ALLOCATE_BOX( unknown );
1842 if( LSMASH_IS_NON_EXISTING_BOX( box ) )
1843 return NULL;
1844 if( size && data )
1846 box->unknown_size = size;
1847 box->unknown_field = lsmash_memdup( data, size );
1848 if( !box->unknown_field )
1850 lsmash_free( box );
1851 return NULL;
1854 else
1856 box->unknown_size = 0;
1857 box->unknown_field = NULL;
1858 size = 0;
1860 box->class = &lsmash_box_class;
1861 box->root = isom_non_existing_root_abstract();
1862 box->file = isom_non_existing_file_abstract();
1863 box->parent = (isom_box_t *)isom_non_existing_unknown();
1864 box->destruct = (isom_extension_destructor_t)isom_remove_unknown_box;
1865 box->manager = LSMASH_UNKNOWN_BOX;
1866 box->precedence = precedence;
1867 box->size = ISOM_BASEBOX_COMMON_SIZE + size + (type.fourcc == ISOM_BOX_TYPE_UUID.fourcc ? 16 : 0);
1868 box->type = type;
1869 isom_set_box_writer( (isom_box_t *)box );
1870 return (lsmash_box_t *)box;
1873 int lsmash_add_box
1875 lsmash_box_t *parent,
1876 lsmash_box_t *box
1879 if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
1880 /* You cannot add any box without a box being its parent. */
1881 return LSMASH_ERR_FUNCTION_PARAM;
1882 if( LSMASH_IS_NON_EXISTING_BOX( box ) || box->size < ISOM_BASEBOX_COMMON_SIZE )
1883 return LSMASH_ERR_FUNCTION_PARAM;
1884 if( parent->root == (lsmash_root_t *)parent )
1886 /* Only files can be added into any ROOT.
1887 * For backward compatibility, use the active file as the parent. */
1888 if( LSMASH_IS_EXISTING_BOX( parent->file ) )
1889 parent = (isom_box_t *)parent->file;
1890 else
1891 return LSMASH_ERR_FUNCTION_PARAM;
1893 /* Add a box as a child box. */
1894 box->class = &lsmash_box_class;
1895 box->root = parent->root;
1896 box->file = parent->file;
1897 box->parent = parent;
1898 return isom_add_box_to_extension_list( parent, box );
1901 int lsmash_add_box_ex
1903 lsmash_box_t *parent,
1904 lsmash_box_t **p_box
1907 if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
1908 /* You cannot add any box without a box being its parent. */
1909 return LSMASH_ERR_FUNCTION_PARAM;
1910 isom_unknown_box_t *box = (isom_unknown_box_t *)*p_box;
1911 if( LSMASH_IS_NON_EXISTING_BOX( box ) || box->size < ISOM_BASEBOX_COMMON_SIZE )
1912 return LSMASH_ERR_FUNCTION_PARAM;
1913 if( !(box->manager & LSMASH_UNKNOWN_BOX) )
1914 /* Simply add the box. */
1915 return lsmash_add_box( parent, *p_box );
1916 /* Check if the size of the box to be added is valid. */
1917 if( box->size != ISOM_BASEBOX_COMMON_SIZE + box->unknown_size + (box->type.fourcc == ISOM_BOX_TYPE_UUID.fourcc ? 16 : 0) )
1918 return LSMASH_ERR_FUNCTION_PARAM;
1919 if( LSMASH_IS_NON_EXISTING_BOX( parent->file ) || parent->file == (lsmash_file_t *)box )
1920 return LSMASH_ERR_FUNCTION_PARAM;
1921 if( parent->root == (lsmash_root_t *)parent )
1922 /* Only files can be added into any ROOT.
1923 * For backward compatibility, use the active file as the parent. */
1924 parent = (isom_box_t *)parent->file;
1925 /* Switch to the fake-file stream mode. */
1926 lsmash_file_t *file = parent->file;
1927 lsmash_bs_t *bs_backup = file->bs;
1928 lsmash_bs_t *bs = lsmash_bs_create();
1929 if( !bs )
1930 return LSMASH_ERR_MEMORY_ALLOC;
1931 uint8_t *buf = lsmash_malloc( box->size );
1932 if( !buf )
1934 lsmash_bs_cleanup( bs );
1935 return LSMASH_ERR_MEMORY_ALLOC;
1937 fake_file_stream_t fake_file =
1939 .size = box->size,
1940 .data = buf,
1941 .pos = 0
1943 bs->stream = &fake_file;
1944 bs->read = fake_file_read;
1945 bs->write = NULL;
1946 bs->seek = fake_file_seek;
1947 file->bs = bs;
1948 file->fake_file_mode = 1;
1949 /* Make the byte string representing the given box. */
1950 LSMASH_SET_BE32( &buf[0], box->size );
1951 LSMASH_SET_BE32( &buf[4], box->type.fourcc );
1952 if( box->type.fourcc == ISOM_BOX_TYPE_UUID.fourcc )
1954 LSMASH_SET_BE32( &buf[8], box->type.user.fourcc );
1955 memcpy( &buf[12], box->type.user.id, 12 );
1957 memcpy( buf + (uintptr_t)(box->size - box->unknown_size), box->unknown_field, box->unknown_size );
1958 /* Add a box as a child box and try to expand into struct format. */
1959 lsmash_box_t dummy = { 0 };
1960 int ret = isom_read_box( file, &dummy, parent, 0, 0 );
1961 lsmash_free( buf );
1962 lsmash_bs_cleanup( bs );
1963 file->bs = bs_backup; /* Switch back to the normal file stream mode. */
1964 file->fake_file_mode = 0;
1965 if( ret < 0 )
1966 return ret;
1967 /* Reorder the added box by 'precedence'. */
1968 *p_box = (lsmash_box_t *)parent->extensions.tail->data;
1969 (*p_box)->precedence = box->precedence;
1970 isom_reorder_tail_box( parent );
1971 /* Do also its children by the same way. */
1972 lsmash_entry_list_t extensions = box->extensions;
1973 lsmash_list_init_simple( &box->extensions ); /* to avoid freeing the children */
1974 isom_remove_box_by_itself( box );
1975 for( lsmash_entry_t *entry = extensions.head; entry; entry = entry->next )
1977 if( !entry->data )
1978 continue;
1979 lsmash_box_t *child = (lsmash_box_t *)entry->data;
1980 if( lsmash_add_box_ex( *p_box, &child ) == 0 )
1982 (*p_box)->size += child->size;
1983 /* Avoid freeing at the end of this function. */
1984 entry->data = NULL;
1987 isom_remove_all_extension_boxes( &extensions );
1988 return 0;
1991 void lsmash_destroy_box
1993 lsmash_box_t *box
1996 isom_remove_box_by_itself( box );
1999 void lsmash_destroy_children
2001 lsmash_box_t *box
2004 if( LSMASH_IS_EXISTING_BOX( box ) )
2005 isom_remove_all_extension_boxes( &box->extensions );
2008 int lsmash_get_box_precedence
2010 lsmash_box_t *box,
2011 uint64_t *precedence
2014 if( !box || !precedence )
2015 return LSMASH_ERR_FUNCTION_PARAM;
2016 *precedence = box->precedence;
2017 return 0;
2020 lsmash_box_t *lsmash_root_as_box
2022 lsmash_root_t *root
2025 return (lsmash_box_t *)root;
2028 lsmash_box_t *lsmash_file_as_box
2030 lsmash_file_t *file
2033 return (lsmash_box_t *)file;
2036 int lsmash_write_top_level_box
2038 lsmash_box_t *box
2041 if( !box || (isom_box_t *)box->file != box->parent )
2042 return LSMASH_ERR_FUNCTION_PARAM;
2043 int ret = isom_write_box( box->file->bs, box );
2044 if( ret < 0 )
2045 return ret;
2046 box->file->size += box->size;
2047 return 0;
2050 uint8_t *lsmash_export_box
2052 lsmash_box_t *box,
2053 uint32_t *size
2056 if( !box || !size )
2057 return NULL;
2058 lsmash_bs_t *bs = lsmash_bs_create();
2059 if( !bs )
2060 return NULL;
2061 if( isom_write_box( bs, box ) < 0 )
2063 lsmash_bs_cleanup( bs );
2064 return NULL;
2066 *size = bs->buffer.store;
2067 uint8_t *data = bs->buffer.data;
2068 bs->buffer.data = NULL;
2069 lsmash_bs_cleanup( bs );
2070 return data;