h264: Fix infinite loop when series of byte stream end by
[L-SMASH.git] / core / box.c
blob63dabcffba7af9d6f65ee2cb9099e1bc7da2e155
1 /*****************************************************************************
2 * box.c:
3 *****************************************************************************
4 * Copyright (C) 2012-2014 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 #ifdef LSMASH_DEMUXER_ENABLED
32 #include "print.h"
33 #include "timeline.h"
34 #endif
36 #include "codecs/mp4a.h"
37 #include "codecs/mp4sys.h"
39 #include "importer/importer.h"
41 static const lsmash_class_t lsmash_box_class =
43 "box"
46 const lsmash_box_type_t static_lsmash_box_type_unspecified = LSMASH_BOX_TYPE_INITIALIZER;
48 void isom_init_box_common_orig
50 void *_box,
51 void *_parent,
52 lsmash_box_type_t box_type,
53 uint64_t precedence,
54 isom_extension_destructor_t destructor
57 isom_box_t *box = (isom_box_t *)_box;
58 isom_box_t *parent = (isom_box_t *)_parent;
59 assert( box && parent && parent->root );
60 box->class = &lsmash_box_class;
61 box->root = parent->root;
62 box->file = parent->file;
63 box->parent = parent;
64 box->precedence = precedence;
65 box->destruct = destructor;
66 box->size = 0;
67 box->type = box_type;
68 if( !lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_STSD ) && isom_is_fullbox( box ) )
70 box->version = 0;
71 box->flags = 0;
73 isom_set_box_writer( box );
76 static void isom_reorder_tail_box( isom_box_t *parent )
78 /* Reorder the appended box by 'precedence'. */
79 lsmash_entry_t *x = parent->extensions.tail;
80 assert( x && x->data );
81 uint64_t precedence = ((isom_box_t *)x->data)->precedence;
82 for( lsmash_entry_t *y = x->prev; y; y = y->prev )
84 isom_box_t *box = (isom_box_t *)y->data;
85 if( !box || precedence > box->precedence )
87 /* Exchange the entity data of adjacent two entries. */
88 y->data = x->data;
89 x->data = box;
90 x = y;
92 else
93 break;
97 int isom_add_box_to_extension_list( void *parent_box, void *child_box )
99 assert( parent_box && child_box );
100 isom_box_t *parent = (isom_box_t *)parent_box;
101 isom_box_t *child = (isom_box_t *)child_box;
102 /* Append at the end of the list. */
103 if( lsmash_add_entry( &parent->extensions, child ) < 0 )
104 return LSMASH_ERR_MEMORY_ALLOC;
105 /* Don't reorder the appended box when the file is opened for reading. */
106 if( !parent->file || (parent->file->flags & LSMASH_FILE_MODE_READ) || parent->file->fake_file_mode )
107 return 0;
108 isom_reorder_tail_box( parent );
109 return 0;
112 void isom_bs_put_basebox_common( lsmash_bs_t *bs, isom_box_t *box )
114 if( box->size > UINT32_MAX )
116 lsmash_bs_put_be32( bs, 1 );
117 lsmash_bs_put_be32( bs, box->type.fourcc );
118 lsmash_bs_put_be64( bs, box->size ); /* largesize */
120 else
122 lsmash_bs_put_be32( bs, (uint32_t)box->size );
123 lsmash_bs_put_be32( bs, box->type.fourcc );
125 if( box->type.fourcc == ISOM_BOX_TYPE_UUID.fourcc )
127 lsmash_bs_put_be32( bs, box->type.user.fourcc );
128 lsmash_bs_put_bytes( bs, 12, box->type.user.id );
132 void isom_bs_put_fullbox_common( lsmash_bs_t *bs, isom_box_t *box )
134 isom_bs_put_basebox_common( bs, box );
135 lsmash_bs_put_byte( bs, box->version );
136 lsmash_bs_put_be24( bs, box->flags );
139 void isom_bs_put_box_common( lsmash_bs_t *bs, void *box )
141 if( !box )
143 bs->error = 1;
144 return;
146 isom_box_t *parent = ((isom_box_t *)box)->parent;
147 if( parent && lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_STSD ) )
149 isom_bs_put_basebox_common( bs, (isom_box_t *)box );
150 return;
152 if( isom_is_fullbox( box ) )
153 isom_bs_put_fullbox_common( bs, (isom_box_t *)box );
154 else
155 isom_bs_put_basebox_common( bs, (isom_box_t *)box );
158 /* Return 1 if the box is fullbox, Otherwise return 0. */
159 int isom_is_fullbox( void *box )
161 isom_box_t *current = (isom_box_t *)box;
162 lsmash_box_type_t type = current->type;
163 static lsmash_box_type_t fullbox_type_table[50] = { LSMASH_BOX_TYPE_INITIALIZER };
164 if( !lsmash_check_box_type_specified( &fullbox_type_table[0] ) )
166 /* Initialize the table. */
167 int i = 0;
168 fullbox_type_table[i++] = ISOM_BOX_TYPE_SIDX;
169 fullbox_type_table[i++] = ISOM_BOX_TYPE_MVHD;
170 fullbox_type_table[i++] = ISOM_BOX_TYPE_TKHD;
171 fullbox_type_table[i++] = ISOM_BOX_TYPE_IODS;
172 fullbox_type_table[i++] = ISOM_BOX_TYPE_ESDS;
173 fullbox_type_table[i++] = QT_BOX_TYPE_ESDS;
174 fullbox_type_table[i++] = QT_BOX_TYPE_CLEF;
175 fullbox_type_table[i++] = QT_BOX_TYPE_PROF;
176 fullbox_type_table[i++] = QT_BOX_TYPE_ENOF;
177 fullbox_type_table[i++] = ISOM_BOX_TYPE_ELST;
178 fullbox_type_table[i++] = ISOM_BOX_TYPE_MDHD;
179 fullbox_type_table[i++] = ISOM_BOX_TYPE_HDLR;
180 fullbox_type_table[i++] = ISOM_BOX_TYPE_VMHD;
181 fullbox_type_table[i++] = ISOM_BOX_TYPE_SMHD;
182 fullbox_type_table[i++] = ISOM_BOX_TYPE_HMHD;
183 fullbox_type_table[i++] = ISOM_BOX_TYPE_NMHD;
184 fullbox_type_table[i++] = QT_BOX_TYPE_GMIN;
185 fullbox_type_table[i++] = ISOM_BOX_TYPE_DREF;
186 fullbox_type_table[i++] = ISOM_BOX_TYPE_STSD;
187 fullbox_type_table[i++] = ISOM_BOX_TYPE_STSL;
188 fullbox_type_table[i++] = QT_BOX_TYPE_CHAN;
189 fullbox_type_table[i++] = ISOM_BOX_TYPE_SRAT;
190 fullbox_type_table[i++] = ISOM_BOX_TYPE_STTS;
191 fullbox_type_table[i++] = ISOM_BOX_TYPE_CTTS;
192 fullbox_type_table[i++] = ISOM_BOX_TYPE_CSLG;
193 fullbox_type_table[i++] = ISOM_BOX_TYPE_STSS;
194 fullbox_type_table[i++] = QT_BOX_TYPE_STPS;
195 fullbox_type_table[i++] = ISOM_BOX_TYPE_SDTP;
196 fullbox_type_table[i++] = ISOM_BOX_TYPE_STSC;
197 fullbox_type_table[i++] = ISOM_BOX_TYPE_STSZ;
198 fullbox_type_table[i++] = ISOM_BOX_TYPE_STCO;
199 fullbox_type_table[i++] = ISOM_BOX_TYPE_CO64;
200 fullbox_type_table[i++] = ISOM_BOX_TYPE_SGPD;
201 fullbox_type_table[i++] = ISOM_BOX_TYPE_SBGP;
202 fullbox_type_table[i++] = ISOM_BOX_TYPE_CHPL;
203 fullbox_type_table[i++] = ISOM_BOX_TYPE_META;
204 fullbox_type_table[i++] = QT_BOX_TYPE_KEYS;
205 fullbox_type_table[i++] = ISOM_BOX_TYPE_MEAN;
206 fullbox_type_table[i++] = ISOM_BOX_TYPE_NAME;
207 fullbox_type_table[i++] = ISOM_BOX_TYPE_MEHD;
208 fullbox_type_table[i++] = ISOM_BOX_TYPE_TREX;
209 fullbox_type_table[i++] = ISOM_BOX_TYPE_MFHD;
210 fullbox_type_table[i++] = ISOM_BOX_TYPE_TFHD;
211 fullbox_type_table[i++] = ISOM_BOX_TYPE_TFDT;
212 fullbox_type_table[i++] = ISOM_BOX_TYPE_TRUN;
213 fullbox_type_table[i++] = ISOM_BOX_TYPE_TFRA;
214 fullbox_type_table[i++] = ISOM_BOX_TYPE_MFRO;
215 fullbox_type_table[i] = LSMASH_BOX_TYPE_UNSPECIFIED;
217 for( int i = 0; lsmash_check_box_type_specified( &fullbox_type_table[i] ); i++ )
218 if( lsmash_check_box_type_identical( type, fullbox_type_table[i] ) )
219 return 1;
220 if( current->parent )
222 if( lsmash_check_box_type_identical( current->parent->type, ISOM_BOX_TYPE_DREF )
223 || (lsmash_check_box_type_identical( type, ISOM_BOX_TYPE_CPRT )
224 && lsmash_check_box_type_identical( current->parent->type, ISOM_BOX_TYPE_UDTA )) )
225 return 1;
227 return 0;
230 /* Return 1 if the sample type is LPCM audio, Otherwise return 0. */
231 int isom_is_lpcm_audio( void *box )
233 isom_box_t *current = (isom_box_t *)box;
234 lsmash_box_type_t type = current->type;
235 return lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_23NI_AUDIO )
236 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_NONE_AUDIO )
237 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_LPCM_AUDIO )
238 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_SOWT_AUDIO )
239 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_TWOS_AUDIO )
240 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_FL32_AUDIO )
241 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_FL64_AUDIO )
242 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_IN24_AUDIO )
243 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_IN32_AUDIO )
244 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_NOT_SPECIFIED )
245 || (lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_RAW_AUDIO ) && (current->manager & LSMASH_AUDIO_DESCRIPTION));
248 int isom_is_qt_audio( lsmash_codec_type_t type )
250 return lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_23NI_AUDIO )
251 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_MAC3_AUDIO )
252 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_MAC6_AUDIO )
253 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_NONE_AUDIO )
254 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_QDM2_AUDIO )
255 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_QDMC_AUDIO )
256 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_QCLP_AUDIO )
257 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_AC_3_AUDIO )
258 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_AGSM_AUDIO )
259 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ALAC_AUDIO )
260 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ALAW_AUDIO )
261 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_CDX2_AUDIO )
262 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_CDX4_AUDIO )
263 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVCA_AUDIO )
264 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVI_AUDIO )
265 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_FL32_AUDIO )
266 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_FL64_AUDIO )
267 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_IMA4_AUDIO )
268 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_IN24_AUDIO )
269 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_IN32_AUDIO )
270 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_LPCM_AUDIO )
271 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_MP4A_AUDIO )
272 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_RAW_AUDIO )
273 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_SOWT_AUDIO )
274 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_TWOS_AUDIO )
275 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ULAW_AUDIO )
276 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_VDVA_AUDIO )
277 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_FULLMP3_AUDIO )
278 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_MP3_AUDIO )
279 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ADPCM2_AUDIO )
280 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ADPCM17_AUDIO )
281 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_GSM49_AUDIO )
282 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_NOT_SPECIFIED );
285 /* Return 1 if the sample type is uncompressed Y'CbCr video, Otherwise return 0. */
286 int isom_is_uncompressed_ycbcr( lsmash_codec_type_t type )
288 return lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_2VUY_VIDEO )
289 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V210_VIDEO )
290 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V216_VIDEO )
291 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V308_VIDEO )
292 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V408_VIDEO )
293 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V410_VIDEO )
294 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_YUV2_VIDEO );
297 int isom_is_waveform_audio( lsmash_box_type_t type )
299 return lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ADPCM2_AUDIO )
300 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ADPCM17_AUDIO )
301 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_GSM49_AUDIO )
302 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_FULLMP3_AUDIO )
303 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_MP3_AUDIO );
306 size_t isom_skip_box_common( uint8_t **p_data )
308 uint8_t *orig = *p_data;
309 uint8_t *data = *p_data;
310 uint64_t size = LSMASH_GET_BE32( data );
311 data += ISOM_BASEBOX_COMMON_SIZE;
312 if( size == 1 )
314 size = LSMASH_GET_BE64( data );
315 data += 8;
317 *p_data = data;
318 return data - orig;
321 static void isom_destruct_extension_binary( void *ext )
323 if( !ext )
324 return;
325 isom_box_t *box = (isom_box_t *)ext;
326 lsmash_free( box->binary );
329 int isom_add_extension_binary
331 void *parent_box,
332 lsmash_box_type_t box_type,
333 uint64_t precedence,
334 uint8_t *box_data,
335 uint32_t box_size
338 if( !parent_box || !box_data || box_size < ISOM_BASEBOX_COMMON_SIZE
339 || !lsmash_check_box_type_specified( &box_type ) )
340 return LSMASH_ERR_FUNCTION_PARAM;
341 isom_box_t *ext = lsmash_malloc_zero( sizeof(isom_box_t) );
342 if( !ext )
343 return LSMASH_ERR_MEMORY_ALLOC;
344 isom_box_t *parent = (isom_box_t *)parent_box;
345 ext->class = &lsmash_box_class;
346 ext->root = parent->root;
347 ext->file = parent->file;
348 ext->parent = parent;
349 ext->manager = LSMASH_BINARY_CODED_BOX;
350 ext->precedence = precedence;
351 ext->size = box_size;
352 ext->type = box_type;
353 ext->binary = box_data;
354 ext->destruct = isom_destruct_extension_binary;
355 if( isom_add_box_to_extension_list( parent, ext ) < 0 )
357 lsmash_free( ext );
358 return LSMASH_ERR_MEMORY_ALLOC;
360 isom_set_box_writer( ext );
361 return 0;
364 static void isom_remove_extension_box( isom_box_t *ext )
366 if( !ext )
367 return;
368 if( ext->destruct )
369 ext->destruct( ext );
370 isom_remove_all_extension_boxes( &ext->extensions );
371 lsmash_free( ext );
374 void isom_remove_all_extension_boxes( lsmash_entry_list_t *extensions )
376 lsmash_remove_entries( extensions, isom_remove_extension_box );
379 isom_box_t *isom_get_extension_box( lsmash_entry_list_t *extensions, lsmash_box_type_t box_type )
381 for( lsmash_entry_t *entry = extensions->head; entry; entry = entry->next )
383 isom_box_t *ext = (isom_box_t *)entry->data;
384 if( !ext )
385 continue;
386 if( lsmash_check_box_type_identical( ext->type, box_type ) )
387 return ext;
389 return NULL;
392 void *isom_get_extension_box_format( lsmash_entry_list_t *extensions, lsmash_box_type_t box_type )
394 for( lsmash_entry_t *entry = extensions->head; entry; entry = entry->next )
396 isom_box_t *ext = (isom_box_t *)entry->data;
397 if( !ext || (ext->manager & LSMASH_BINARY_CODED_BOX) || !lsmash_check_box_type_identical( ext->type, box_type ) )
398 continue;
399 return ext;
401 return NULL;
404 lsmash_entry_t *isom_get_entry_of_box
406 lsmash_box_t *parent,
407 const lsmash_box_path_t box_path[]
410 if( !parent )
411 return NULL;
412 lsmash_entry_t *entry = NULL;
413 const lsmash_box_path_t *path = &box_path[0];
414 while( lsmash_check_box_type_specified( &path->type ) )
416 entry = parent->extensions.head;
417 if( !entry )
418 return NULL;
419 parent = NULL;
420 uint32_t i = 1;
421 uint32_t number = path->number ? path->number : 1;
422 while( entry )
424 isom_box_t *box = entry->data;
425 if( box && lsmash_check_box_type_identical( path->type, box->type ) )
427 if( i == number )
429 /* Found a box. Move to a child box. */
430 parent = box;
431 ++path;
432 break;
434 ++i;
436 entry = entry->next;
438 if( !parent )
439 return NULL;
441 return entry;
444 /* box destructors */
445 #define REMOVE_BOX( box_name, parent_type ) \
446 isom_remove_predefined_box( box_name, offsetof( parent_type, box_name ) )
448 #define REMOVE_BOX_IN_LIST( box_name, parent_type ) \
449 isom_remove_box_in_predefined_list( box_name, offsetof( parent_type, box_name##_list ) )
451 #define REMOVE_LIST_BOX_TEMPLATE( REMOVER, box_name, parent_type, eliminator ) \
452 do \
454 lsmash_remove_list( box_name->list, eliminator ); \
455 REMOVER( box_name, parent_type ); \
456 } while( 0 )
458 #define REMOVE_LIST_BOX( box_name, ... ) CALL_FUNC_DEFAULT_ARGS( REMOVE_LIST_BOX, box_name, __VA_ARGS__ )
459 #define REMOVE_LIST_BOX_3( box_name, parent_type, eliminator ) \
460 REMOVE_LIST_BOX_TEMPLATE( REMOVE_BOX, box_name, parent_type, eliminator )
461 #define REMOVE_LIST_BOX_2( box_name, parent_type ) \
462 REMOVE_LIST_BOX_3( box_name, parent_type, NULL )
464 #define REMOVE_LIST_BOX_IN_LIST( box_name, parent_type ) \
465 REMOVE_LIST_BOX_TEMPLATE( REMOVE_BOX_IN_LIST, box_name, parent_type, NULL )
467 #define DEFINE_SIMPLE_BOX_REMOVER_TEMPLATE( REMOVER, box_name, ... ) \
468 static void isom_remove_##box_name( isom_##box_name##_t *box_name ) \
470 if( !box_name ) \
471 return; \
472 REMOVER( box_name, __VA_ARGS__ ); \
475 #define DEFINE_SIMPLE_BOX_REMOVER( func_name, box_name, ... ) \
476 DEFINE_SIMPLE_BOX_REMOVER_TEMPLATE( REMOVE_BOX, box_name, __VA_ARGS__ )
478 #define DEFINE_SIMPLE_LIST_BOX_REMOVER( func_name, box_name, ... ) \
479 DEFINE_SIMPLE_BOX_REMOVER_TEMPLATE( REMOVE_LIST_BOX, box_name, __VA_ARGS__ )
481 #define DEFINE_SIMPLE_BOX_IN_LIST_REMOVER( func_name, box_name, ... ) \
482 DEFINE_SIMPLE_BOX_REMOVER_TEMPLATE( REMOVE_BOX_IN_LIST, box_name, __VA_ARGS__ )
484 #define DEFINE_SIMPLE_LIST_BOX_IN_LIST_REMOVER( func_name, box_name, ... ) \
485 DEFINE_SIMPLE_BOX_REMOVER_TEMPLATE( REMOVE_LIST_BOX_IN_LIST, box_name, __VA_ARGS__ )
487 static void isom_remove_predefined_box( void *opaque_box, size_t offset_of_box )
489 assert( opaque_box );
490 isom_box_t *box = (isom_box_t *)opaque_box;
491 if( box->parent )
493 isom_box_t **p = (isom_box_t **)(((int8_t *)box->parent) + offset_of_box);
494 if( *p == box )
495 *p = NULL;
499 /* We always free boxes through the extension list of the parent box.
500 * Therefore, don't free boxes through any list other than the extension list. */
501 static void isom_remove_box_in_predefined_list( void *opaque_box, size_t offset_of_list )
503 assert( opaque_box );
504 isom_box_t *box = (isom_box_t *)opaque_box;
505 if( box->parent )
507 lsmash_entry_list_t *list = (lsmash_entry_list_t *)(((int8_t *)box->parent) + offset_of_list);
508 if( list )
509 for( lsmash_entry_t *entry = list->head; entry; entry = entry->next )
510 if( box == entry->data )
512 /* We don't free this box here.
513 * Because of freeing an entry of the list here, don't pass the list to free this box.
514 * Or double free. */
515 entry->data = NULL;
516 lsmash_remove_entry_direct( list, entry, NULL );
517 break;
522 /* Remove a box by the pointer containing its address.
523 * In addition, remove from the extension list of the parent box if possible.
524 * Don't call this function within a function freeing one or more entries of any extension list because of double free.
525 * Basically, don't use this function as a callback function. */
526 void isom_remove_box_by_itself( void *opaque_box )
528 if( !opaque_box )
529 return;
530 isom_box_t *box = (isom_box_t *)opaque_box;
531 if( box->parent )
533 isom_box_t *parent = box->parent;
534 for( lsmash_entry_t *entry = parent->extensions.head; entry; entry = entry->next )
535 if( box == entry->data )
537 /* Free the corresponding entry here, therefore don't call this function as a callback function
538 * if a function frees the same entry later and calls this function. */
539 lsmash_remove_entry_direct( &parent->extensions, entry, isom_remove_extension_box );
540 return;
543 isom_remove_extension_box( box );
546 void isom_remove_unknown_box( isom_unknown_box_t *unknown_box )
548 if( !unknown_box )
549 return;
550 lsmash_free( unknown_box->unknown_field );
553 static void isom_remove_file( lsmash_file_t *file )
555 if( !file )
556 return;
557 #ifdef LSMASH_DEMUXER_ENABLED
558 isom_remove_print_funcs( file );
559 isom_remove_timelines( file );
560 #endif
561 lsmash_free( file->compatible_brands );
562 lsmash_bs_cleanup( file->bs );
563 lsmash_importer_destroy( file->importer );
564 if( file->fragment )
566 lsmash_remove_list( file->fragment->pool, isom_remove_sample_pool );
567 lsmash_free( file->fragment );
569 REMOVE_BOX_IN_LIST( file, lsmash_root_t );
572 static void isom_remove_ftyp( isom_ftyp_t *ftyp )
574 if( !ftyp )
575 return;
576 lsmash_free( ftyp->compatible_brands );
577 REMOVE_BOX( ftyp, lsmash_file_t );
580 static void isom_remove_iods( isom_iods_t *iods )
582 if( !iods )
583 return;
584 mp4sys_remove_descriptor( iods->OD );
585 REMOVE_BOX( iods, isom_moov_t );
588 static void isom_remove_trak( isom_trak_t *trak )
590 if( !trak )
591 return;
592 if( trak->cache )
594 isom_remove_sample_pool( trak->cache->chunk.pool );
595 lsmash_remove_list( trak->cache->roll.pool, NULL );
596 lsmash_free( trak->cache->rap );
597 lsmash_free( trak->cache->fragment );
598 lsmash_free( trak->cache );
600 REMOVE_BOX_IN_LIST( trak, isom_moov_t );
603 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_tkhd, tkhd, isom_trak_t )
604 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_clef, clef, isom_tapt_t )
605 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_prof, prof, isom_tapt_t )
606 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_enof, enof, isom_tapt_t )
607 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_tapt, tapt, isom_trak_t )
608 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_edts, edts, isom_trak_t )
609 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_tref, tref, isom_trak_t )
610 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_elst, elst, isom_edts_t )
612 static void isom_remove_track_reference_type( isom_tref_type_t *ref )
614 if( !ref )
615 return;
616 lsmash_free( ref->track_ID );
617 isom_remove_box_in_predefined_list( ref, offsetof( isom_tref_t, ref_list ) );
620 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mdhd, mdhd, isom_mdia_t )
621 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_vmhd, vmhd, isom_minf_t )
622 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_smhd, smhd, isom_minf_t )
623 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_hmhd, hmhd, isom_minf_t )
624 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_nmhd, nmhd, isom_minf_t )
625 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_gmhd, gmhd, isom_minf_t )
626 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_gmin, gmin, isom_gmhd_t )
627 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_text, text, isom_gmhd_t )
629 static void isom_remove_hdlr( isom_hdlr_t *hdlr )
631 if( !hdlr )
632 return;
633 lsmash_free( hdlr->componentName );
634 if( hdlr->parent )
636 if( lsmash_check_box_type_identical( hdlr->parent->type, ISOM_BOX_TYPE_MDIA ) )
637 REMOVE_BOX( hdlr, isom_mdia_t );
638 else if( lsmash_check_box_type_identical( hdlr->parent->type, ISOM_BOX_TYPE_META )
639 || lsmash_check_box_type_identical( hdlr->parent->type, QT_BOX_TYPE_META ) )
640 REMOVE_BOX( hdlr, isom_meta_t );
641 else if( lsmash_check_box_type_identical( hdlr->parent->type, ISOM_BOX_TYPE_MINF ) )
642 REMOVE_BOX( hdlr, isom_minf_t );
643 else
644 assert( 0 );
645 return;
649 static void isom_remove_glbl( isom_glbl_t *glbl )
651 if( !glbl )
652 return;
653 lsmash_free( glbl->header_data );
656 static void isom_remove_esds( isom_esds_t *esds )
658 if( !esds )
659 return;
660 mp4sys_remove_descriptor( esds->ES );
663 static void isom_remove_font_record( isom_font_record_t *font_record )
665 if( !font_record )
666 return;
667 lsmash_free( font_record->font_name );
668 lsmash_free( font_record );
670 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_ftab, ftab, isom_tx3g_entry_t, isom_remove_font_record )
672 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_frma, frma, isom_wave_t )
673 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_enda, enda, isom_wave_t )
674 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mp4a, mp4a, isom_wave_t )
675 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_terminator, terminator, isom_wave_t )
677 static void isom_remove_chan( isom_chan_t *chan )
679 if( !chan )
680 return;
681 lsmash_free( chan->channelDescriptions );
684 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_stsd, stsd, isom_stbl_t )
686 static void isom_remove_visual_description( isom_sample_entry_t *description )
688 isom_visual_entry_t *visual = (isom_visual_entry_t *)description;
689 lsmash_free( visual->color_table.array );
690 isom_remove_box_in_predefined_list( visual, offsetof( isom_stsd_t, list ) );
693 static void isom_remove_audio_description( isom_sample_entry_t *description )
695 isom_remove_box_in_predefined_list( description, offsetof( isom_stsd_t, list ) );
698 static void isom_remove_hint_description( isom_sample_entry_t *description )
700 isom_hint_entry_t *hint = (isom_hint_entry_t *)description;
701 lsmash_free( hint->data );
702 isom_remove_box_in_predefined_list( hint, offsetof( isom_stsd_t, list ) );
705 static void isom_remove_metadata_description( isom_sample_entry_t *description )
707 isom_remove_box_in_predefined_list( description, offsetof( isom_stsd_t, list ) );
710 static void isom_remove_tx3g_description( isom_sample_entry_t *description )
712 isom_remove_box_in_predefined_list( description, offsetof( isom_stsd_t, list ) );
715 static void isom_remove_qt_text_description( isom_sample_entry_t *description )
717 isom_qt_text_entry_t *text = (isom_qt_text_entry_t *)description;
718 lsmash_free( text->font_name );
719 isom_remove_box_in_predefined_list( text, offsetof( isom_stsd_t, list ) );
722 static void isom_remove_mp4s_description( isom_sample_entry_t *description )
724 isom_remove_box_in_predefined_list( description, offsetof( isom_stsd_t, list ) );
727 void isom_remove_sample_description( isom_sample_entry_t *sample )
729 if( !sample )
730 return;
731 lsmash_codec_type_t sample_type = sample->type;
732 if( lsmash_check_box_type_identical( sample_type, LSMASH_CODEC_TYPE_RAW ) )
734 if( sample->manager & LSMASH_VIDEO_DESCRIPTION )
736 isom_remove_visual_description( sample );
737 return;
739 else if( sample->manager & LSMASH_AUDIO_DESCRIPTION )
741 isom_remove_audio_description( sample );
742 return;
745 static struct description_remover_table_tag
747 lsmash_codec_type_t type;
748 void (*func)( isom_sample_entry_t * );
749 } description_remover_table[160] = { { LSMASH_CODEC_TYPE_INITIALIZER, NULL } };
750 if( !description_remover_table[0].func )
752 /* Initialize the table. */
753 int i = 0;
754 #define ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( type, func ) \
755 description_remover_table[i++] = (struct description_remover_table_tag){ type, func }
756 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVC1_VIDEO, isom_remove_visual_description );
757 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVC2_VIDEO, isom_remove_visual_description );
758 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVC3_VIDEO, isom_remove_visual_description );
759 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVC4_VIDEO, isom_remove_visual_description );
760 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVCP_VIDEO, isom_remove_visual_description );
761 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_HVC1_VIDEO, isom_remove_visual_description );
762 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_HEV1_VIDEO, isom_remove_visual_description );
763 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SVC1_VIDEO, isom_remove_visual_description );
764 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MVC1_VIDEO, isom_remove_visual_description );
765 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MVC2_VIDEO, isom_remove_visual_description );
766 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MP4V_VIDEO, isom_remove_visual_description );
767 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DRAC_VIDEO, isom_remove_visual_description );
768 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_ENCV_VIDEO, isom_remove_visual_description );
769 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MJP2_VIDEO, isom_remove_visual_description );
770 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_S263_VIDEO, isom_remove_visual_description );
771 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_VC_1_VIDEO, isom_remove_visual_description );
772 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_2VUY_VIDEO, isom_remove_visual_description );
773 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_CFHD_VIDEO, isom_remove_visual_description );
774 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DV10_VIDEO, isom_remove_visual_description );
775 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVOO_VIDEO, isom_remove_visual_description );
776 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVOR_VIDEO, isom_remove_visual_description );
777 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVTV_VIDEO, isom_remove_visual_description );
778 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVVT_VIDEO, isom_remove_visual_description );
779 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_HD10_VIDEO, isom_remove_visual_description );
780 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_M105_VIDEO, isom_remove_visual_description );
781 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_PNTG_VIDEO, isom_remove_visual_description );
782 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SVQ1_VIDEO, isom_remove_visual_description );
783 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SVQ3_VIDEO, isom_remove_visual_description );
784 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR0_VIDEO, isom_remove_visual_description );
785 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR1_VIDEO, isom_remove_visual_description );
786 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR2_VIDEO, isom_remove_visual_description );
787 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR3_VIDEO, isom_remove_visual_description );
788 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR4_VIDEO, isom_remove_visual_description );
789 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_WRLE_VIDEO, isom_remove_visual_description );
790 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_APCH_VIDEO, isom_remove_visual_description );
791 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_APCN_VIDEO, isom_remove_visual_description );
792 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_APCS_VIDEO, isom_remove_visual_description );
793 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_APCO_VIDEO, isom_remove_visual_description );
794 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_AP4H_VIDEO, isom_remove_visual_description );
795 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_CIVD_VIDEO, isom_remove_visual_description );
796 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DRAC_VIDEO, isom_remove_visual_description );
797 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVC_VIDEO, isom_remove_visual_description );
798 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVCP_VIDEO, isom_remove_visual_description );
799 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVPP_VIDEO, isom_remove_visual_description );
800 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DV5N_VIDEO, isom_remove_visual_description );
801 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DV5P_VIDEO, isom_remove_visual_description );
802 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVH2_VIDEO, isom_remove_visual_description );
803 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVH3_VIDEO, isom_remove_visual_description );
804 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVH5_VIDEO, isom_remove_visual_description );
805 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVH6_VIDEO, isom_remove_visual_description );
806 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVHP_VIDEO, isom_remove_visual_description );
807 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVHQ_VIDEO, isom_remove_visual_description );
808 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_FLIC_VIDEO, isom_remove_visual_description );
809 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_GIF_VIDEO, isom_remove_visual_description );
810 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_H261_VIDEO, isom_remove_visual_description );
811 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_H263_VIDEO, isom_remove_visual_description );
812 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_JPEG_VIDEO, isom_remove_visual_description );
813 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_MJPA_VIDEO, isom_remove_visual_description );
814 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_MJPB_VIDEO, isom_remove_visual_description );
815 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_PNG_VIDEO, isom_remove_visual_description );
816 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_RLE_VIDEO, isom_remove_visual_description );
817 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_RPZA_VIDEO, isom_remove_visual_description );
818 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_TGA_VIDEO, isom_remove_visual_description );
819 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_TIFF_VIDEO, isom_remove_visual_description );
820 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULRA_VIDEO, isom_remove_visual_description );
821 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULRG_VIDEO, isom_remove_visual_description );
822 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULY2_VIDEO, isom_remove_visual_description );
823 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULY0_VIDEO, isom_remove_visual_description );
824 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULH2_VIDEO, isom_remove_visual_description );
825 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULH0_VIDEO, isom_remove_visual_description );
826 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V210_VIDEO, isom_remove_visual_description );
827 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V216_VIDEO, isom_remove_visual_description );
828 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V308_VIDEO, isom_remove_visual_description );
829 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V408_VIDEO, isom_remove_visual_description );
830 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V410_VIDEO, isom_remove_visual_description );
831 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_YUV2_VIDEO, isom_remove_visual_description );
832 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MP4A_AUDIO, isom_remove_audio_description );
833 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AC_3_AUDIO, isom_remove_audio_description );
834 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_ALAC_AUDIO, isom_remove_audio_description );
835 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSC_AUDIO, isom_remove_audio_description );
836 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSE_AUDIO, isom_remove_audio_description );
837 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSH_AUDIO, isom_remove_audio_description );
838 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSL_AUDIO, isom_remove_audio_description );
839 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_EC_3_AUDIO, isom_remove_audio_description );
840 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SAMR_AUDIO, isom_remove_audio_description );
841 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SAWB_AUDIO, isom_remove_audio_description );
842 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_23NI_AUDIO, isom_remove_audio_description );
843 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_NONE_AUDIO, isom_remove_audio_description );
844 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_LPCM_AUDIO, isom_remove_audio_description );
845 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SOWT_AUDIO, isom_remove_audio_description );
846 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_TWOS_AUDIO, isom_remove_audio_description );
847 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_FL32_AUDIO, isom_remove_audio_description );
848 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_FL64_AUDIO, isom_remove_audio_description );
849 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_IN24_AUDIO, isom_remove_audio_description );
850 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_IN32_AUDIO, isom_remove_audio_description );
851 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_NOT_SPECIFIED, isom_remove_audio_description );
852 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DRA1_AUDIO, isom_remove_audio_description );
853 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_ENCA_AUDIO, isom_remove_audio_description );
854 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_G719_AUDIO, isom_remove_audio_description );
855 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_G726_AUDIO, isom_remove_audio_description );
856 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_M4AE_AUDIO, isom_remove_audio_description );
857 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MLPA_AUDIO, isom_remove_audio_description );
858 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SAWP_AUDIO, isom_remove_audio_description );
859 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SEVC_AUDIO, isom_remove_audio_description );
860 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SQCP_AUDIO, isom_remove_audio_description );
861 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SSMV_AUDIO, isom_remove_audio_description );
862 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_TWOS_AUDIO, isom_remove_audio_description );
863 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_FDP_HINT, isom_remove_hint_description );
864 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_M2TS_HINT, isom_remove_hint_description );
865 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_PM2T_HINT, isom_remove_hint_description );
866 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_PRTP_HINT, isom_remove_hint_description );
867 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_RM2T_HINT, isom_remove_hint_description );
868 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_RRTP_HINT, isom_remove_hint_description );
869 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_RSRP_HINT, isom_remove_hint_description );
870 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_RTP_HINT , isom_remove_hint_description );
871 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SM2T_HINT, isom_remove_hint_description );
872 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SRTP_HINT, isom_remove_hint_description );
873 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_IXSE_META, isom_remove_metadata_description );
874 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_METT_META, isom_remove_metadata_description );
875 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_METX_META, isom_remove_metadata_description );
876 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MLIX_META, isom_remove_metadata_description );
877 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_OKSD_META, isom_remove_metadata_description );
878 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SVCM_META, isom_remove_metadata_description );
879 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_TEXT_META, isom_remove_metadata_description );
880 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_URIM_META, isom_remove_metadata_description );
881 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_XML_META, isom_remove_metadata_description );
882 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_TX3G_TEXT, isom_remove_tx3g_description );
883 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_TEXT_TEXT, isom_remove_qt_text_description );
884 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MP4S_SYSTEM, isom_remove_mp4s_description );
885 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( LSMASH_CODEC_TYPE_UNSPECIFIED, NULL );
887 for( int i = 0; description_remover_table[i].func; i++ )
888 if( lsmash_check_codec_type_identical( sample_type, description_remover_table[i].type ) )
890 description_remover_table[i].func( sample );
891 return;
895 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stts, stts, isom_stbl_t )
896 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_ctts, ctts, isom_stbl_t )
897 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_cslg, cslg, isom_stbl_t )
898 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stsc, stsc, isom_stbl_t )
899 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stsz, stsz, isom_stbl_t )
900 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stss, stss, isom_stbl_t )
901 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stps, stps, isom_stbl_t )
902 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stco, stco, isom_stbl_t )
904 static void isom_remove_sdtp( isom_sdtp_t *sdtp )
906 if( !sdtp )
907 return;
908 lsmash_remove_list( sdtp->list, NULL );
909 if( sdtp->parent )
911 if( lsmash_check_box_type_identical( sdtp->parent->type, ISOM_BOX_TYPE_STBL ) )
912 REMOVE_BOX( sdtp, isom_stbl_t );
913 else if( lsmash_check_box_type_identical( sdtp->parent->type, ISOM_BOX_TYPE_TRAF ) )
914 REMOVE_BOX( sdtp, isom_traf_t );
915 else
916 assert( 0 );
917 return;
921 static void isom_remove_sgpd( isom_sgpd_t *sgpd )
923 if( !sgpd )
924 return;
925 lsmash_remove_list( sgpd->list, NULL );
926 if( sgpd->parent )
928 if( lsmash_check_box_type_identical( sgpd->parent->type, ISOM_BOX_TYPE_STBL ) )
929 REMOVE_BOX_IN_LIST( sgpd, isom_stbl_t );
930 else if( lsmash_check_box_type_identical( sgpd->parent->type, ISOM_BOX_TYPE_TRAF ) )
931 REMOVE_BOX_IN_LIST( sgpd, isom_traf_t );
932 else
933 assert( 0 );
934 return;
938 static void isom_remove_sbgp( isom_sbgp_t *sbgp )
940 if( !sbgp )
941 return;
942 lsmash_remove_list( sbgp->list, NULL );
943 if( sbgp->parent )
945 if( lsmash_check_box_type_identical( sbgp->parent->type, ISOM_BOX_TYPE_STBL ) )
946 REMOVE_BOX_IN_LIST( sbgp, isom_stbl_t );
947 else if( lsmash_check_box_type_identical( sbgp->parent->type, ISOM_BOX_TYPE_TRAF ) )
948 REMOVE_BOX_IN_LIST( sbgp, isom_traf_t );
949 else
950 assert( 0 );
951 return;
955 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_stbl, stbl, isom_minf_t )
957 static void isom_remove_dref_entry( isom_dref_entry_t *data_entry )
959 if( !data_entry )
960 return;
961 lsmash_free( data_entry->name );
962 lsmash_free( data_entry->location );
963 isom_remove_box_in_predefined_list( data_entry, offsetof( isom_dref_t, list ) );
966 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_dref, dref, isom_dinf_t )
967 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_dinf, dinf, isom_minf_t )
968 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_minf, minf, isom_mdia_t )
969 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mdia, mdia, isom_trak_t )
971 static void isom_remove_chpl_entry( isom_chpl_entry_t *data )
973 if( !data )
974 return;
975 lsmash_free( data->chapter_name );
976 lsmash_free( data );
978 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_chpl, chpl, isom_udta_t, isom_remove_chpl_entry )
980 static void isom_remove_keys_entry( isom_keys_entry_t *data )
982 if( !data )
983 return;
984 lsmash_free( data->key_value );
985 lsmash_free( data );
987 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_keys, keys, isom_meta_t, isom_remove_keys_entry )
989 static void isom_remove_mean( isom_mean_t *mean )
991 if( !mean )
992 return;
993 lsmash_free( mean->meaning_string );
994 REMOVE_BOX( mean, isom_metaitem_t );
997 static void isom_remove_name( isom_name_t *name )
999 if( !name )
1000 return;
1001 lsmash_free( name->name );
1002 REMOVE_BOX( name, isom_metaitem_t );
1005 static void isom_remove_data( isom_data_t *data )
1007 if( !data )
1008 return;
1009 lsmash_free( data->value );
1010 REMOVE_BOX( data, isom_metaitem_t );
1013 DEFINE_SIMPLE_BOX_IN_LIST_REMOVER( isom_remove_metaitem, metaitem, isom_ilst_t )
1014 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_ilst, ilst, isom_meta_t )
1016 static void isom_remove_meta( isom_meta_t *meta )
1018 if( !meta )
1019 return;
1020 if( meta->parent )
1022 if( lsmash_check_box_type_identical( meta->parent->type, LSMASH_BOX_TYPE_UNSPECIFIED ) )
1023 REMOVE_BOX( meta, lsmash_file_t );
1024 else if( lsmash_check_box_type_identical( meta->parent->type, ISOM_BOX_TYPE_MOOV ) )
1025 REMOVE_BOX( meta, isom_moov_t );
1026 else if( lsmash_check_box_type_identical( meta->parent->type, ISOM_BOX_TYPE_TRAK ) )
1027 REMOVE_BOX( meta, isom_trak_t );
1028 else if( lsmash_check_box_type_identical( meta->parent->type, ISOM_BOX_TYPE_UDTA ) )
1029 REMOVE_BOX( meta, isom_udta_t );
1030 else
1031 assert( 0 );
1032 return;
1036 static void isom_remove_cprt( isom_cprt_t *cprt )
1038 if( !cprt )
1039 return;
1040 lsmash_free( cprt->notice );
1041 REMOVE_BOX_IN_LIST( cprt, isom_udta_t );
1044 static void isom_remove_udta( isom_udta_t *udta )
1046 if( !udta )
1047 return;
1048 if( udta->parent )
1050 if( lsmash_check_box_type_identical( udta->parent->type, ISOM_BOX_TYPE_MOOV ) )
1051 REMOVE_BOX( udta, isom_moov_t );
1052 else if( lsmash_check_box_type_identical( udta->parent->type, ISOM_BOX_TYPE_TRAK ) )
1053 REMOVE_BOX( udta, isom_trak_t );
1054 else
1055 assert( 0 );
1056 return;
1060 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_WLOC, WLOC, isom_udta_t )
1061 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_LOOP, LOOP, isom_udta_t )
1062 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_SelO, SelO, isom_udta_t )
1063 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_AllF, AllF, isom_udta_t )
1065 static void isom_remove_ctab( isom_ctab_t *ctab )
1067 if( !ctab )
1068 return;
1069 lsmash_free( ctab->color_table.array );
1070 if( ctab->parent && lsmash_check_box_type_identical( ctab->parent->type, ISOM_BOX_TYPE_MOOV ) )
1071 REMOVE_BOX( ctab, isom_moov_t );
1074 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mvex, mvex, isom_moov_t )
1075 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mvhd, mvhd, isom_moov_t )
1076 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mehd, mehd, isom_mvex_t )
1077 DEFINE_SIMPLE_BOX_IN_LIST_REMOVER( isom_remove_trex, trex, isom_mvex_t )
1078 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_moov, moov, lsmash_file_t )
1079 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mdat, mdat, lsmash_file_t )
1080 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mfhd, mfhd, isom_moof_t )
1081 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_tfhd, tfhd, isom_traf_t )
1082 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_tfdt, tfdt, isom_traf_t )
1084 static void isom_remove_trun( isom_trun_t *trun )
1086 if( !trun )
1087 return;
1088 lsmash_remove_list( trun->optional, NULL );
1089 REMOVE_BOX_IN_LIST( trun, isom_traf_t );
1092 DEFINE_SIMPLE_BOX_IN_LIST_REMOVER( isom_remove_traf, traf, isom_moof_t )
1093 DEFINE_SIMPLE_BOX_IN_LIST_REMOVER( isom_remove_moof, moof, lsmash_file_t )
1095 static void isom_remove_free( isom_free_t *skip )
1097 if( !skip )
1098 return;
1099 lsmash_free( skip->data );
1100 isom_remove_predefined_box( skip, offsetof( lsmash_file_t, free ) );
1102 #define isom_remove_skip isom_remove_free
1104 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mfra, mfra, lsmash_file_t )
1105 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mfro, mfro, isom_mfra_t )
1106 DEFINE_SIMPLE_LIST_BOX_IN_LIST_REMOVER( isom_remove_tfra, tfra, isom_mfra_t )
1107 DEFINE_SIMPLE_LIST_BOX_IN_LIST_REMOVER( isom_remove_sidx, sidx, lsmash_file_t )
1109 static void isom_remove_styp( isom_styp_t *styp )
1111 if( !styp )
1112 return;
1113 lsmash_free( styp->compatible_brands );
1114 REMOVE_BOX_IN_LIST( styp, lsmash_file_t );
1117 /* box size updater */
1118 uint64_t isom_update_box_size( void *opaque_box )
1120 assert( opaque_box );
1121 isom_box_t *box = (isom_box_t *)opaque_box;
1122 if( box->manager & LSMASH_WRITTEN_BOX )
1123 /* No need to calculate the size of this box since the size is already decided and fixed. */
1124 return box->size;
1125 uint64_t size = 0;
1126 if( box->write )
1128 /* Calculate the size of this box excluding its children with a fake bytestream writer. */
1130 lsmash_bs_t fake_bs = { NULL };
1131 if( box->write( &fake_bs, box ) == 0 )
1132 size = lsmash_bs_get_valid_data_size( &fake_bs );
1134 /* Calculate the size of the children if no error. */
1135 if( size >= ISOM_BASEBOX_COMMON_SIZE )
1137 for( lsmash_entry_t *entry = box->extensions.head; entry; entry = entry->next )
1138 if( entry->data )
1139 size += isom_update_box_size( entry->data );
1140 /* Check large size. */
1141 if( size > UINT32_MAX )
1142 size += 8;
1144 else
1145 /* TODO: add error handling. */
1146 size = 0;
1148 box->size = size;
1149 return size;
1152 /* box adding functions */
1153 #define ATTACH_EXACTLY_ONE_BOX_TO_PARENT( box_name, parent_type ) \
1154 do \
1156 isom_box_t **p = (isom_box_t **)(((int8_t *)box_name->parent) \
1157 + offsetof( parent_type, box_name )); \
1158 if( *p == NULL ) \
1159 *p = (isom_box_t *)box_name; \
1160 } while( 0 )
1162 #define INIT_BOX_COMMON0( box_name, parent, box_type, precedence ) \
1163 const isom_extension_destructor_t isom_remove_##box_name = NULL; \
1164 isom_init_box_common( box_name, parent, box_type, precedence, isom_remove_##box_name )
1165 #define INIT_BOX_COMMON1( box_name, parent, box_type, precedence ) \
1166 isom_init_box_common( box_name, parent, box_type, precedence, isom_remove_##box_name )
1168 #define CREATE_BOX( box_name, parent, box_type, precedence, has_destructor ) \
1169 if( !(parent) ) \
1170 return NULL; \
1171 isom_##box_name##_t *box_name = lsmash_malloc_zero( sizeof(isom_##box_name##_t) ); \
1172 if( !box_name ) \
1173 return NULL; \
1174 INIT_BOX_COMMON ## has_destructor( box_name, parent, box_type, precedence ); \
1175 if( isom_add_box_to_extension_list( parent, box_name ) < 0 ) \
1177 lsmash_free( box_name ); \
1178 return NULL; \
1180 #define CREATE_LIST_BOX( box_name, parent, box_type, precedence, has_destructor ) \
1181 CREATE_BOX( box_name, parent, box_type, precedence, has_destructor ); \
1182 box_name->list = lsmash_create_entry_list(); \
1183 if( !box_name->list ) \
1185 lsmash_remove_entry_tail( &(parent)->extensions, isom_remove_##box_name ); \
1186 return NULL; \
1189 #define ADD_BOX_TEMPLATE( box_name, parent, box_type, precedence, BOX_CREATOR ) \
1190 BOX_CREATOR( box_name, parent, box_type, precedence, 1 ); \
1191 if( !(parent)->box_name ) \
1192 (parent)->box_name = box_name
1193 #define ADD_BOX_IN_LIST_TEMPLATE( box_name, parent, box_type, precedence, BOX_CREATOR ) \
1194 BOX_CREATOR( box_name, parent, box_type, precedence, 1 ); \
1195 if( lsmash_add_entry( &(parent)->box_name##_list, box_name ) < 0 ) \
1197 lsmash_remove_entry_tail( &(parent)->extensions, isom_remove_##box_name ); \
1198 return NULL; \
1201 #define ADD_BOX( box_name, parent, box_type, precedence ) \
1202 ADD_BOX_TEMPLATE( box_name, parent, box_type, precedence, CREATE_BOX )
1203 #define ADD_BOX_IN_LIST( box_name, parent, box_type, precedence ) \
1204 ADD_BOX_IN_LIST_TEMPLATE( box_name, parent, box_type, precedence, CREATE_BOX )
1205 #define ADD_LIST_BOX( box_name, parent, box_type, precedence ) \
1206 ADD_BOX_TEMPLATE( box_name, parent, box_type, precedence, CREATE_LIST_BOX )
1207 #define ADD_LIST_BOX_IN_LIST( box_name, parent, box_type, precedence ) \
1208 ADD_BOX_IN_LIST_TEMPLATE( box_name, parent, box_type, precedence, CREATE_LIST_BOX )
1210 #define DEFINE_SIMPLE_BOX_ADDER_TEMPLATE( ... ) CALL_FUNC_DEFAULT_ARGS( DEFINE_SIMPLE_BOX_ADDER_TEMPLATE, __VA_ARGS__ )
1211 #define DEFINE_SIMPLE_BOX_ADDER_TEMPLATE_6( ADDER, box_name, parent_name, box_type, precedence, parent_type ) \
1212 isom_##box_name##_t *isom_add_##box_name( parent_type *parent_name ) \
1214 ADDER( box_name, parent_name, box_type, precedence ); \
1215 return box_name; \
1217 #define DEFINE_SIMPLE_BOX_ADDER_TEMPLATE_5( ADDER, box_name, parent_name, box_type, precedence ) \
1218 DEFINE_SIMPLE_BOX_ADDER_TEMPLATE_6( ADDER, box_name, parent_name, box_type, precedence, isom_##parent_name##_t )
1220 #define DEFINE_SIMPLE_BOX_ADDER( func_name, ... ) \
1221 DEFINE_SIMPLE_BOX_ADDER_TEMPLATE( ADD_BOX, __VA_ARGS__ )
1222 #define DEFINE_SIMPLE_BOX_IN_LIST_ADDER( func_name, ... ) \
1223 DEFINE_SIMPLE_BOX_ADDER_TEMPLATE( ADD_BOX_IN_LIST, __VA_ARGS__ )
1224 #define DEFINE_SIMPLE_LIST_BOX_ADDER( func_name, ... ) \
1225 DEFINE_SIMPLE_BOX_ADDER_TEMPLATE( ADD_LIST_BOX, __VA_ARGS__ )
1227 #define DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( func_name, box_name, parent_name, box_type, precedence, has_destructor, parent_type ) \
1228 isom_##box_name##_t *isom_add_##box_name( parent_type *parent_name ) \
1230 CREATE_BOX( box_name, parent_name, box_type, precedence, has_destructor ); \
1231 return box_name; \
1234 lsmash_file_t *isom_add_file( lsmash_root_t *root )
1236 lsmash_file_t *file = lsmash_malloc_zero( sizeof(lsmash_file_t) );
1237 if( !file )
1238 return NULL;
1239 file->class = &lsmash_box_class;
1240 file->root = root;
1241 file->file = file;
1242 file->parent = (isom_box_t *)root;
1243 file->destruct = (isom_extension_destructor_t)isom_remove_file;
1244 file->size = 0;
1245 file->type = LSMASH_BOX_TYPE_UNSPECIFIED;
1246 if( isom_add_box_to_extension_list( root, file ) < 0 )
1248 lsmash_free( file );
1249 return NULL;
1251 if( lsmash_add_entry( &root->file_list, file ) < 0 )
1253 lsmash_remove_entry_tail( &root->extensions, isom_remove_file );
1254 return NULL;
1256 return file;
1259 isom_tref_type_t *isom_add_track_reference_type( isom_tref_t *tref, isom_track_reference_type type )
1261 if( !tref )
1262 return NULL;
1263 isom_tref_type_t *ref = lsmash_malloc_zero( sizeof(isom_tref_type_t) );
1264 if( !ref )
1265 return NULL;
1266 /* Initialize common fields. */
1267 ref->root = tref->root;
1268 ref->file = tref->file;
1269 ref->parent = (isom_box_t *)tref;
1270 ref->size = 0;
1271 ref->type = lsmash_form_iso_box_type( type );
1272 ref->precedence = LSMASH_BOX_PRECEDENCE_ISOM_TREF_TYPE;
1273 ref->destruct = (isom_extension_destructor_t)isom_remove_track_reference_type;
1274 isom_set_box_writer( (isom_box_t *)ref );
1275 if( isom_add_box_to_extension_list( tref, ref ) < 0 )
1277 lsmash_free( ref );
1278 return NULL;
1280 if( lsmash_add_entry( &tref->ref_list, ref ) < 0 )
1282 lsmash_remove_entry_tail( &tref->extensions, isom_remove_track_reference_type );
1283 return NULL;
1285 return ref;
1288 DEFINE_SIMPLE_BOX_ADDER( isom_add_terminator, terminator, wave, QT_BOX_TYPE_TERMINATOR, LSMASH_BOX_PRECEDENCE_QTFF_TERMINATOR )
1289 DEFINE_SIMPLE_BOX_ADDER( isom_add_frma, frma, wave, QT_BOX_TYPE_FRMA, LSMASH_BOX_PRECEDENCE_QTFF_FRMA )
1290 DEFINE_SIMPLE_BOX_ADDER( isom_add_enda, enda, wave, QT_BOX_TYPE_ENDA, LSMASH_BOX_PRECEDENCE_QTFF_ENDA )
1291 DEFINE_SIMPLE_BOX_ADDER( isom_add_mp4a, mp4a, wave, QT_BOX_TYPE_MP4A, LSMASH_BOX_PRECEDENCE_QTFF_MP4A )
1292 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_ftab, ftab, tx3g, ISOM_BOX_TYPE_FTAB, LSMASH_BOX_PRECEDENCE_ISOM_FTAB, isom_tx3g_entry_t )
1293 DEFINE_SIMPLE_BOX_ADDER( isom_add_ftyp, ftyp, file, ISOM_BOX_TYPE_FTYP, LSMASH_BOX_PRECEDENCE_ISOM_FTYP, lsmash_file_t )
1294 DEFINE_SIMPLE_BOX_ADDER( isom_add_moov, moov, file, ISOM_BOX_TYPE_MOOV, LSMASH_BOX_PRECEDENCE_ISOM_MOOV, lsmash_file_t )
1295 DEFINE_SIMPLE_BOX_ADDER( isom_add_mvhd, mvhd, moov, ISOM_BOX_TYPE_MVHD, LSMASH_BOX_PRECEDENCE_ISOM_MVHD )
1296 DEFINE_SIMPLE_BOX_ADDER( isom_add_iods, iods, moov, ISOM_BOX_TYPE_IODS, LSMASH_BOX_PRECEDENCE_ISOM_IODS )
1298 isom_ctab_t *isom_add_ctab( void *parent_box )
1300 /* According to QuickTime File Format Specification, this box is placed inside Movie Box if present.
1301 * However, sometimes this box occurs inside an image description entry or the end of Sample Description Box. */
1302 if( !parent_box )
1303 return NULL;
1304 isom_box_t *parent = (isom_box_t *)parent_box;
1305 CREATE_BOX( ctab, parent, QT_BOX_TYPE_CTAB, LSMASH_BOX_PRECEDENCE_QTFF_CTAB, 1 );
1306 if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_MOOV ) )
1307 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( ctab, isom_moov_t );
1308 return ctab;
1311 isom_trak_t *isom_add_trak( isom_moov_t *moov )
1313 if( !moov || !moov->file )
1314 return NULL;
1315 CREATE_BOX( trak, moov, ISOM_BOX_TYPE_TRAK, LSMASH_BOX_PRECEDENCE_ISOM_TRAK, 1 );
1316 isom_fragment_t *fragment = NULL;
1317 isom_cache_t *cache = lsmash_malloc_zero( sizeof(isom_cache_t) );
1318 if( !cache )
1319 goto fail;
1320 if( moov->file->fragment )
1322 fragment = lsmash_malloc_zero( sizeof(isom_fragment_t) );
1323 if( !fragment )
1324 goto fail;
1325 cache->fragment = fragment;
1327 if( lsmash_add_entry( &moov->trak_list, trak ) < 0 )
1328 goto fail;
1329 trak->cache = cache;
1330 return trak;
1331 fail:
1332 lsmash_free( fragment );
1333 lsmash_free( cache );
1334 lsmash_remove_entry_tail( &moov->extensions, isom_remove_trak );
1335 return NULL;
1338 DEFINE_SIMPLE_BOX_ADDER ( isom_add_tkhd, tkhd, trak, ISOM_BOX_TYPE_TKHD, LSMASH_BOX_PRECEDENCE_ISOM_TKHD )
1339 DEFINE_SIMPLE_BOX_ADDER ( isom_add_tapt, tapt, trak, QT_BOX_TYPE_TAPT, LSMASH_BOX_PRECEDENCE_QTFF_TAPT )
1340 DEFINE_SIMPLE_BOX_ADDER ( isom_add_clef, clef, tapt, QT_BOX_TYPE_CLEF, LSMASH_BOX_PRECEDENCE_QTFF_CLEF )
1341 DEFINE_SIMPLE_BOX_ADDER ( isom_add_prof, prof, tapt, QT_BOX_TYPE_PROF, LSMASH_BOX_PRECEDENCE_QTFF_PROF )
1342 DEFINE_SIMPLE_BOX_ADDER ( isom_add_enof, enof, tapt, QT_BOX_TYPE_ENOF, LSMASH_BOX_PRECEDENCE_QTFF_ENOF )
1343 DEFINE_SIMPLE_BOX_ADDER ( isom_add_edts, edts, trak, ISOM_BOX_TYPE_EDTS, LSMASH_BOX_PRECEDENCE_ISOM_EDTS )
1344 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_elst, elst, edts, ISOM_BOX_TYPE_ELST, LSMASH_BOX_PRECEDENCE_ISOM_ELST )
1345 DEFINE_SIMPLE_BOX_ADDER ( isom_add_tref, tref, trak, ISOM_BOX_TYPE_TREF, LSMASH_BOX_PRECEDENCE_ISOM_TREF )
1346 DEFINE_SIMPLE_BOX_ADDER ( isom_add_mdia, mdia, trak, ISOM_BOX_TYPE_MDIA, LSMASH_BOX_PRECEDENCE_ISOM_MDIA )
1347 DEFINE_SIMPLE_BOX_ADDER ( isom_add_mdhd, mdhd, mdia, ISOM_BOX_TYPE_MDHD, LSMASH_BOX_PRECEDENCE_ISOM_MDHD )
1349 isom_hdlr_t *isom_add_hdlr( void *parent_box )
1351 if( !parent_box )
1352 return NULL;
1353 isom_box_t *parent = (isom_box_t *)parent_box;
1354 CREATE_BOX( hdlr, parent, ISOM_BOX_TYPE_HDLR, LSMASH_BOX_PRECEDENCE_ISOM_HDLR, 1 );
1355 if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_MDIA ) )
1356 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( hdlr, isom_mdia_t );
1357 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_META )
1358 || lsmash_check_box_type_identical( parent->type, QT_BOX_TYPE_META ) )
1359 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( hdlr, isom_meta_t );
1360 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_MINF ) )
1361 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( hdlr, isom_minf_t );
1362 else
1363 assert( 0 );
1364 return hdlr;
1367 DEFINE_SIMPLE_BOX_ADDER( isom_add_minf, minf, mdia, ISOM_BOX_TYPE_MINF, LSMASH_BOX_PRECEDENCE_ISOM_MINF )
1368 DEFINE_SIMPLE_BOX_ADDER( isom_add_vmhd, vmhd, minf, ISOM_BOX_TYPE_VMHD, LSMASH_BOX_PRECEDENCE_ISOM_VMHD )
1369 DEFINE_SIMPLE_BOX_ADDER( isom_add_smhd, smhd, minf, ISOM_BOX_TYPE_SMHD, LSMASH_BOX_PRECEDENCE_ISOM_SMHD )
1370 DEFINE_SIMPLE_BOX_ADDER( isom_add_hmhd, hmhd, minf, ISOM_BOX_TYPE_HMHD, LSMASH_BOX_PRECEDENCE_ISOM_HMHD )
1371 DEFINE_SIMPLE_BOX_ADDER( isom_add_nmhd, nmhd, minf, ISOM_BOX_TYPE_NMHD, LSMASH_BOX_PRECEDENCE_ISOM_NMHD )
1372 DEFINE_SIMPLE_BOX_ADDER( isom_add_gmhd, gmhd, minf, QT_BOX_TYPE_GMHD, LSMASH_BOX_PRECEDENCE_QTFF_GMHD )
1373 DEFINE_SIMPLE_BOX_ADDER( isom_add_gmin, gmin, gmhd, QT_BOX_TYPE_GMIN, LSMASH_BOX_PRECEDENCE_QTFF_GMIN )
1374 DEFINE_SIMPLE_BOX_ADDER( isom_add_text, text, gmhd, QT_BOX_TYPE_TEXT, LSMASH_BOX_PRECEDENCE_QTFF_TEXT )
1376 isom_dinf_t *isom_add_dinf( void *parent_box )
1378 if( !parent_box )
1379 return NULL;
1380 isom_box_t *parent = (isom_box_t *)parent_box;
1381 CREATE_BOX( dinf, parent, ISOM_BOX_TYPE_DINF, LSMASH_BOX_PRECEDENCE_ISOM_DINF, 1 );
1382 if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_MINF ) )
1383 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( dinf, isom_minf_t );
1384 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_META )
1385 || lsmash_check_box_type_identical( parent->type, QT_BOX_TYPE_META ) )
1386 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( dinf, isom_meta_t );
1387 else
1388 assert( 0 );
1389 return dinf;
1392 isom_dref_entry_t *isom_add_dref_entry( isom_dref_t *dref, lsmash_box_type_t type )
1394 if( !dref )
1395 return NULL;
1396 isom_dref_entry_t *data = lsmash_malloc_zero( sizeof(isom_dref_entry_t) );
1397 if( !data )
1398 return NULL;
1399 isom_init_box_common( data, dref, type, LSMASH_BOX_PRECEDENCE_ISOM_DREF_ENTRY, isom_remove_dref_entry );
1400 if( isom_add_box_to_extension_list( dref, data ) < 0 )
1402 lsmash_free( data );
1403 return NULL;
1405 if( lsmash_add_entry( &dref->list, data ) < 0 )
1407 lsmash_remove_entry_tail( &dref->extensions, isom_remove_dref_entry );
1408 return NULL;
1410 return data;
1413 DEFINE_SIMPLE_BOX_ADDER( isom_add_dref, dref, dinf, ISOM_BOX_TYPE_DREF, LSMASH_BOX_PRECEDENCE_ISOM_DREF )
1414 DEFINE_SIMPLE_BOX_ADDER( isom_add_stbl, stbl, minf, ISOM_BOX_TYPE_STBL, LSMASH_BOX_PRECEDENCE_ISOM_STBL )
1415 DEFINE_SIMPLE_BOX_ADDER( isom_add_stsd, stsd, stbl, ISOM_BOX_TYPE_STSD, LSMASH_BOX_PRECEDENCE_ISOM_STSD )
1417 static int isom_add_sample_description_entry
1419 isom_stsd_t *stsd,
1420 void *description,
1421 void (*destructor)( isom_sample_entry_t * )
1424 if( isom_add_box_to_extension_list( stsd, description ) < 0 )
1426 lsmash_free( description );
1427 return LSMASH_ERR_MEMORY_ALLOC;
1429 if( lsmash_add_entry( &stsd->list, description ) < 0 )
1431 lsmash_remove_entry_tail( &stsd->extensions, destructor );
1432 return LSMASH_ERR_MEMORY_ALLOC;
1434 return 0;
1437 isom_visual_entry_t *isom_add_visual_description( isom_stsd_t *stsd, lsmash_codec_type_t sample_type )
1439 assert( stsd );
1440 isom_visual_entry_t *visual = lsmash_malloc_zero( sizeof(isom_visual_entry_t) );
1441 if( !visual )
1442 return NULL;
1443 isom_init_box_common( visual, stsd, sample_type, LSMASH_BOX_PRECEDENCE_HM, isom_remove_visual_description );
1444 visual->manager |= LSMASH_VIDEO_DESCRIPTION;
1445 return isom_add_sample_description_entry( stsd, visual, isom_remove_visual_description ) ? NULL : visual;
1448 isom_audio_entry_t *isom_add_audio_description( isom_stsd_t *stsd, lsmash_codec_type_t sample_type )
1450 assert( stsd );
1451 isom_audio_entry_t *audio = lsmash_malloc_zero( sizeof(isom_audio_entry_t) );
1452 if( !audio )
1453 return NULL;
1454 isom_init_box_common( audio, stsd, sample_type, LSMASH_BOX_PRECEDENCE_HM, isom_remove_audio_description );
1455 audio->manager |= LSMASH_AUDIO_DESCRIPTION;
1456 return isom_add_sample_description_entry( stsd, audio, isom_remove_audio_description ) ? NULL : audio;
1459 isom_qt_text_entry_t *isom_add_qt_text_description( isom_stsd_t *stsd )
1461 assert( stsd );
1462 isom_qt_text_entry_t *text = lsmash_malloc_zero( sizeof(isom_qt_text_entry_t) );
1463 if( !text )
1464 return NULL;
1465 isom_init_box_common( text, stsd, QT_CODEC_TYPE_TEXT_TEXT, LSMASH_BOX_PRECEDENCE_HM, isom_remove_qt_text_description );
1466 return isom_add_sample_description_entry( stsd, text, isom_remove_qt_text_description ) ? NULL : text;
1469 isom_tx3g_entry_t *isom_add_tx3g_description( isom_stsd_t *stsd )
1471 assert( stsd );
1472 isom_tx3g_entry_t *tx3g = lsmash_malloc_zero( sizeof(isom_tx3g_entry_t) );
1473 if( !tx3g )
1474 return NULL;
1475 isom_init_box_common( tx3g, stsd, ISOM_CODEC_TYPE_TX3G_TEXT, LSMASH_BOX_PRECEDENCE_HM, isom_remove_tx3g_description );
1476 return isom_add_sample_description_entry( stsd, tx3g, isom_remove_tx3g_description ) ? NULL : tx3g;
1479 isom_esds_t *isom_add_esds( void *parent_box )
1481 isom_box_t *parent = (isom_box_t *)parent_box;
1482 int is_qt = lsmash_check_box_type_identical( parent->type, QT_BOX_TYPE_WAVE );
1483 lsmash_box_type_t box_type = is_qt ? QT_BOX_TYPE_ESDS : ISOM_BOX_TYPE_ESDS;
1484 uint64_t precedence = is_qt ? LSMASH_BOX_PRECEDENCE_QTFF_ESDS : LSMASH_BOX_PRECEDENCE_ISOM_ESDS;
1485 CREATE_BOX( esds, parent, box_type, precedence, 1 );
1486 return esds;
1489 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_glbl, glbl, parent_box, QT_BOX_TYPE_GLBL, LSMASH_BOX_PRECEDENCE_QTFF_GLBL, 1, void )
1490 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_clap, clap, visual, ISOM_BOX_TYPE_CLAP, LSMASH_BOX_PRECEDENCE_ISOM_CLAP, 0, isom_visual_entry_t )
1491 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_pasp, pasp, visual, ISOM_BOX_TYPE_PASP, LSMASH_BOX_PRECEDENCE_ISOM_PASP, 0, isom_visual_entry_t )
1492 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_colr, colr, visual, ISOM_BOX_TYPE_COLR, LSMASH_BOX_PRECEDENCE_ISOM_COLR, 0, isom_visual_entry_t )
1493 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_gama, gama, visual, QT_BOX_TYPE_GAMA, LSMASH_BOX_PRECEDENCE_QTFF_GAMA, 0, isom_visual_entry_t )
1494 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_fiel, fiel, visual, QT_BOX_TYPE_FIEL, LSMASH_BOX_PRECEDENCE_QTFF_FIEL, 0, isom_visual_entry_t )
1495 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_cspc, cspc, visual, QT_BOX_TYPE_CSPC, LSMASH_BOX_PRECEDENCE_QTFF_CSPC, 0, isom_visual_entry_t )
1496 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_sgbt, sgbt, visual, QT_BOX_TYPE_SGBT, LSMASH_BOX_PRECEDENCE_QTFF_SGBT, 0, isom_visual_entry_t )
1497 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_stsl, stsl, visual, ISOM_BOX_TYPE_STSL, LSMASH_BOX_PRECEDENCE_ISOM_STSL, 0, isom_visual_entry_t )
1498 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_btrt, btrt, visual, ISOM_BOX_TYPE_BTRT, LSMASH_BOX_PRECEDENCE_ISOM_BTRT, 0, isom_visual_entry_t )
1499 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_wave, wave, audio, QT_BOX_TYPE_WAVE, LSMASH_BOX_PRECEDENCE_QTFF_WAVE, 0, isom_audio_entry_t )
1500 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_chan, chan, audio, QT_BOX_TYPE_CHAN, LSMASH_BOX_PRECEDENCE_QTFF_CHAN, 1, isom_audio_entry_t )
1501 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_srat, srat, audio, ISOM_BOX_TYPE_SRAT, LSMASH_BOX_PRECEDENCE_ISOM_SRAT, 0, isom_audio_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_stss, stss, stbl, ISOM_BOX_TYPE_STSS, LSMASH_BOX_PRECEDENCE_ISOM_STSS )
1509 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_stps, stps, stbl, QT_BOX_TYPE_STPS, LSMASH_BOX_PRECEDENCE_QTFF_STPS )
1511 isom_stco_t *isom_add_stco( isom_stbl_t *stbl )
1513 ADD_LIST_BOX( stco, stbl, ISOM_BOX_TYPE_STCO, LSMASH_BOX_PRECEDENCE_ISOM_STCO );
1514 stco->large_presentation = 0;
1515 return stco;
1518 isom_stco_t *isom_add_co64( isom_stbl_t *stbl )
1520 ADD_LIST_BOX( stco, stbl, ISOM_BOX_TYPE_CO64, LSMASH_BOX_PRECEDENCE_ISOM_CO64 );
1521 stco->large_presentation = 1;
1522 return stco;
1525 isom_sdtp_t *isom_add_sdtp( isom_box_t *parent )
1527 if( !parent )
1528 return NULL;
1529 if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_STBL ) )
1531 isom_stbl_t *stbl = (isom_stbl_t *)parent;
1532 ADD_LIST_BOX( sdtp, stbl, ISOM_BOX_TYPE_SDTP, LSMASH_BOX_PRECEDENCE_ISOM_SDTP );
1533 return sdtp;
1535 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_TRAF ) )
1537 isom_traf_t *traf = (isom_traf_t *)parent;
1538 ADD_LIST_BOX( sdtp, traf, ISOM_BOX_TYPE_SDTP, LSMASH_BOX_PRECEDENCE_ISOM_SDTP );
1539 return sdtp;
1541 assert( 0 );
1542 return NULL;
1545 isom_sgpd_t *isom_add_sgpd( void *parent_box )
1547 if( !parent_box )
1548 return NULL;
1549 isom_box_t *parent = (isom_box_t *)parent_box;
1550 if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_STBL ) )
1552 isom_stbl_t *stbl = (isom_stbl_t *)parent;
1553 ADD_LIST_BOX_IN_LIST( sgpd, stbl, ISOM_BOX_TYPE_SGPD, LSMASH_BOX_PRECEDENCE_ISOM_SGPD );
1554 return sgpd;
1556 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_TRAF ) )
1558 isom_traf_t *traf = (isom_traf_t *)parent;
1559 ADD_LIST_BOX_IN_LIST( sgpd, traf, ISOM_BOX_TYPE_SGPD, LSMASH_BOX_PRECEDENCE_ISOM_SGPD );
1560 return sgpd;
1562 assert( 0 );
1563 return NULL;
1566 isom_sbgp_t *isom_add_sbgp( void *parent_box )
1568 if( !parent_box )
1569 return NULL;
1570 isom_box_t *parent = (isom_box_t *)parent_box;
1571 if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_STBL ) )
1573 isom_stbl_t *stbl = (isom_stbl_t *)parent;
1574 ADD_LIST_BOX_IN_LIST( sbgp, stbl, ISOM_BOX_TYPE_SBGP, LSMASH_BOX_PRECEDENCE_ISOM_SBGP );
1575 return sbgp;
1577 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_TRAF ) )
1579 isom_traf_t *traf = (isom_traf_t *)parent;
1580 ADD_LIST_BOX_IN_LIST( sbgp, traf, ISOM_BOX_TYPE_SBGP, LSMASH_BOX_PRECEDENCE_ISOM_SBGP );
1581 return sbgp;
1583 assert( 0 );
1584 return NULL;
1587 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_chpl, chpl, udta, ISOM_BOX_TYPE_CHPL, LSMASH_BOX_PRECEDENCE_ISOM_CHPL )
1589 isom_metaitem_t *isom_add_metaitem( isom_ilst_t *ilst, lsmash_itunes_metadata_item item )
1591 if( !ilst )
1592 return NULL;
1593 lsmash_box_type_t type = lsmash_form_iso_box_type( item );
1594 ADD_BOX_IN_LIST( metaitem, ilst, type, LSMASH_BOX_PRECEDENCE_ISOM_METAITEM );
1595 return metaitem;
1598 DEFINE_SIMPLE_BOX_ADDER ( isom_add_mean, mean, metaitem, ISOM_BOX_TYPE_MEAN, LSMASH_BOX_PRECEDENCE_ISOM_MEAN )
1599 DEFINE_SIMPLE_BOX_ADDER ( isom_add_name, name, metaitem, ISOM_BOX_TYPE_NAME, LSMASH_BOX_PRECEDENCE_ISOM_NAME )
1600 DEFINE_SIMPLE_BOX_ADDER ( isom_add_data, data, metaitem, ISOM_BOX_TYPE_DATA, LSMASH_BOX_PRECEDENCE_ISOM_DATA )
1601 DEFINE_SIMPLE_BOX_ADDER ( isom_add_ilst, ilst, meta, ISOM_BOX_TYPE_ILST, LSMASH_BOX_PRECEDENCE_ISOM_ILST )
1602 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_keys, keys, meta, QT_BOX_TYPE_KEYS, LSMASH_BOX_PRECEDENCE_QTFF_KEYS )
1604 isom_meta_t *isom_add_meta( void *parent_box )
1606 if( !parent_box )
1607 return NULL;
1608 isom_box_t *parent = (isom_box_t *)parent_box;
1609 CREATE_BOX( meta, parent, ISOM_BOX_TYPE_META, LSMASH_BOX_PRECEDENCE_ISOM_META, 1 );
1610 if( parent->file == (lsmash_file_t *)parent )
1611 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( meta, lsmash_file_t );
1612 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_MOOV ) )
1613 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( meta, isom_moov_t );
1614 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_TRAK ) )
1615 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( meta, isom_trak_t );
1616 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_UDTA ) )
1617 ATTACH_EXACTLY_ONE_BOX_TO_PARENT( meta, isom_udta_t );
1618 else
1619 assert( 0 );
1620 return meta;
1623 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_cprt, cprt, udta, ISOM_BOX_TYPE_CPRT, LSMASH_BOX_PRECEDENCE_ISOM_CPRT )
1625 isom_udta_t *isom_add_udta( void *parent_box )
1627 if( !parent_box )
1628 return NULL;
1629 isom_box_t *parent = (isom_box_t *)parent_box;
1630 if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_MOOV ) )
1632 isom_moov_t *moov = (isom_moov_t *)parent;
1633 ADD_BOX( udta, moov, ISOM_BOX_TYPE_UDTA, LSMASH_BOX_PRECEDENCE_ISOM_UDTA );
1634 return udta;
1636 else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_TRAK ) )
1638 isom_trak_t *trak = (isom_trak_t *)parent;
1639 ADD_BOX( udta, trak, ISOM_BOX_TYPE_UDTA, LSMASH_BOX_PRECEDENCE_ISOM_UDTA );
1640 return udta;
1642 assert( 0 );
1643 return NULL;
1646 DEFINE_SIMPLE_BOX_ADDER ( isom_add_WLOC, WLOC, udta, QT_BOX_TYPE_WLOC, LSMASH_BOX_PRECEDENCE_QTFF_WLOC )
1647 DEFINE_SIMPLE_BOX_ADDER ( isom_add_LOOP, LOOP, udta, QT_BOX_TYPE_LOOP, LSMASH_BOX_PRECEDENCE_QTFF_LOOP )
1648 DEFINE_SIMPLE_BOX_ADDER ( isom_add_SelO, SelO, udta, QT_BOX_TYPE_SELO, LSMASH_BOX_PRECEDENCE_QTFF_SELO )
1649 DEFINE_SIMPLE_BOX_ADDER ( isom_add_AllF, AllF, udta, QT_BOX_TYPE_ALLF, LSMASH_BOX_PRECEDENCE_QTFF_ALLF )
1650 DEFINE_SIMPLE_BOX_ADDER ( isom_add_mvex, mvex, moov, ISOM_BOX_TYPE_MVEX, LSMASH_BOX_PRECEDENCE_ISOM_MVEX )
1651 DEFINE_SIMPLE_BOX_ADDER ( isom_add_mehd, mehd, mvex, ISOM_BOX_TYPE_MEHD, LSMASH_BOX_PRECEDENCE_ISOM_MEHD )
1652 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_trex, trex, mvex, ISOM_BOX_TYPE_TREX, LSMASH_BOX_PRECEDENCE_ISOM_TREX )
1653 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_moof, moof, file, ISOM_BOX_TYPE_MOOF, LSMASH_BOX_PRECEDENCE_ISOM_MOOF, lsmash_file_t )
1654 DEFINE_SIMPLE_BOX_ADDER ( isom_add_mfhd, mfhd, moof, ISOM_BOX_TYPE_MFHD, LSMASH_BOX_PRECEDENCE_ISOM_MFHD )
1655 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_traf, traf, moof, ISOM_BOX_TYPE_TRAF, LSMASH_BOX_PRECEDENCE_ISOM_TRAF )
1656 DEFINE_SIMPLE_BOX_ADDER ( isom_add_tfhd, tfhd, traf, ISOM_BOX_TYPE_TFHD, LSMASH_BOX_PRECEDENCE_ISOM_TFHD )
1657 DEFINE_SIMPLE_BOX_ADDER ( isom_add_tfdt, tfdt, traf, ISOM_BOX_TYPE_TFDT, LSMASH_BOX_PRECEDENCE_ISOM_TFDT )
1658 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_trun, trun, traf, ISOM_BOX_TYPE_TRUN, LSMASH_BOX_PRECEDENCE_ISOM_TRUN )
1659 DEFINE_SIMPLE_BOX_ADDER ( isom_add_mfra, mfra, file, ISOM_BOX_TYPE_MFRA, LSMASH_BOX_PRECEDENCE_ISOM_MFRA, lsmash_file_t )
1660 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_tfra, tfra, mfra, ISOM_BOX_TYPE_TFRA, LSMASH_BOX_PRECEDENCE_ISOM_TFRA )
1661 DEFINE_SIMPLE_BOX_ADDER ( isom_add_mfro, mfro, mfra, ISOM_BOX_TYPE_MFRO, LSMASH_BOX_PRECEDENCE_ISOM_MFRO )
1663 isom_mdat_t *isom_add_mdat( lsmash_file_t *file )
1665 assert( !file->mdat );
1666 CREATE_BOX( mdat, file, ISOM_BOX_TYPE_MDAT, LSMASH_BOX_PRECEDENCE_ISOM_MDAT, 1 );
1667 file->mdat = mdat;
1668 return mdat;
1671 isom_free_t *isom_add_free( void *parent_box )
1673 if( !parent_box )
1674 return NULL;
1675 isom_box_t *parent = (isom_box_t *)parent_box;
1676 if( parent->file == (lsmash_file_t *)parent )
1678 lsmash_file_t *file = (lsmash_file_t *)parent;
1679 CREATE_BOX( skip, file, ISOM_BOX_TYPE_FREE, LSMASH_BOX_PRECEDENCE_ISOM_FREE, 1 );
1680 if( !file->free )
1681 file->free = skip;
1682 return skip;
1684 CREATE_BOX( skip, parent, ISOM_BOX_TYPE_FREE, LSMASH_BOX_PRECEDENCE_ISOM_FREE, 1 );
1685 return skip;
1688 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_styp, styp, file, ISOM_BOX_TYPE_STYP, LSMASH_BOX_PRECEDENCE_ISOM_STYP, lsmash_file_t )
1690 isom_sidx_t *isom_add_sidx( lsmash_file_t *file )
1692 ADD_LIST_BOX_IN_LIST( sidx, file, ISOM_BOX_TYPE_SIDX, LSMASH_BOX_PRECEDENCE_ISOM_SIDX );
1693 return sidx;
1696 #undef ATTACH_EXACTLY_ONE_BOX_TO_PARENT
1697 #undef CREATE_BOX
1698 #undef CREATE_LIST_BOX
1699 #undef ADD_BOX_TEMPLATE
1700 #undef ADD_BOX_IN_LIST_TEMPLATE
1701 #undef ADD_BOX
1702 #undef ADD_BOX_IN_LIST
1703 #undef ADD_LIST_BOX
1704 #undef ADD_LIST_BOX_IN_LIST
1705 #undef DEFINE_SIMPLE_BOX_ADDER_TEMPLATE
1706 #undef DEFINE_SIMPLE_BOX_ADDER_TEMPLATE_6
1707 #undef DEFINE_SIMPLE_BOX_ADDER_TEMPLATE_5
1708 #undef DEFINE_SIMPLE_BOX_ADDER
1709 #undef DEFINE_SIMPLE_BOX_IN_LIST_ADDER
1710 #undef DEFINE_SIMPLE_LIST_BOX_ADDER
1712 static int fake_file_read
1714 void *opaque,
1715 uint8_t *buf,
1716 int size
1719 fake_file_stream_t *stream = (fake_file_stream_t *)opaque;
1720 int read_size;
1721 if( stream->pos + size > stream->size )
1722 read_size = stream->size - stream->pos;
1723 else
1724 read_size = size;
1725 memcpy( buf, stream->data + stream->pos, read_size );
1726 stream->pos += read_size;
1727 return read_size;
1730 static int64_t fake_file_seek
1732 void *opaque,
1733 int64_t offset,
1734 int whence
1737 fake_file_stream_t *stream = (fake_file_stream_t *)opaque;
1738 if( whence == SEEK_SET )
1739 stream->pos = offset;
1740 else if( whence == SEEK_CUR )
1741 stream->pos += offset;
1742 else if( whence == SEEK_END )
1743 stream->pos = stream->size + offset;
1744 return stream->pos;
1747 /* Public functions */
1748 lsmash_root_t *lsmash_create_root( void )
1750 lsmash_root_t *root = lsmash_malloc_zero( sizeof(lsmash_root_t) );
1751 if( !root )
1752 return NULL;
1753 root->root = root;
1754 return root;
1757 void lsmash_destroy_root( lsmash_root_t *root )
1759 isom_remove_box_by_itself( root );
1762 lsmash_extended_box_type_t lsmash_form_extended_box_type( uint32_t fourcc, const uint8_t id[12] )
1764 return (lsmash_extended_box_type_t){ fourcc, { id[0], id[1], id[2], id[3], id[4], id[5],
1765 id[6], id[7], id[8], id[9], id[10], id[11] } };
1768 lsmash_box_type_t lsmash_form_iso_box_type( uint32_t fourcc )
1770 return (lsmash_box_type_t){ fourcc, lsmash_form_extended_box_type( fourcc, LSMASH_ISO_12_BYTES ) };
1773 lsmash_box_type_t lsmash_form_qtff_box_type( uint32_t fourcc )
1775 return (lsmash_box_type_t){ fourcc, lsmash_form_extended_box_type( fourcc, LSMASH_QTFF_12_BYTES ) };
1778 #define CHECK_BOX_TYPE_IDENTICAL( a, b ) \
1779 a.fourcc == b.fourcc \
1780 && a.user.fourcc == b.user.fourcc \
1781 && a.user.id[0] == b.user.id[0] \
1782 && a.user.id[1] == b.user.id[1] \
1783 && a.user.id[2] == b.user.id[2] \
1784 && a.user.id[3] == b.user.id[3] \
1785 && a.user.id[4] == b.user.id[4] \
1786 && a.user.id[5] == b.user.id[5] \
1787 && a.user.id[6] == b.user.id[6] \
1788 && a.user.id[7] == b.user.id[7] \
1789 && a.user.id[8] == b.user.id[8] \
1790 && a.user.id[9] == b.user.id[9] \
1791 && a.user.id[10] == b.user.id[10] \
1792 && a.user.id[11] == b.user.id[11]
1794 int lsmash_check_box_type_identical( lsmash_box_type_t a, lsmash_box_type_t b )
1796 return CHECK_BOX_TYPE_IDENTICAL( a, b );
1799 int lsmash_check_codec_type_identical( lsmash_codec_type_t a, lsmash_codec_type_t b )
1801 return CHECK_BOX_TYPE_IDENTICAL( a, b );
1804 int lsmash_check_box_type_specified( const lsmash_box_type_t *box_type )
1806 assert( box_type );
1807 if( !box_type )
1808 return 0;
1809 return !!(box_type->fourcc
1810 | box_type->user.fourcc
1811 | box_type->user.id[0] | box_type->user.id[1] | box_type->user.id[2] | box_type->user.id[3]
1812 | box_type->user.id[4] | box_type->user.id[5] | box_type->user.id[6] | box_type->user.id[7]
1813 | box_type->user.id[8] | box_type->user.id[9] | box_type->user.id[10] | box_type->user.id[11]);
1816 lsmash_box_t *lsmash_get_box
1818 lsmash_box_t *parent,
1819 const lsmash_box_path_t box_path[]
1822 lsmash_entry_t *entry = isom_get_entry_of_box( parent, box_path );
1823 return (lsmash_box_t *)(entry ? entry->data : NULL);
1826 lsmash_box_t *lsmash_create_box
1828 lsmash_box_type_t type,
1829 uint8_t *data,
1830 uint32_t size,
1831 uint64_t precedence
1834 if( !lsmash_check_box_type_specified( &type ) )
1835 return NULL;
1836 isom_unknown_box_t *box = lsmash_malloc_zero( sizeof(isom_unknown_box_t) );
1837 if( !box )
1838 return NULL;
1839 if( size && data )
1841 box->unknown_size = size;
1842 box->unknown_field = lsmash_memdup( data, size );
1843 if( !box->unknown_field )
1845 lsmash_free( box );
1846 return NULL;
1849 else
1851 box->unknown_size = 0;
1852 box->unknown_field = NULL;
1853 size = 0;
1855 box->class = &lsmash_box_class;
1856 box->root = NULL;
1857 box->file = NULL;
1858 box->parent = NULL;
1859 box->destruct = (isom_extension_destructor_t)isom_remove_unknown_box;
1860 box->manager = LSMASH_UNKNOWN_BOX;
1861 box->precedence = precedence;
1862 box->size = ISOM_BASEBOX_COMMON_SIZE + size + (type.fourcc == ISOM_BOX_TYPE_UUID.fourcc ? 16 : 0);
1863 box->type = type;
1864 isom_set_box_writer( (isom_box_t *)box );
1865 return (lsmash_box_t *)box;
1868 int lsmash_add_box
1870 lsmash_box_t *parent,
1871 lsmash_box_t *box
1874 if( !parent )
1875 /* You cannot add any box without a box being its parent. */
1876 return LSMASH_ERR_FUNCTION_PARAM;
1877 if( !box || box->size < ISOM_BASEBOX_COMMON_SIZE )
1878 return LSMASH_ERR_FUNCTION_PARAM;
1879 if( parent->root == (lsmash_root_t *)parent )
1881 /* Only files can be added into any ROOT.
1882 * For backward compatibility, use the active file as the parent. */
1883 if( parent->file )
1884 parent = (isom_box_t *)parent->file;
1885 else
1886 return LSMASH_ERR_FUNCTION_PARAM;
1888 /* Add a box as a child box. */
1889 box->root = parent->root;
1890 box->file = parent->file;
1891 box->parent = parent;
1892 return isom_add_box_to_extension_list( parent, box );
1895 int lsmash_add_box_ex
1897 lsmash_box_t *parent,
1898 lsmash_box_t **p_box
1901 if( !parent )
1902 /* You cannot add any box without a box being its parent. */
1903 return LSMASH_ERR_FUNCTION_PARAM;
1904 isom_unknown_box_t *box = (isom_unknown_box_t *)*p_box;
1905 if( !box || box->size < ISOM_BASEBOX_COMMON_SIZE )
1906 return LSMASH_ERR_FUNCTION_PARAM;
1907 if( !(box->manager & LSMASH_UNKNOWN_BOX) )
1908 /* Simply add the box. */
1909 return lsmash_add_box( parent, *p_box );
1910 /* Check if the size of the box to be added is valid. */
1911 if( box->size != ISOM_BASEBOX_COMMON_SIZE + box->unknown_size + (box->type.fourcc == ISOM_BOX_TYPE_UUID.fourcc ? 16 : 0) )
1912 return LSMASH_ERR_FUNCTION_PARAM;
1913 if( !parent->file || parent->file == (lsmash_file_t *)box )
1914 return LSMASH_ERR_FUNCTION_PARAM;
1915 if( parent->root == (lsmash_root_t *)parent )
1916 /* Only files can be added into any ROOT.
1917 * For backward compatibility, use the active file as the parent. */
1918 parent = (isom_box_t *)parent->file;
1919 /* Switch to the fake-file stream mode. */
1920 lsmash_file_t *file = parent->file;
1921 lsmash_bs_t *bs_backup = file->bs;
1922 lsmash_bs_t *bs = lsmash_bs_create();
1923 if( !bs )
1924 return LSMASH_ERR_MEMORY_ALLOC;
1925 uint8_t *buf = lsmash_malloc( box->size );
1926 if( !buf )
1928 lsmash_bs_cleanup( bs );
1929 return LSMASH_ERR_MEMORY_ALLOC;
1931 fake_file_stream_t fake_file =
1933 .size = box->size,
1934 .data = buf,
1935 .pos = 0
1937 bs->stream = &fake_file;
1938 bs->read = fake_file_read;
1939 bs->write = NULL;
1940 bs->seek = fake_file_seek;
1941 file->bs = bs;
1942 file->fake_file_mode = 1;
1943 /* Make the byte string representing the given box. */
1944 LSMASH_SET_BE32( &buf[0], box->size );
1945 LSMASH_SET_BE32( &buf[4], box->type.fourcc );
1946 if( box->type.fourcc == ISOM_BOX_TYPE_UUID.fourcc )
1948 LSMASH_SET_BE32( &buf[8], box->type.user.fourcc );
1949 memcpy( &buf[12], box->type.user.id, 12 );
1951 memcpy( buf + (uintptr_t)(box->size - box->unknown_size), box->unknown_field, box->unknown_size );
1952 /* Add a box as a child box and try to expand into struct format. */
1953 lsmash_box_t dummy = { 0 };
1954 int ret = isom_read_box( file, &dummy, parent, 0, 0 );
1955 lsmash_free( buf );
1956 lsmash_bs_cleanup( bs );
1957 file->bs = bs_backup; /* Switch back to the normal file stream mode. */
1958 file->fake_file_mode = 0;
1959 if( ret < 0 )
1960 return ret;
1961 /* Reorder the added box by 'precedence'. */
1962 *p_box = (lsmash_box_t *)parent->extensions.tail->data;
1963 (*p_box)->precedence = box->precedence;
1964 isom_reorder_tail_box( parent );
1965 /* Do also its children by the same way. */
1966 lsmash_entry_list_t extensions = box->extensions;
1967 lsmash_init_entry_list( &box->extensions ); /* to avoid freeing the children */
1968 isom_remove_box_by_itself( box );
1969 for( lsmash_entry_t *entry = extensions.head; entry; entry = entry->next )
1971 if( !entry->data )
1972 continue;
1973 lsmash_box_t *child = (lsmash_box_t *)entry->data;
1974 if( lsmash_add_box_ex( *p_box, &child ) == 0 )
1976 (*p_box)->size += child->size;
1977 /* Avoid freeing at the end of this function. */
1978 entry->data = NULL;
1981 isom_remove_all_extension_boxes( &extensions );
1982 return 0;
1985 void lsmash_destroy_box
1987 lsmash_box_t *box
1990 isom_remove_box_by_itself( box );
1993 void lsmash_destroy_children
1995 lsmash_box_t *box
1998 if( box )
1999 isom_remove_all_extension_boxes( &box->extensions );
2002 int lsmash_get_box_precedence
2004 lsmash_box_t *box,
2005 uint64_t *precedence
2008 if( !box || !precedence )
2009 return LSMASH_ERR_FUNCTION_PARAM;
2010 *precedence = box->precedence;
2011 return 0;
2014 lsmash_box_t *lsmash_root_as_box
2016 lsmash_root_t *root
2019 return (lsmash_box_t *)root;
2022 lsmash_box_t *lsmash_file_as_box
2024 lsmash_file_t *file
2027 return (lsmash_box_t *)file;
2030 int lsmash_write_top_level_box
2032 lsmash_box_t *box
2035 if( !box || (isom_box_t *)box->file != box->parent )
2036 return LSMASH_ERR_FUNCTION_PARAM;
2037 int ret = isom_write_box( box->file->bs, box );
2038 if( ret < 0 )
2039 return ret;
2040 box->file->size += box->size;
2041 return 0;
2044 uint8_t *lsmash_export_box
2046 lsmash_box_t *box,
2047 uint32_t *size
2050 if( !box || !size )
2051 return NULL;
2052 lsmash_bs_t *bs = lsmash_bs_create();
2053 if( !bs )
2054 return NULL;
2055 if( isom_write_box( bs, box ) < 0 )
2057 lsmash_bs_cleanup( bs );
2058 return NULL;
2060 *size = bs->buffer.store;
2061 uint8_t *data = bs->buffer.data;
2062 bs->buffer.data = NULL;
2063 lsmash_bs_cleanup( bs );
2064 return data;