1 /*****************************************************************************
2  * box.c
3  *****************************************************************************
4  * Copyright (C) 2012-2017 L-SMASH project
5  *
6  * Authors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
7  *
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.
11  *
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  *****************************************************************************/
20 
21 /* This file is available under an ISC license. */
22 
23 #include "common/internal.h" /* must be placed first */
24 
25 #include <stdlib.h>
26 #include <string.h>
27 
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"
34 
35 #include "codecs/mp4a.h"
36 #include "codecs/mp4sys.h"
37 
38 #include "importer/importer.h"
39 
40 static const lsmash_class_t lsmash_box_class =
41 {
42     "box"
43 };
44 
45 const lsmash_box_type_t static_lsmash_box_type_unspecified = LSMASH_BOX_TYPE_INITIALIZER;
46 
isom_init_box_common_orig(void * _box,void * _parent,lsmash_box_type_t box_type,uint64_t precedence,isom_extension_destructor_t destructor)47 void isom_init_box_common_orig
48 (
49     void                       *_box,
50     void                       *_parent,
51     lsmash_box_type_t           box_type,
52     uint64_t                    precedence,
53     isom_extension_destructor_t destructor
54 )
55 {
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 ) )
68     {
69         box->version = 0;
70         box->flags   = 0;
71     }
72     isom_set_box_writer( box );
73 }
74 
isom_reorder_tail_box(isom_box_t * parent)75 static void isom_reorder_tail_box( isom_box_t *parent )
76 {
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 )
82     {
83         isom_box_t *box = (isom_box_t *)y->data;
84         if( LSMASH_IS_NON_EXISTING_BOX( box ) || precedence > box->precedence )
85         {
86             /* Exchange the entity data of adjacent two entries. */
87             y->data = x->data;
88             x->data = box;
89             x = y;
90         }
91         else
92             break;
93     }
94 }
95 
isom_add_box_to_extension_list(void * parent_box,void * child_box)96 int isom_add_box_to_extension_list( void *parent_box, void *child_box )
97 {
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;
111 }
112 
isom_bs_put_basebox_common(lsmash_bs_t * bs,isom_box_t * box)113 void isom_bs_put_basebox_common( lsmash_bs_t *bs, isom_box_t *box )
114 {
115     if( box->size > UINT32_MAX )
116     {
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 */
120     }
121     else
122     {
123         lsmash_bs_put_be32( bs, (uint32_t)box->size );
124         lsmash_bs_put_be32( bs, box->type.fourcc );
125     }
126     if( box->type.fourcc == ISOM_BOX_TYPE_UUID.fourcc )
127     {
128         lsmash_bs_put_be32( bs, box->type.user.fourcc );
129         lsmash_bs_put_bytes( bs, 12, box->type.user.id );
130     }
131 }
132 
isom_bs_put_fullbox_common(lsmash_bs_t * bs,isom_box_t * box)133 void isom_bs_put_fullbox_common( lsmash_bs_t *bs, isom_box_t *box )
134 {
135     isom_bs_put_basebox_common( bs, box );
136     lsmash_bs_put_byte( bs, box->version );
137     lsmash_bs_put_be24( bs, box->flags );
138 }
139 
isom_bs_put_box_common(lsmash_bs_t * bs,void * box)140 void isom_bs_put_box_common( lsmash_bs_t *bs, void *box )
141 {
142     if( !box )
143     {
144         bs->error = 1;
145         return;
146     }
147     isom_box_t *parent = ((isom_box_t *)box)->parent;
148     if( parent && lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_STSD ) )
149     {
150         isom_bs_put_basebox_common( bs, (isom_box_t *)box );
151         return;
152     }
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 );
157 }
158 
159 /* Return 1 if the box is fullbox, Otherwise return 0. */
isom_is_fullbox(const void * box)160 int isom_is_fullbox( const void *box )
161 {
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] ) )
166     {
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;
218     }
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 )
223     {
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;
228     }
229     return 0;
230 }
231 
232 /* Return 1 if the sample type is LPCM audio, Otherwise return 0. */
isom_is_lpcm_audio(const void * box)233 int isom_is_lpcm_audio( const void *box )
234 {
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));
248 }
249 
isom_is_qt_audio(lsmash_codec_type_t type)250 int isom_is_qt_audio( lsmash_codec_type_t type )
251 {
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 );
285 }
286 
287 /* Return 1 if the sample type is uncompressed Y'CbCr video, Otherwise return 0. */
isom_is_uncompressed_ycbcr(lsmash_codec_type_t type)288 int isom_is_uncompressed_ycbcr( lsmash_codec_type_t type )
289 {
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 );
297 }
298 
isom_is_waveform_audio(lsmash_box_type_t type)299 int isom_is_waveform_audio( lsmash_box_type_t type )
300 {
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 );
306 }
307 
isom_skip_box_common(uint8_t ** p_data)308 size_t isom_skip_box_common( uint8_t **p_data )
309 {
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 )
315     {
316         /* 'size = LSMASH_GET_BE64( data );' is a dead assignment here. */
317         data += 8;
318     }
319     *p_data = data;
320     return data - orig;
321 }
322 
323 /* TODO: more secure handling */
isom_read_box_size_and_type_from_binary_string(uint8_t ** p_data,uint64_t * size,lsmash_box_type_t * type)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 )
325 {
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 )
332     {
333         *size = LSMASH_GET_BE64( data );
334         data += 8;
335     }
336     *p_data = data;
337     if( type->fourcc == ISOM_BOX_TYPE_UUID.fourcc )
338     {
339         type->user.fourcc = LSMASH_GET_BE32( &data[0] );
340         memcpy( type->user.id, &data[4], 12 );
341     }
342     return data - orig;
343 }
344 
isom_get_child_box_position(uint8_t * parent_data,uint32_t parent_size,lsmash_box_type_t child_type,uint32_t * child_size)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 )
346 {
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; )
357     {
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 ) )
360         {
361             *child_size = size;
362             return pos - offset;
363         }
364         pos += size - offset;   /* Move to the next box. */
365     }
366     return NULL;
367 }
368 
isom_destruct_extension_binary(void * ext)369 static void isom_destruct_extension_binary( void *ext )
370 {
371     if( !ext )
372         return;
373     isom_box_t *box = (isom_box_t *)ext;
374     lsmash_free( box->binary );
375 }
376 
isom_add_extension_binary(void * parent_box,lsmash_box_type_t box_type,uint64_t precedence,uint8_t * box_data,uint32_t box_size)377 int isom_add_extension_binary
378 (
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
384 )
385 {
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 )
404     {
405         lsmash_free( ext );
406         return LSMASH_ERR_MEMORY_ALLOC;
407     }
408     isom_set_box_writer( ext );
409     return 0;
410 }
411 
isom_remove_extension_box(isom_box_t * ext)412 void isom_remove_extension_box( isom_box_t *ext )
413 {
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 );
420 }
421 
isom_remove_all_extension_boxes(lsmash_entry_list_t * extensions)422 void isom_remove_all_extension_boxes( lsmash_entry_list_t *extensions )
423 {
424     lsmash_list_remove_entries( extensions );
425 }
426 
isom_get_extension_box(lsmash_entry_list_t * extensions,lsmash_box_type_t box_type)427 isom_box_t *isom_get_extension_box( lsmash_entry_list_t *extensions, lsmash_box_type_t box_type )
428 {
429     for( lsmash_entry_t *entry = extensions->head; entry; entry = entry->next )
430     {
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;
436     }
437     return (isom_box_t *)isom_non_existing_unknown();
438 }
439 
isom_get_extension_box_format(lsmash_entry_list_t * extensions,lsmash_box_type_t box_type)440 void *isom_get_extension_box_format( lsmash_entry_list_t *extensions, lsmash_box_type_t box_type )
441 {
442     for( lsmash_entry_t *entry = extensions->head; entry; entry = entry->next )
443     {
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;
450     }
451     return isom_non_existing_unknown();
452 }
453 
isom_get_entry_of_box(lsmash_box_t * parent,const lsmash_box_path_t box_path[])454 lsmash_entry_t *isom_get_entry_of_box
455 (
456     lsmash_box_t           *parent,
457     const lsmash_box_path_t box_path[]
458 )
459 {
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 ) )
465     {
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 )
473         {
474             isom_box_t *box = entry->data;
475             if( box && lsmash_check_box_type_identical( path->type, box->type ) )
476             {
477                 if( i == number )
478                 {
479                     /* Found a box. Move to a child box. */
480                     parent = box;
481                     ++path;
482                     break;
483                 }
484                 ++i;
485             }
486             entry = entry->next;
487         }
488         if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
489             return NULL;
490     }
491     return entry;
492 }
493 
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 )
499 
500 #define REMOVE_BOX_IN_LIST( box_name ) \
501         isom_remove_box_in_predefined_list( box_name )
502 
503 #define REMOVE_LIST_BOX_TEMPLATE( REMOVER, box_name ) \
504     do                                                \
505     {                                                 \
506         lsmash_list_destroy( box_name->list );        \
507         REMOVER( box_name );                          \
508     } while( 0 )
509 
510 #define REMOVE_LIST_BOX( box_name ) \
511         REMOVE_LIST_BOX_TEMPLATE( REMOVE_BOX, box_name )
512 
513 #define REMOVE_LIST_BOX_IN_LIST( box_name ) \
514         REMOVE_LIST_BOX_TEMPLATE( REMOVE_BOX_IN_LIST, box_name )
515 
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 ) \
520     {                                                                   \
521         REMOVER( box_name, __VA_ARGS__ );                               \
522     }
523 #define DEFINE_SIMPLE_BOX_REMOVER_TEMPLATE_2( REMOVER, box_name )       \
524     static void isom_remove_##box_name( isom_##box_name##_t *box_name ) \
525     {                                                                   \
526         REMOVER( box_name );                                            \
527     }
528 
529 #define DEFINE_SIMPLE_BOX_REMOVER( func_name, box_name )   \
530         DEFINE_SIMPLE_BOX_REMOVER_TEMPLATE( REMOVE_BOX, box_name )
531 
532 #define DEFINE_SIMPLE_BOX_IN_LIST_REMOVER( func_name, box_name ) \
533         DEFINE_SIMPLE_BOX_REMOVER_TEMPLATE( REMOVE_BOX_IN_LIST, box_name )
534 
535 #define DEFINE_SIMPLE_LIST_BOX_REMOVER( func_name, box_name ) \
536         DEFINE_SIMPLE_BOX_REMOVER_TEMPLATE( REMOVE_LIST_BOX, box_name )
537 
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 )
540 
isom_remove_predefined_box(void * opaque_box)541 static void isom_remove_predefined_box( void *opaque_box )
542 {
543     isom_box_t *box = (isom_box_t *)opaque_box;
544     if( LSMASH_IS_EXISTING_BOX( box )
545      && LSMASH_IS_EXISTING_BOX( box->parent ) )
546     {
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;
550     }
551 }
552 
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. */
isom_remove_box_in_predefined_list(void * opaque_box)555 static void isom_remove_box_in_predefined_list( void *opaque_box )
556 {
557     isom_box_t *box = (isom_box_t *)opaque_box;
558     if( LSMASH_IS_EXISTING_BOX( box )
559      && LSMASH_IS_EXISTING_BOX( box->parent ) )
560     {
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 )
565                 {
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;
572                 }
573     }
574 }
575 
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. */
isom_remove_box_by_itself(void * opaque_box)580 void isom_remove_box_by_itself( void *opaque_box )
581 {
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 ) )
586     {
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 )
590             {
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;
595             }
596     }
597     isom_remove_extension_box( box );
598 }
599 
isom_remove_unknown_box(isom_unknown_box_t * unknown_box)600 void isom_remove_unknown_box( isom_unknown_box_t *unknown_box )
601 {
602     lsmash_free( unknown_box->unknown_field );
603 }
604 
isom_remove_file_abstract(isom_file_abstract_t * file_abstract)605 static void isom_remove_file_abstract( isom_file_abstract_t *file_abstract )
606 {
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 )
615     {
616         lsmash_list_destroy( file_abstract->fragment->pool );
617         lsmash_free( file_abstract->fragment );
618     }
619     REMOVE_BOX_IN_LIST( file_abstract );
620 }
621 
isom_remove_ftyp(isom_ftyp_t * ftyp)622 static void isom_remove_ftyp( isom_ftyp_t *ftyp )
623 {
624     lsmash_free( ftyp->compatible_brands );
625     REMOVE_BOX( ftyp );
626 }
627 
isom_remove_iods(isom_iods_t * iods)628 static void isom_remove_iods( isom_iods_t *iods )
629 {
630     if( LSMASH_IS_NON_EXISTING_BOX( iods ) )
631         return;
632     mp4sys_remove_descriptor( iods->OD );
633     REMOVE_BOX( iods );
634 }
635 
isom_remove_trak(isom_trak_t * trak)636 static void isom_remove_trak( isom_trak_t *trak )
637 {
638     if( trak->cache )
639     {
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 );
645     }
646     REMOVE_BOX_IN_LIST( trak );
647 }
648 
DEFINE_SIMPLE_BOX_REMOVER(isom_remove_tkhd,tkhd)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 )
657 
658 static void isom_remove_track_reference_type( isom_tref_type_t *ref )
659 {
660     lsmash_free( ref->track_ID );
661     isom_remove_box_in_predefined_list( ref );
662 }
663 
DEFINE_SIMPLE_BOX_REMOVER(isom_remove_mdhd,mdhd)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 )
672 
673 static void isom_remove_hdlr( isom_hdlr_t *hdlr )
674 {
675     lsmash_free( hdlr->componentName );
676     REMOVE_BOX( hdlr );
677 }
678 
isom_remove_glbl(isom_glbl_t * glbl)679 static void isom_remove_glbl( isom_glbl_t *glbl )
680 {
681     lsmash_free( glbl->header_data );
682 }
683 
isom_remove_esds(isom_esds_t * esds)684 static void isom_remove_esds( isom_esds_t *esds )
685 {
686     if( LSMASH_IS_NON_EXISTING_BOX( esds ) )
687         return;
688     mp4sys_remove_descriptor( esds->ES );
689 }
690 
DEFINE_SIMPLE_LIST_BOX_REMOVER(isom_remove_ftab,ftab)691 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_ftab, ftab )
692 
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 )
697 
698 static void isom_remove_chan( isom_chan_t *chan )
699 {
700     lsmash_free( chan->channelDescriptions );
701 }
702 
DEFINE_SIMPLE_BOX_REMOVER(isom_remove_stsd,stsd)703 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_stsd, stsd )
704 
705 static void isom_remove_visual_description( isom_sample_entry_t *description )
706 {
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 );
710 }
711 
isom_remove_audio_description(isom_sample_entry_t * description)712 static void isom_remove_audio_description( isom_sample_entry_t *description )
713 {
714     isom_remove_box_in_predefined_list( description );
715 }
716 
isom_remove_hint_description(isom_sample_entry_t * description)717 static void isom_remove_hint_description( isom_sample_entry_t *description )
718 {
719     isom_hint_entry_t *hint = (isom_hint_entry_t *)description;
720     lsmash_free( hint->data );
721     isom_remove_box_in_predefined_list( hint );
722 }
723 
isom_remove_metadata_description(isom_sample_entry_t * description)724 static void isom_remove_metadata_description( isom_sample_entry_t *description )
725 {
726     isom_remove_box_in_predefined_list( description );
727 }
728 
isom_remove_tx3g_description(isom_sample_entry_t * description)729 static void isom_remove_tx3g_description( isom_sample_entry_t *description )
730 {
731     isom_remove_box_in_predefined_list( description );
732 }
733 
isom_remove_qt_text_description(isom_sample_entry_t * description)734 static void isom_remove_qt_text_description( isom_sample_entry_t *description )
735 {
736     isom_qt_text_entry_t *text = (isom_qt_text_entry_t *)description;
737     lsmash_free( text->font_name );
738     isom_remove_box_in_predefined_list( text );
739 }
740 
isom_remove_mp4s_description(isom_sample_entry_t * description)741 static void isom_remove_mp4s_description( isom_sample_entry_t *description )
742 {
743     isom_remove_box_in_predefined_list( description );
744 }
745 
isom_remove_sample_description(isom_sample_entry_t * sample)746 void isom_remove_sample_description( isom_sample_entry_t *sample )
747 {
748     if( LSMASH_IS_NON_EXISTING_BOX( sample ) )
749         return;
750     lsmash_codec_type_t sample_type = sample->type;
751     if( lsmash_check_box_type_identical( sample_type, LSMASH_CODEC_TYPE_RAW ) )
752     {
753         if( sample->manager & LSMASH_VIDEO_DESCRIPTION )
754         {
755             isom_remove_visual_description( sample );
756             return;
757         }
758         else if( sample->manager & LSMASH_AUDIO_DESCRIPTION )
759         {
760             isom_remove_audio_description( sample );
761             return;
762         }
763     }
764     static struct description_remover_table_tag
765     {
766         lsmash_codec_type_t type;
767         void (*func)( isom_sample_entry_t * );
768     } description_remover_table[160] = { { LSMASH_CODEC_TYPE_INITIALIZER, NULL } };
769     if( !description_remover_table[0].func )
770     {
771         /* Initialize the table. */
772         int i = 0;
773 #define ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( type, func ) \
774     description_remover_table[i++] = (struct description_remover_table_tag){ type, func }
775         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVC1_VIDEO, isom_remove_visual_description );
776         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVC2_VIDEO, isom_remove_visual_description );
777         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVC3_VIDEO, isom_remove_visual_description );
778         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVC4_VIDEO, isom_remove_visual_description );
779         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVCP_VIDEO, isom_remove_visual_description );
780         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_HVC1_VIDEO, isom_remove_visual_description );
781         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_HEV1_VIDEO, isom_remove_visual_description );
782         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SVC1_VIDEO, isom_remove_visual_description );
783         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MVC1_VIDEO, isom_remove_visual_description );
784         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MVC2_VIDEO, isom_remove_visual_description );
785         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MP4V_VIDEO, isom_remove_visual_description );
786         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DRAC_VIDEO, isom_remove_visual_description );
787         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_ENCV_VIDEO, isom_remove_visual_description );
788         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MJP2_VIDEO, isom_remove_visual_description );
789         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_S263_VIDEO, isom_remove_visual_description );
790         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_VC_1_VIDEO, isom_remove_visual_description );
791         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_2VUY_VIDEO, isom_remove_visual_description );
792         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_CFHD_VIDEO, isom_remove_visual_description );
793         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DV10_VIDEO, isom_remove_visual_description );
794         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVOO_VIDEO, isom_remove_visual_description );
795         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVOR_VIDEO, isom_remove_visual_description );
796         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVTV_VIDEO, isom_remove_visual_description );
797         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVVT_VIDEO, isom_remove_visual_description );
798         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_HD10_VIDEO, isom_remove_visual_description );
799         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_M105_VIDEO, isom_remove_visual_description );
800         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_PNTG_VIDEO, isom_remove_visual_description );
801         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SVQ1_VIDEO, isom_remove_visual_description );
802         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SVQ3_VIDEO, isom_remove_visual_description );
803         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR0_VIDEO, isom_remove_visual_description );
804         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR1_VIDEO, isom_remove_visual_description );
805         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR2_VIDEO, isom_remove_visual_description );
806         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR3_VIDEO, isom_remove_visual_description );
807         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR4_VIDEO, isom_remove_visual_description );
808         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_WRLE_VIDEO, isom_remove_visual_description );
809         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_APCH_VIDEO, isom_remove_visual_description );
810         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_APCN_VIDEO, isom_remove_visual_description );
811         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_APCS_VIDEO, isom_remove_visual_description );
812         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_APCO_VIDEO, isom_remove_visual_description );
813         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_AP4H_VIDEO, isom_remove_visual_description );
814         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_AP4X_VIDEO, isom_remove_visual_description );
815         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_CIVD_VIDEO, isom_remove_visual_description );
816         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DRAC_VIDEO, isom_remove_visual_description );
817         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVC_VIDEO,  isom_remove_visual_description );
818         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVCP_VIDEO, isom_remove_visual_description );
819         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVPP_VIDEO, isom_remove_visual_description );
820         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DV5N_VIDEO, isom_remove_visual_description );
821         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DV5P_VIDEO, isom_remove_visual_description );
822         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVH2_VIDEO, isom_remove_visual_description );
823         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVH3_VIDEO, isom_remove_visual_description );
824         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVH5_VIDEO, isom_remove_visual_description );
825         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVH6_VIDEO, isom_remove_visual_description );
826         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVHP_VIDEO, isom_remove_visual_description );
827         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVHQ_VIDEO, isom_remove_visual_description );
828         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_FLIC_VIDEO, isom_remove_visual_description );
829         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_GIF_VIDEO,  isom_remove_visual_description );
830         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_H261_VIDEO, isom_remove_visual_description );
831         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_H263_VIDEO, isom_remove_visual_description );
832         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_JPEG_VIDEO, isom_remove_visual_description );
833         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_MJPA_VIDEO, isom_remove_visual_description );
834         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_MJPB_VIDEO, isom_remove_visual_description );
835         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_PNG_VIDEO,  isom_remove_visual_description );
836         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_RLE_VIDEO,  isom_remove_visual_description );
837         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_RPZA_VIDEO, isom_remove_visual_description );
838         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_TGA_VIDEO,  isom_remove_visual_description );
839         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_TIFF_VIDEO, isom_remove_visual_description );
840         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULRA_VIDEO, isom_remove_visual_description );
841         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULRG_VIDEO, isom_remove_visual_description );
842         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULY2_VIDEO, isom_remove_visual_description );
843         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULY0_VIDEO, isom_remove_visual_description );
844         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULH2_VIDEO, isom_remove_visual_description );
845         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULH0_VIDEO, isom_remove_visual_description );
846         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_UQY2_VIDEO, isom_remove_visual_description );
847         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V210_VIDEO, isom_remove_visual_description );
848         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V216_VIDEO, isom_remove_visual_description );
849         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V308_VIDEO, isom_remove_visual_description );
850         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V408_VIDEO, isom_remove_visual_description );
851         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V410_VIDEO, isom_remove_visual_description );
852         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_YUV2_VIDEO, isom_remove_visual_description );
853         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MP4A_AUDIO, isom_remove_audio_description );
854         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AC_3_AUDIO, isom_remove_audio_description );
855         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_ALAC_AUDIO, isom_remove_audio_description );
856         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSEL_AUDIO, isom_remove_audio_description );
857         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSDL_AUDIO, isom_remove_audio_description );
858         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSC_AUDIO, isom_remove_audio_description );
859         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSE_AUDIO, isom_remove_audio_description );
860         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSH_AUDIO, isom_remove_audio_description );
861         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSL_AUDIO, isom_remove_audio_description );
862         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSX_AUDIO, isom_remove_audio_description );
863         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_EC_3_AUDIO, isom_remove_audio_description );
864         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SAMR_AUDIO, isom_remove_audio_description );
865         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SAWB_AUDIO, isom_remove_audio_description );
866         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_MP4A_AUDIO, isom_remove_audio_description );
867         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_23NI_AUDIO, isom_remove_audio_description );
868         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_NONE_AUDIO, isom_remove_audio_description );
869         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_LPCM_AUDIO, isom_remove_audio_description );
870         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SOWT_AUDIO, isom_remove_audio_description );
871         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_TWOS_AUDIO, isom_remove_audio_description );
872         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_FL32_AUDIO, isom_remove_audio_description );
873         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_FL64_AUDIO, isom_remove_audio_description );
874         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_IN24_AUDIO, isom_remove_audio_description );
875         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_IN32_AUDIO, isom_remove_audio_description );
876         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_NOT_SPECIFIED, isom_remove_audio_description );
877         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DRA1_AUDIO, isom_remove_audio_description );
878         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_ENCA_AUDIO, isom_remove_audio_description );
879         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_G719_AUDIO, isom_remove_audio_description );
880         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_G726_AUDIO, isom_remove_audio_description );
881         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_M4AE_AUDIO, isom_remove_audio_description );
882         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MLPA_AUDIO, isom_remove_audio_description );
883         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SAWP_AUDIO, isom_remove_audio_description );
884         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SEVC_AUDIO, isom_remove_audio_description );
885         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SQCP_AUDIO, isom_remove_audio_description );
886         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SSMV_AUDIO, isom_remove_audio_description );
887         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_TWOS_AUDIO, isom_remove_audio_description );
888         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_FDP_HINT,  isom_remove_hint_description );
889         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_M2TS_HINT, isom_remove_hint_description );
890         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_PM2T_HINT, isom_remove_hint_description );
891         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_PRTP_HINT, isom_remove_hint_description );
892         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_RM2T_HINT, isom_remove_hint_description );
893         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_RRTP_HINT, isom_remove_hint_description );
894         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_RSRP_HINT, isom_remove_hint_description );
895         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_RTP_HINT , isom_remove_hint_description );
896         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SM2T_HINT, isom_remove_hint_description );
897         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SRTP_HINT, isom_remove_hint_description );
898         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_IXSE_META, isom_remove_metadata_description );
899         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_METT_META, isom_remove_metadata_description );
900         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_METX_META, isom_remove_metadata_description );
901         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MLIX_META, isom_remove_metadata_description );
902         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_OKSD_META, isom_remove_metadata_description );
903         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SVCM_META, isom_remove_metadata_description );
904         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_TEXT_META, isom_remove_metadata_description );
905         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_URIM_META, isom_remove_metadata_description );
906         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_XML_META,  isom_remove_metadata_description );
907         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_TX3G_TEXT, isom_remove_tx3g_description );
908         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_TEXT_TEXT, isom_remove_qt_text_description );
909         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MP4S_SYSTEM, isom_remove_mp4s_description );
910         ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( LSMASH_CODEC_TYPE_UNSPECIFIED, NULL );
911     }
912     for( int i = 0; description_remover_table[i].func; i++ )
913         if( lsmash_check_codec_type_identical( sample_type, description_remover_table[i].type ) )
914         {
915             description_remover_table[i].func( sample );
916             return;
917         }
918 }
919 
DEFINE_SIMPLE_LIST_BOX_REMOVER(isom_remove_stts,stts)920 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stts, stts )
921 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_ctts, ctts )
922 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_cslg, cslg )
923 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stsc, stsc )
924 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stsz, stsz )
925 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stz2, stz2 )
926 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stss, stss )
927 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stps, stps )
928 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_stco, stco )
929 
930 static void isom_remove_sdtp( isom_sdtp_t *sdtp )
931 {
932     if( LSMASH_IS_NON_EXISTING_BOX( sdtp ) )
933         return;
934     lsmash_list_destroy( sdtp->list );
935     REMOVE_BOX( sdtp );
936 }
937 
isom_remove_sgpd(isom_sgpd_t * sgpd)938 static void isom_remove_sgpd( isom_sgpd_t *sgpd )
939 {
940     if( LSMASH_IS_NON_EXISTING_BOX( sgpd ) )
941         return;
942     lsmash_list_destroy( sgpd->list );
943     REMOVE_BOX_IN_LIST( sgpd );
944 }
945 
isom_remove_sbgp(isom_sbgp_t * sbgp)946 static void isom_remove_sbgp( isom_sbgp_t *sbgp )
947 {
948     if( LSMASH_IS_NON_EXISTING_BOX( sbgp ) )
949         return;
950     lsmash_list_destroy( sbgp->list );
951     REMOVE_BOX_IN_LIST( sbgp );
952 }
953 
DEFINE_SIMPLE_BOX_REMOVER(isom_remove_stbl,stbl)954 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_stbl, stbl )
955 
956 static void isom_remove_dref_entry( isom_dref_entry_t *data_entry )
957 {
958     lsmash_free( data_entry->name );
959     lsmash_free( data_entry->location );
960     isom_remove_box_in_predefined_list( data_entry );
961 }
962 
DEFINE_SIMPLE_BOX_REMOVER(isom_remove_dref,dref)963 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_dref, dref )
964 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_dinf, dinf )
965 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_minf, minf )
966 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mdia, mdia )
967 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_chpl, chpl )
968 DEFINE_SIMPLE_LIST_BOX_REMOVER( isom_remove_keys, keys )
969 
970 static void isom_remove_mean( isom_mean_t *mean )
971 {
972     lsmash_free( mean->meaning_string );
973     REMOVE_BOX( mean );
974 }
975 
isom_remove_name(isom_name_t * name)976 static void isom_remove_name( isom_name_t *name )
977 {
978     lsmash_free( name->name );
979     REMOVE_BOX( name );
980 }
981 
isom_remove_data(isom_data_t * data)982 static void isom_remove_data( isom_data_t *data )
983 {
984     lsmash_free( data->value );
985     REMOVE_BOX( data );
986 }
987 
DEFINE_SIMPLE_BOX_IN_LIST_REMOVER(isom_remove_metaitem,metaitem)988 DEFINE_SIMPLE_BOX_IN_LIST_REMOVER( isom_remove_metaitem, metaitem )
989 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_ilst, ilst )
990 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_meta, meta )
991 
992 static void isom_remove_cprt( isom_cprt_t *cprt )
993 {
994     lsmash_free( cprt->notice );
995     REMOVE_BOX_IN_LIST( cprt );
996 }
997 
DEFINE_SIMPLE_BOX_REMOVER(isom_remove_udta,udta)998 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_udta, udta )
999 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_WLOC, WLOC )
1000 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_LOOP, LOOP )
1001 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_SelO, SelO )
1002 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_AllF, AllF )
1003 
1004 static void isom_remove_ctab( isom_ctab_t *ctab )
1005 {
1006     lsmash_free( ctab->color_table.array );
1007     REMOVE_BOX( ctab );
1008 }
1009 
DEFINE_SIMPLE_BOX_REMOVER(isom_remove_mvex,mvex)1010 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mvex, mvex )
1011 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mvhd, mvhd )
1012 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mehd, mehd )
1013 DEFINE_SIMPLE_BOX_IN_LIST_REMOVER( isom_remove_trex, trex )
1014 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_moov, moov )
1015 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mdat, mdat )
1016 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mfhd, mfhd )
1017 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_tfhd, tfhd )
1018 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_tfdt, tfdt )
1019 
1020 static void isom_remove_trun( isom_trun_t *trun )
1021 {
1022     lsmash_list_destroy( trun->optional );
1023     REMOVE_BOX_IN_LIST( trun );
1024 }
1025 
DEFINE_SIMPLE_BOX_IN_LIST_REMOVER(isom_remove_traf,traf)1026 DEFINE_SIMPLE_BOX_IN_LIST_REMOVER( isom_remove_traf, traf )
1027 DEFINE_SIMPLE_BOX_IN_LIST_REMOVER( isom_remove_moof, moof )
1028 
1029 static void isom_remove_free( isom_free_t *skip )
1030 {
1031     lsmash_free( skip->data );
1032 }
1033 #define isom_remove_skip isom_remove_free
1034 
DEFINE_SIMPLE_BOX_REMOVER(isom_remove_mfra,mfra)1035 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mfra, mfra )
1036 DEFINE_SIMPLE_BOX_REMOVER( isom_remove_mfro, mfro )
1037 DEFINE_SIMPLE_LIST_BOX_IN_LIST_REMOVER( isom_remove_tfra, tfra )
1038 DEFINE_SIMPLE_LIST_BOX_IN_LIST_REMOVER( isom_remove_sidx, sidx )
1039 
1040 static void isom_remove_styp( isom_styp_t *styp )
1041 {
1042     lsmash_free( styp->compatible_brands );
1043     REMOVE_BOX_IN_LIST( styp );
1044 }
1045 
1046 #define isom_remove_elst_entry lsmash_free
1047 #define isom_remove_stts_entry lsmash_free
1048 #define isom_remove_ctts_entry lsmash_free
1049 #define isom_remove_stsz_entry lsmash_free
1050 #define isom_remove_stz2_entry lsmash_free
1051 #define isom_remove_stss_entry lsmash_free
1052 #define isom_remove_stps_entry lsmash_free
1053 #define isom_remove_sdtp_entry lsmash_free
1054 #define isom_remove_stsc_entry lsmash_free
1055 #define isom_remove_stco_entry lsmash_free
1056 #define isom_remove_co64_entry lsmash_free
1057 #define isom_remove_sgpd_entry lsmash_free
1058 #define isom_remove_sbgp_entry lsmash_free
1059 #define isom_remove_trun_entry lsmash_free
1060 #define isom_remove_tfra_entry lsmash_free
1061 #define isom_remove_sidx_entry lsmash_free
1062 
isom_remove_ftab_entry(isom_font_record_t * font_record)1063 static void isom_remove_ftab_entry( isom_font_record_t *font_record )
1064 {
1065     if( !font_record )
1066         return;
1067     lsmash_free( font_record->font_name );
1068     lsmash_free( font_record );
1069 }
1070 
isom_remove_chpl_entry(isom_chpl_entry_t * data)1071 static void isom_remove_chpl_entry( isom_chpl_entry_t *data )
1072 {
1073     if( !data )
1074         return;
1075     lsmash_free( data->chapter_name );
1076     lsmash_free( data );
1077 }
1078 
isom_remove_keys_entry(isom_keys_entry_t * data)1079 static void isom_remove_keys_entry( isom_keys_entry_t *data )
1080 {
1081     if( !data )
1082         return;
1083     lsmash_free( data->key_value );
1084     lsmash_free( data );
1085 }
1086 
1087 /* box size updater */
isom_update_box_size(void * opaque_box)1088 uint64_t isom_update_box_size( void *opaque_box )
1089 {
1090     isom_box_t *box = (isom_box_t *)opaque_box;
1091     assert( LSMASH_IS_EXISTING_BOX( box ) );
1092     if( box->manager & LSMASH_WRITTEN_BOX )
1093         /* No need to calculate the size of this box since the size is already decided and fixed. */
1094         return box->size;
1095     uint64_t size = 0;
1096     if( box->write )
1097     {
1098         /* Calculate the size of this box excluding its children with a fake bytestream writer. */
1099         {
1100             lsmash_bs_t fake_bs = { NULL };
1101             if( box->write( &fake_bs, box ) == 0 )
1102                 size = lsmash_bs_get_valid_data_size( &fake_bs );
1103         }
1104         /* Calculate the size of the children if no error. */
1105         if( size >= ISOM_BASEBOX_COMMON_SIZE )
1106         {
1107             for( lsmash_entry_t *entry = box->extensions.head; entry; entry = entry->next )
1108                 if( entry->data )
1109                     size += isom_update_box_size( entry->data );
1110             /* Check large size. */
1111             if( size > UINT32_MAX )
1112                 size += 8;
1113         }
1114         else
1115             /* TODO: add error handling. */
1116             size = 0;
1117     }
1118     box->size = size;
1119     return size;
1120 }
1121 
1122 /* box adding functions */
1123 #define ATTACH_EXACTLY_ONE_BOX_TO_PARENT( box_name, parent_type )     \
1124     do                                                                \
1125     {                                                                 \
1126         size_t offset_in_parent = offsetof( parent_type, box_name );  \
1127         isom_box_t **p = (isom_box_t **)(((int8_t *)box_name->parent) \
1128                        + offset_in_parent);                           \
1129         assert( *p );                                                 \
1130         if( LSMASH_IS_NON_EXISTING_BOX( *p ) )                        \
1131         {                                                             \
1132             *p = (isom_box_t *)box_name;                              \
1133             (*p)->offset_in_parent = offset_in_parent;                \
1134         }                                                             \
1135     } while( 0 )
1136 
1137 #define ADD_BOX_TO_PREDEFINED_LIST( box_name, parent_name )                    \
1138     if( lsmash_list_add_entry( &parent_name->box_name##_list, box_name ) < 0 ) \
1139     {                                                                          \
1140         lsmash_list_remove_entry_tail( &parent_name->extensions );             \
1141         return isom_non_existing_##box_name();                                 \
1142     }                                                                          \
1143     box_name->offset_in_parent = offsetof( isom_##parent_name##_t, box_name##_list )
1144 
1145 #define INIT_BOX_COMMON0( box_name, parent_name, box_type, precedence )  \
1146         const isom_extension_destructor_t isom_remove_##box_name = NULL; \
1147         isom_init_box_common( box_name, parent_name, box_type, precedence, isom_remove_##box_name )
1148 #define INIT_BOX_COMMON1( box_name, parent_name, box_type, precedence ) \
1149         isom_init_box_common( box_name, parent_name, box_type, precedence, isom_remove_##box_name )
1150 
1151 #define CREATE_BOX( box_name, parent_name, box_type, precedence, has_destructor )      \
1152     if( LSMASH_IS_NON_EXISTING_BOX( (isom_box_t *)parent_name ) )                      \
1153         return isom_non_existing_##box_name();                                         \
1154     isom_##box_name##_t *box_name = ALLOCATE_BOX( box_name );                          \
1155     if( LSMASH_IS_NON_EXISTING_BOX( box_name ) )                                       \
1156         return box_name;                                                               \
1157     INIT_BOX_COMMON ## has_destructor( box_name, parent_name, box_type, precedence );  \
1158     if( isom_add_box_to_extension_list( parent_name, box_name ) < 0 )                  \
1159     {                                                                                  \
1160         lsmash_free( box_name );                                                       \
1161         return isom_non_existing_##box_name();                                         \
1162     }
1163 #define CREATE_LIST_BOX( box_name, parent_name, box_type, precedence, has_destructor )  \
1164     CREATE_BOX( box_name, parent_name, box_type, precedence, has_destructor );          \
1165     box_name->list = lsmash_list_create( isom_remove_##box_name##_entry );              \
1166     if( !box_name->list )                                                               \
1167     {                                                                                   \
1168         lsmash_list_remove_entry_tail( &parent_name->extensions );                      \
1169         return isom_non_existing_##box_name();                                          \
1170     }
1171 
1172 #define ADD_BOX_TEMPLATE( box_name, parent_name, box_type, precedence, BOX_CREATOR ) \
1173     BOX_CREATOR( box_name, parent_name, box_type, precedence, 1 );                   \
1174     if( LSMASH_IS_NON_EXISTING_BOX( parent_name->box_name ) )                        \
1175     {                                                                                \
1176         parent_name->box_name = box_name;                                            \
1177         box_name->offset_in_parent = offsetof( isom_##parent_name##_t, box_name );   \
1178     } do {} while( 0 )
1179 #define ADD_BOX_IN_LIST_TEMPLATE( box_name, parent_name, box_type, precedence, BOX_CREATOR ) \
1180     BOX_CREATOR( box_name, parent_name, box_type, precedence, 1 );                           \
1181     ADD_BOX_TO_PREDEFINED_LIST( box_name, parent_name )
1182 
1183 #define ADD_BOX( box_name, parent_name, box_type, precedence ) \
1184         ADD_BOX_TEMPLATE( box_name, parent_name, box_type, precedence, CREATE_BOX )
1185 #define ADD_BOX_IN_LIST( box_name, parent_name, box_type, precedence ) \
1186         ADD_BOX_IN_LIST_TEMPLATE( box_name, parent_name, box_type, precedence, CREATE_BOX )
1187 #define ADD_LIST_BOX( box_name, parent_name, box_type, precedence ) \
1188         ADD_BOX_TEMPLATE( box_name, parent_name, box_type, precedence, CREATE_LIST_BOX )
1189 #define ADD_LIST_BOX_IN_LIST( box_name, parent_name, box_type, precedence ) \
1190         ADD_BOX_IN_LIST_TEMPLATE( box_name, parent_name, box_type, precedence, CREATE_LIST_BOX )
1191 
1192 #define DEFINE_SIMPLE_BOX_ADDER_TEMPLATE( ... ) CALL_FUNC_DEFAULT_ARGS( DEFINE_SIMPLE_BOX_ADDER_TEMPLATE, __VA_ARGS__ )
1193 #define DEFINE_SIMPLE_BOX_ADDER_TEMPLATE_6( ADDER, box_name, parent_name, box_type, precedence, postprocess ) \
1194     isom_##box_name##_t *isom_add_##box_name( isom_##parent_name##_t *parent_name )                           \
1195     {                                                                                                         \
1196         ADDER( box_name, parent_name, box_type, precedence );                                                 \
1197         do { postprocess } while( 0 );                                                                        \
1198         return box_name;                                                                                      \
1199     }
1200 #define DEFINE_SIMPLE_BOX_ADDER_TEMPLATE_5( ADDER, box_name, parent_name, box_type, precedence ) \
1201     DEFINE_SIMPLE_BOX_ADDER_TEMPLATE_6( ADDER, box_name, parent_name, box_type, precedence, )
1202 
1203 #define DEFINE_SIMPLE_BOX_ADDER( func_name, ... ) \
1204         DEFINE_SIMPLE_BOX_ADDER_TEMPLATE( ADD_BOX, __VA_ARGS__ )
1205 #define DEFINE_SIMPLE_BOX_IN_LIST_ADDER( func_name, ... ) \
1206         DEFINE_SIMPLE_BOX_ADDER_TEMPLATE( ADD_BOX_IN_LIST, __VA_ARGS__ )
1207 #define DEFINE_SIMPLE_LIST_BOX_ADDER( func_name, ... ) \
1208         DEFINE_SIMPLE_BOX_ADDER_TEMPLATE( ADD_LIST_BOX, __VA_ARGS__ )
1209 
1210 #define DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( func_name, box_name, parent_name, box_type, precedence, has_destructor, parent_type ) \
1211     isom_##box_name##_t *isom_add_##box_name( parent_type *parent_name )                                                            \
1212     {                                                                                                                               \
1213         CREATE_BOX( box_name, parent_name, box_type, precedence, has_destructor );                                                  \
1214         return box_name;                                                                                                            \
1215     }
1216 
1217 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_file_abstract, file_abstract, root_abstract, LSMASH_BOX_TYPE_UNSPECIFIED, 0,
1218                                  file_abstract->file = file_abstract; )
1219 
isom_add_track_reference_type(isom_tref_t * tref,isom_track_reference_type type)1220 isom_tref_type_t *isom_add_track_reference_type( isom_tref_t *tref, isom_track_reference_type type )
1221 {
1222     if( LSMASH_IS_NON_EXISTING_BOX( tref ) )
1223         return isom_non_existing_tref_type();
1224     isom_tref_type_t *tref_type = ALLOCATE_BOX( tref_type );
1225     if( LSMASH_IS_NON_EXISTING_BOX( tref_type ) )
1226         return tref_type;
1227     /* Initialize common fields. */
1228     tref_type->class      = &lsmash_box_class;
1229     tref_type->root       = tref->root;
1230     tref_type->file       = tref->file;
1231     tref_type->parent     = (isom_box_t *)tref;
1232     tref_type->precedence = LSMASH_BOX_PRECEDENCE_ISOM_TREF_TYPE;
1233     tref_type->destruct   = (isom_extension_destructor_t)isom_remove_track_reference_type;
1234     tref_type->size       = 0;
1235     tref_type->type       = lsmash_form_iso_box_type( type );
1236     isom_set_box_writer( (isom_box_t *)tref_type );
1237     if( isom_add_box_to_extension_list( tref, tref_type ) < 0 )
1238     {
1239         lsmash_free( tref_type );
1240         return isom_non_existing_tref_type();
1241     }
1242     if( lsmash_list_add_entry( &tref->ref_list, tref_type ) < 0 )
1243     {
1244         lsmash_list_remove_entry_tail( &tref->extensions );
1245         return isom_non_existing_tref_type();
1246     }
1247     tref_type->offset_in_parent = offsetof( isom_tref_t, ref_list );
1248     return tref_type;
1249 }
1250 
DEFINE_SIMPLE_BOX_ADDER(isom_add_terminator,terminator,wave,QT_BOX_TYPE_TERMINATOR,LSMASH_BOX_PRECEDENCE_QTFF_TERMINATOR)1251 DEFINE_SIMPLE_BOX_ADDER( isom_add_terminator, terminator, wave, QT_BOX_TYPE_TERMINATOR, LSMASH_BOX_PRECEDENCE_QTFF_TERMINATOR )
1252 DEFINE_SIMPLE_BOX_ADDER( isom_add_frma, frma, wave,   QT_BOX_TYPE_FRMA, LSMASH_BOX_PRECEDENCE_QTFF_FRMA )
1253 DEFINE_SIMPLE_BOX_ADDER( isom_add_enda, enda, wave,   QT_BOX_TYPE_ENDA, LSMASH_BOX_PRECEDENCE_QTFF_ENDA )
1254 DEFINE_SIMPLE_BOX_ADDER( isom_add_mp4a, mp4a, wave,   QT_BOX_TYPE_MP4A, LSMASH_BOX_PRECEDENCE_QTFF_MP4A )
1255 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_ftab, ftab, tx3g_entry, ISOM_BOX_TYPE_FTAB, LSMASH_BOX_PRECEDENCE_ISOM_FTAB )
1256 DEFINE_SIMPLE_BOX_ADDER( isom_add_ftyp, ftyp, file_abstract, ISOM_BOX_TYPE_FTYP, LSMASH_BOX_PRECEDENCE_ISOM_FTYP )
1257 DEFINE_SIMPLE_BOX_ADDER( isom_add_moov, moov, file_abstract, ISOM_BOX_TYPE_MOOV, LSMASH_BOX_PRECEDENCE_ISOM_MOOV )
1258 DEFINE_SIMPLE_BOX_ADDER( isom_add_mvhd, mvhd, moov,          ISOM_BOX_TYPE_MVHD, LSMASH_BOX_PRECEDENCE_ISOM_MVHD )
1259 DEFINE_SIMPLE_BOX_ADDER( isom_add_iods, iods, moov,          ISOM_BOX_TYPE_IODS, LSMASH_BOX_PRECEDENCE_ISOM_IODS )
1260 
1261 isom_ctab_t *isom_add_ctab( void *parent_box )
1262 {
1263     /* According to QuickTime File Format Specification, this box is placed inside Movie Box if present.
1264      * However, sometimes this box occurs inside an image description entry or the end of Sample Description Box. */
1265     isom_box_t *parent = (isom_box_t *)parent_box;
1266     if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
1267         return isom_non_existing_ctab();
1268     CREATE_BOX( ctab, parent, QT_BOX_TYPE_CTAB, LSMASH_BOX_PRECEDENCE_QTFF_CTAB, 1 );
1269     if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_MOOV ) )
1270         ATTACH_EXACTLY_ONE_BOX_TO_PARENT( ctab, isom_moov_t );
1271     return ctab;
1272 }
1273 
isom_add_trak(isom_moov_t * moov)1274 isom_trak_t *isom_add_trak( isom_moov_t *moov )
1275 {
1276     if( LSMASH_IS_NON_EXISTING_BOX( moov )
1277      || LSMASH_IS_NON_EXISTING_BOX( moov->file ) )
1278         return isom_non_existing_trak();
1279     CREATE_BOX( trak, moov, ISOM_BOX_TYPE_TRAK, LSMASH_BOX_PRECEDENCE_ISOM_TRAK, 1 );
1280     isom_fragment_t *fragment = NULL;
1281     isom_cache_t    *cache    = lsmash_malloc_zero( sizeof(isom_cache_t) );
1282     if( !cache )
1283         goto fail;
1284     if( moov->file->fragment )
1285     {
1286         fragment = lsmash_malloc_zero( sizeof(isom_fragment_t) );
1287         if( !fragment )
1288             goto fail;
1289         cache->fragment = fragment;
1290         fragment->largest_cts                 = LSMASH_TIMESTAMP_UNDEFINED;
1291         fragment->subsegment.largest_cts      = LSMASH_TIMESTAMP_UNDEFINED;
1292         fragment->subsegment.smallest_cts     = LSMASH_TIMESTAMP_UNDEFINED;
1293         fragment->subsegment.first_sample_cts = LSMASH_TIMESTAMP_UNDEFINED;
1294         fragment->subsegment.first_ed_cts     = LSMASH_TIMESTAMP_UNDEFINED;
1295         fragment->subsegment.first_rp_cts     = LSMASH_TIMESTAMP_UNDEFINED;
1296     }
1297     if( lsmash_list_add_entry( &moov->trak_list, trak ) < 0 )
1298         goto fail;
1299     trak->offset_in_parent = offsetof( isom_moov_t, trak_list );
1300     trak->cache            = cache;
1301     return trak;
1302 fail:
1303     lsmash_free( fragment );
1304     lsmash_free( cache );
1305     lsmash_list_remove_entry_tail( &moov->extensions );
1306     return isom_non_existing_trak();
1307 }
1308 
DEFINE_SIMPLE_BOX_ADDER(isom_add_tkhd,tkhd,trak,ISOM_BOX_TYPE_TKHD,LSMASH_BOX_PRECEDENCE_ISOM_TKHD)1309 DEFINE_SIMPLE_BOX_ADDER     ( isom_add_tkhd, tkhd, trak, ISOM_BOX_TYPE_TKHD, LSMASH_BOX_PRECEDENCE_ISOM_TKHD )
1310 DEFINE_SIMPLE_BOX_ADDER     ( isom_add_tapt, tapt, trak,   QT_BOX_TYPE_TAPT, LSMASH_BOX_PRECEDENCE_QTFF_TAPT )
1311 DEFINE_SIMPLE_BOX_ADDER     ( isom_add_clef, clef, tapt,   QT_BOX_TYPE_CLEF, LSMASH_BOX_PRECEDENCE_QTFF_CLEF )
1312 DEFINE_SIMPLE_BOX_ADDER     ( isom_add_prof, prof, tapt,   QT_BOX_TYPE_PROF, LSMASH_BOX_PRECEDENCE_QTFF_PROF )
1313 DEFINE_SIMPLE_BOX_ADDER     ( isom_add_enof, enof, tapt,   QT_BOX_TYPE_ENOF, LSMASH_BOX_PRECEDENCE_QTFF_ENOF )
1314 DEFINE_SIMPLE_BOX_ADDER     ( isom_add_edts, edts, trak, ISOM_BOX_TYPE_EDTS, LSMASH_BOX_PRECEDENCE_ISOM_EDTS )
1315 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_elst, elst, edts, ISOM_BOX_TYPE_ELST, LSMASH_BOX_PRECEDENCE_ISOM_ELST )
1316 DEFINE_SIMPLE_BOX_ADDER     ( isom_add_tref, tref, trak, ISOM_BOX_TYPE_TREF, LSMASH_BOX_PRECEDENCE_ISOM_TREF )
1317 DEFINE_SIMPLE_BOX_ADDER     ( isom_add_mdia, mdia, trak, ISOM_BOX_TYPE_MDIA, LSMASH_BOX_PRECEDENCE_ISOM_MDIA )
1318 DEFINE_SIMPLE_BOX_ADDER     ( isom_add_mdhd, mdhd, mdia, ISOM_BOX_TYPE_MDHD, LSMASH_BOX_PRECEDENCE_ISOM_MDHD )
1319 
1320 isom_hdlr_t *isom_add_hdlr( void *parent_box )
1321 {
1322     isom_box_t *parent = (isom_box_t *)parent_box;
1323     if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
1324         return isom_non_existing_hdlr();
1325     CREATE_BOX( hdlr, parent, ISOM_BOX_TYPE_HDLR, LSMASH_BOX_PRECEDENCE_ISOM_HDLR, 1 );
1326     if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_MDIA ) )
1327         ATTACH_EXACTLY_ONE_BOX_TO_PARENT( hdlr, isom_mdia_t );
1328     else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_META )
1329           || lsmash_check_box_type_identical( parent->type,   QT_BOX_TYPE_META ) )
1330         ATTACH_EXACTLY_ONE_BOX_TO_PARENT( hdlr, isom_meta_t );
1331     else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_MINF ) )
1332         ATTACH_EXACTLY_ONE_BOX_TO_PARENT( hdlr, isom_minf_t );
1333     else
1334         assert( 0 );
1335     return hdlr;
1336 }
1337 
DEFINE_SIMPLE_BOX_ADDER(isom_add_minf,minf,mdia,ISOM_BOX_TYPE_MINF,LSMASH_BOX_PRECEDENCE_ISOM_MINF)1338 DEFINE_SIMPLE_BOX_ADDER( isom_add_minf, minf, mdia, ISOM_BOX_TYPE_MINF, LSMASH_BOX_PRECEDENCE_ISOM_MINF )
1339 DEFINE_SIMPLE_BOX_ADDER( isom_add_vmhd, vmhd, minf, ISOM_BOX_TYPE_VMHD, LSMASH_BOX_PRECEDENCE_ISOM_VMHD )
1340 DEFINE_SIMPLE_BOX_ADDER( isom_add_smhd, smhd, minf, ISOM_BOX_TYPE_SMHD, LSMASH_BOX_PRECEDENCE_ISOM_SMHD )
1341 DEFINE_SIMPLE_BOX_ADDER( isom_add_hmhd, hmhd, minf, ISOM_BOX_TYPE_HMHD, LSMASH_BOX_PRECEDENCE_ISOM_HMHD )
1342 DEFINE_SIMPLE_BOX_ADDER( isom_add_nmhd, nmhd, minf, ISOM_BOX_TYPE_NMHD, LSMASH_BOX_PRECEDENCE_ISOM_NMHD )
1343 DEFINE_SIMPLE_BOX_ADDER( isom_add_gmhd, gmhd, minf,   QT_BOX_TYPE_GMHD, LSMASH_BOX_PRECEDENCE_QTFF_GMHD )
1344 DEFINE_SIMPLE_BOX_ADDER( isom_add_gmin, gmin, gmhd,   QT_BOX_TYPE_GMIN, LSMASH_BOX_PRECEDENCE_QTFF_GMIN )
1345 DEFINE_SIMPLE_BOX_ADDER( isom_add_text, text, gmhd,   QT_BOX_TYPE_TEXT, LSMASH_BOX_PRECEDENCE_QTFF_TEXT )
1346 
1347 isom_dinf_t *isom_add_dinf( void *parent_box )
1348 {
1349     isom_box_t *parent = (isom_box_t *)parent_box;
1350     if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
1351         return isom_non_existing_dinf();
1352     CREATE_BOX( dinf, parent, ISOM_BOX_TYPE_DINF, LSMASH_BOX_PRECEDENCE_ISOM_DINF, 1 );
1353     if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_MINF ) )
1354         ATTACH_EXACTLY_ONE_BOX_TO_PARENT( dinf, isom_minf_t );
1355     else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_META )
1356           || lsmash_check_box_type_identical( parent->type,   QT_BOX_TYPE_META ) )
1357         ATTACH_EXACTLY_ONE_BOX_TO_PARENT( dinf, isom_meta_t );
1358     else
1359         assert( 0 );
1360     return dinf;
1361 }
1362 
isom_add_dref_entry(isom_dref_t * dref,lsmash_box_type_t type)1363 isom_dref_entry_t *isom_add_dref_entry( isom_dref_t *dref, lsmash_box_type_t type )
1364 {
1365     if( LSMASH_IS_NON_EXISTING_BOX( dref ) )
1366         return isom_non_existing_dref_entry();
1367     isom_dref_entry_t *dref_entry = ALLOCATE_BOX( dref_entry );
1368     if( LSMASH_IS_NON_EXISTING_BOX( dref_entry ) )
1369         return dref_entry;
1370     isom_init_box_common( dref_entry, dref, type, LSMASH_BOX_PRECEDENCE_ISOM_DREF_ENTRY, isom_remove_dref_entry );
1371     if( isom_add_box_to_extension_list( dref, dref_entry ) < 0 )
1372     {
1373         lsmash_free( dref_entry );
1374         return isom_non_existing_dref_entry();
1375     }
1376     if( lsmash_list_add_entry( &dref->list, dref_entry ) < 0 )
1377     {
1378         lsmash_list_remove_entry_tail( &dref->extensions );
1379         return isom_non_existing_dref_entry();
1380     }
1381     dref_entry->offset_in_parent = offsetof( isom_dref_t, list );
1382     return dref_entry;
1383 }
1384 
DEFINE_SIMPLE_BOX_ADDER(isom_add_dref,dref,dinf,ISOM_BOX_TYPE_DREF,LSMASH_BOX_PRECEDENCE_ISOM_DREF)1385 DEFINE_SIMPLE_BOX_ADDER( isom_add_dref, dref, dinf, ISOM_BOX_TYPE_DREF, LSMASH_BOX_PRECEDENCE_ISOM_DREF )
1386 DEFINE_SIMPLE_BOX_ADDER( isom_add_stbl, stbl, minf, ISOM_BOX_TYPE_STBL, LSMASH_BOX_PRECEDENCE_ISOM_STBL )
1387 DEFINE_SIMPLE_BOX_ADDER( isom_add_stsd, stsd, stbl, ISOM_BOX_TYPE_STSD, LSMASH_BOX_PRECEDENCE_ISOM_STSD )
1388 
1389 static void *isom_add_sample_description_entry
1390 (
1391     isom_stsd_t *stsd,
1392     void        *description
1393 )
1394 {
1395     assert( description );
1396     if( isom_add_box_to_extension_list( stsd, description ) < 0 )
1397     {
1398         isom_remove_box_by_itself( description );
1399         return description;
1400     }
1401     if( lsmash_list_add_entry( &stsd->list, description ) < 0 )
1402     {
1403         lsmash_list_remove_entry_tail( &stsd->extensions );
1404         return description;
1405     }
1406     ((isom_box_t *)description)->offset_in_parent = offsetof( isom_stsd_t, list );
1407     return description;
1408 }
1409 
isom_add_visual_description(isom_stsd_t * stsd,lsmash_codec_type_t sample_type)1410 isom_visual_entry_t *isom_add_visual_description( isom_stsd_t *stsd, lsmash_codec_type_t sample_type )
1411 {
1412     assert( LSMASH_IS_EXISTING_BOX( stsd ) );
1413     isom_visual_entry_t *visual = ALLOCATE_BOX( visual_entry );
1414     if( LSMASH_IS_NON_EXISTING_BOX( visual ) )
1415         return visual;
1416     isom_init_box_common( visual, stsd, sample_type, LSMASH_BOX_PRECEDENCE_HM, isom_remove_visual_description );
1417     visual->manager |= LSMASH_VIDEO_DESCRIPTION;
1418     return isom_add_sample_description_entry( stsd, visual );
1419 }
1420 
isom_add_audio_description(isom_stsd_t * stsd,lsmash_codec_type_t sample_type)1421 isom_audio_entry_t *isom_add_audio_description( isom_stsd_t *stsd, lsmash_codec_type_t sample_type )
1422 {
1423     assert( LSMASH_IS_EXISTING_BOX( stsd ) );
1424     isom_audio_entry_t *audio = ALLOCATE_BOX( audio_entry );
1425     if( LSMASH_IS_NON_EXISTING_BOX( audio ) )
1426         return audio;
1427     isom_init_box_common( audio, stsd, sample_type, LSMASH_BOX_PRECEDENCE_HM, isom_remove_audio_description );
1428     audio->manager |= LSMASH_AUDIO_DESCRIPTION;
1429     return isom_add_sample_description_entry( stsd, audio );
1430 }
1431 
isom_add_qt_text_description(isom_stsd_t * stsd)1432 isom_qt_text_entry_t *isom_add_qt_text_description( isom_stsd_t *stsd )
1433 {
1434     assert( LSMASH_IS_EXISTING_BOX( stsd ) );
1435     isom_qt_text_entry_t *text = ALLOCATE_BOX( qt_text_entry );
1436     if( LSMASH_IS_NON_EXISTING_BOX( text ) )
1437         return text;
1438     isom_init_box_common( text, stsd, QT_CODEC_TYPE_TEXT_TEXT, LSMASH_BOX_PRECEDENCE_HM, isom_remove_qt_text_description );
1439     return isom_add_sample_description_entry( stsd, text );
1440 }
1441 
isom_add_tx3g_description(isom_stsd_t * stsd)1442 isom_tx3g_entry_t *isom_add_tx3g_description( isom_stsd_t *stsd )
1443 {
1444     assert( LSMASH_IS_EXISTING_BOX( stsd ) );
1445     isom_tx3g_entry_t *tx3g = ALLOCATE_BOX( tx3g_entry );
1446     if( LSMASH_IS_NON_EXISTING_BOX( tx3g ) )
1447         return tx3g;
1448     isom_init_box_common( tx3g, stsd, ISOM_CODEC_TYPE_TX3G_TEXT, LSMASH_BOX_PRECEDENCE_HM, isom_remove_tx3g_description );
1449     return isom_add_sample_description_entry( stsd, tx3g );
1450 }
1451 
isom_add_esds(void * parent_box)1452 isom_esds_t *isom_add_esds( void *parent_box )
1453 {
1454     isom_box_t *parent = (isom_box_t *)parent_box;
1455     int is_qt = lsmash_check_box_type_identical( parent->type, QT_BOX_TYPE_WAVE );
1456     lsmash_box_type_t box_type   = is_qt ? QT_BOX_TYPE_ESDS : ISOM_BOX_TYPE_ESDS;
1457     uint64_t          precedence = is_qt ? LSMASH_BOX_PRECEDENCE_QTFF_ESDS : LSMASH_BOX_PRECEDENCE_ISOM_ESDS;
1458     CREATE_BOX( esds, parent, box_type, precedence, 1 );
1459     return esds;
1460 }
1461 
1462 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_glbl, glbl, parent_box, QT_BOX_TYPE_GLBL, LSMASH_BOX_PRECEDENCE_QTFF_GLBL, 1, void )
1463 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_clap, clap, visual, ISOM_BOX_TYPE_CLAP, LSMASH_BOX_PRECEDENCE_ISOM_CLAP, 0, isom_visual_entry_t )
1464 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_pasp, pasp, visual, ISOM_BOX_TYPE_PASP, LSMASH_BOX_PRECEDENCE_ISOM_PASP, 0, isom_visual_entry_t )
1465 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_colr, colr, visual, ISOM_BOX_TYPE_COLR, LSMASH_BOX_PRECEDENCE_ISOM_COLR, 0, isom_visual_entry_t )
1466 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_gama, gama, visual,   QT_BOX_TYPE_GAMA, LSMASH_BOX_PRECEDENCE_QTFF_GAMA, 0, isom_visual_entry_t )
1467 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_fiel, fiel, visual,   QT_BOX_TYPE_FIEL, LSMASH_BOX_PRECEDENCE_QTFF_FIEL, 0, isom_visual_entry_t )
1468 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_cspc, cspc, visual,   QT_BOX_TYPE_CSPC, LSMASH_BOX_PRECEDENCE_QTFF_CSPC, 0, isom_visual_entry_t )
1469 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_sgbt, sgbt, visual,   QT_BOX_TYPE_SGBT, LSMASH_BOX_PRECEDENCE_QTFF_SGBT, 0, isom_visual_entry_t )
1470 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_stsl, stsl, visual, ISOM_BOX_TYPE_STSL, LSMASH_BOX_PRECEDENCE_ISOM_STSL, 0, isom_visual_entry_t )
1471 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_btrt, btrt, visual, ISOM_BOX_TYPE_BTRT, LSMASH_BOX_PRECEDENCE_ISOM_BTRT, 0, isom_visual_entry_t )
1472 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_wave, wave, audio,    QT_BOX_TYPE_WAVE, LSMASH_BOX_PRECEDENCE_QTFF_WAVE, 0, isom_audio_entry_t )
1473 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_chan, chan, audio,    QT_BOX_TYPE_CHAN, LSMASH_BOX_PRECEDENCE_QTFF_CHAN, 1, isom_audio_entry_t )
1474 DEFINE_SIMPLE_SAMPLE_EXTENSION_ADDER( isom_add_srat, srat, audio,  ISOM_BOX_TYPE_SRAT, LSMASH_BOX_PRECEDENCE_ISOM_SRAT, 0, isom_audio_entry_t )
1475 
DEFINE_SIMPLE_LIST_BOX_ADDER(isom_add_stts,stts,stbl,ISOM_BOX_TYPE_STTS,LSMASH_BOX_PRECEDENCE_ISOM_STTS)1476 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_stts, stts, stbl, ISOM_BOX_TYPE_STTS, LSMASH_BOX_PRECEDENCE_ISOM_STTS )
1477 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_ctts, ctts, stbl, ISOM_BOX_TYPE_CTTS, LSMASH_BOX_PRECEDENCE_ISOM_CTTS )
1478 DEFINE_SIMPLE_BOX_ADDER     ( isom_add_cslg, cslg, stbl, ISOM_BOX_TYPE_CSLG, LSMASH_BOX_PRECEDENCE_ISOM_CSLG )
1479 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_stsc, stsc, stbl, ISOM_BOX_TYPE_STSC, LSMASH_BOX_PRECEDENCE_ISOM_STSC )
1480 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. */
1481 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_stz2, stz2, stbl, ISOM_BOX_TYPE_STZ2, LSMASH_BOX_PRECEDENCE_ISOM_STZ2 )
1482 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_stss, stss, stbl, ISOM_BOX_TYPE_STSS, LSMASH_BOX_PRECEDENCE_ISOM_STSS )
1483 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_stps, stps, stbl,   QT_BOX_TYPE_STPS, LSMASH_BOX_PRECEDENCE_QTFF_STPS )
1484 
1485 isom_stco_t *isom_add_stco( isom_stbl_t *stbl )
1486 {
1487     ADD_LIST_BOX( stco, stbl, ISOM_BOX_TYPE_STCO, LSMASH_BOX_PRECEDENCE_ISOM_STCO );
1488     stco->large_presentation = 0;
1489     return stco;
1490 }
1491 
isom_add_co64(isom_stbl_t * stbl)1492 isom_stco_t *isom_add_co64( isom_stbl_t *stbl )
1493 {
1494     ADD_LIST_BOX( stco, stbl, ISOM_BOX_TYPE_CO64, LSMASH_BOX_PRECEDENCE_ISOM_CO64 );
1495     stco->large_presentation = 1;
1496     return stco;
1497 }
1498 
isom_add_sdtp(isom_box_t * parent)1499 isom_sdtp_t *isom_add_sdtp( isom_box_t *parent )
1500 {
1501     if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
1502         return isom_non_existing_sdtp();
1503     if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_STBL ) )
1504     {
1505         isom_stbl_t *stbl = (isom_stbl_t *)parent;
1506         ADD_LIST_BOX( sdtp, stbl, ISOM_BOX_TYPE_SDTP, LSMASH_BOX_PRECEDENCE_ISOM_SDTP );
1507         return sdtp;
1508     }
1509     else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_TRAF ) )
1510     {
1511         isom_traf_t *traf = (isom_traf_t *)parent;
1512         ADD_LIST_BOX( sdtp, traf, ISOM_BOX_TYPE_SDTP, LSMASH_BOX_PRECEDENCE_ISOM_SDTP );
1513         return sdtp;
1514     }
1515     assert( 0 );
1516     return isom_non_existing_sdtp();
1517 }
1518 
isom_add_sgpd(void * parent_box)1519 isom_sgpd_t *isom_add_sgpd( void *parent_box )
1520 {
1521     isom_box_t *parent = (isom_box_t *)parent_box;
1522     if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
1523         return isom_non_existing_sgpd();
1524     if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_STBL ) )
1525     {
1526         isom_stbl_t *stbl = (isom_stbl_t *)parent;
1527         ADD_LIST_BOX_IN_LIST( sgpd, stbl, ISOM_BOX_TYPE_SGPD, LSMASH_BOX_PRECEDENCE_ISOM_SGPD );
1528         return sgpd;
1529     }
1530     else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_TRAF ) )
1531     {
1532         isom_traf_t *traf = (isom_traf_t *)parent;
1533         ADD_LIST_BOX_IN_LIST( sgpd, traf, ISOM_BOX_TYPE_SGPD, LSMASH_BOX_PRECEDENCE_ISOM_SGPD );
1534         return sgpd;
1535     }
1536     assert( 0 );
1537     return isom_non_existing_sgpd();
1538 }
1539 
isom_add_sbgp(void * parent_box)1540 isom_sbgp_t *isom_add_sbgp( void *parent_box )
1541 {
1542     isom_box_t *parent = (isom_box_t *)parent_box;
1543     if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
1544         return isom_non_existing_sbgp();
1545     if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_STBL ) )
1546     {
1547         isom_stbl_t *stbl = (isom_stbl_t *)parent;
1548         ADD_LIST_BOX_IN_LIST( sbgp, stbl, ISOM_BOX_TYPE_SBGP, LSMASH_BOX_PRECEDENCE_ISOM_SBGP );
1549         return sbgp;
1550     }
1551     else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_TRAF ) )
1552     {
1553         isom_traf_t *traf = (isom_traf_t *)parent;
1554         ADD_LIST_BOX_IN_LIST( sbgp, traf, ISOM_BOX_TYPE_SBGP, LSMASH_BOX_PRECEDENCE_ISOM_SBGP );
1555         return sbgp;
1556     }
1557     assert( 0 );
1558     return isom_non_existing_sbgp();
1559 }
1560 
DEFINE_SIMPLE_LIST_BOX_ADDER(isom_add_chpl,chpl,udta,ISOM_BOX_TYPE_CHPL,LSMASH_BOX_PRECEDENCE_ISOM_CHPL)1561 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_chpl, chpl, udta, ISOM_BOX_TYPE_CHPL, LSMASH_BOX_PRECEDENCE_ISOM_CHPL )
1562 
1563 isom_metaitem_t *isom_add_metaitem( isom_ilst_t *ilst, lsmash_itunes_metadata_item item )
1564 {
1565     if( LSMASH_IS_NON_EXISTING_BOX( ilst ) )
1566         return isom_non_existing_metaitem();
1567     lsmash_box_type_t type = lsmash_form_iso_box_type( item );
1568     ADD_BOX_IN_LIST( metaitem, ilst, type, LSMASH_BOX_PRECEDENCE_ISOM_METAITEM );
1569     return metaitem;
1570 }
1571 
DEFINE_SIMPLE_BOX_ADDER(isom_add_mean,mean,metaitem,ISOM_BOX_TYPE_MEAN,LSMASH_BOX_PRECEDENCE_ISOM_MEAN)1572 DEFINE_SIMPLE_BOX_ADDER     ( isom_add_mean, mean, metaitem, ISOM_BOX_TYPE_MEAN, LSMASH_BOX_PRECEDENCE_ISOM_MEAN )
1573 DEFINE_SIMPLE_BOX_ADDER     ( isom_add_name, name, metaitem, ISOM_BOX_TYPE_NAME, LSMASH_BOX_PRECEDENCE_ISOM_NAME )
1574 DEFINE_SIMPLE_BOX_ADDER     ( isom_add_data, data, metaitem, ISOM_BOX_TYPE_DATA, LSMASH_BOX_PRECEDENCE_ISOM_DATA )
1575 DEFINE_SIMPLE_BOX_ADDER     ( isom_add_ilst, ilst, meta,     ISOM_BOX_TYPE_ILST, LSMASH_BOX_PRECEDENCE_ISOM_ILST )
1576 DEFINE_SIMPLE_LIST_BOX_ADDER( isom_add_keys, keys, meta,       QT_BOX_TYPE_KEYS, LSMASH_BOX_PRECEDENCE_QTFF_KEYS )
1577 
1578 isom_meta_t *isom_add_meta( void *parent_box )
1579 {
1580     isom_box_t *parent = (isom_box_t *)parent_box;
1581     if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
1582         return isom_non_existing_meta();
1583     CREATE_BOX( meta, parent, ISOM_BOX_TYPE_META, LSMASH_BOX_PRECEDENCE_ISOM_META, 1 );
1584     if( parent->file == (lsmash_file_t *)parent )
1585         ATTACH_EXACTLY_ONE_BOX_TO_PARENT( meta, lsmash_file_t );
1586     else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_MOOV ) )
1587         ATTACH_EXACTLY_ONE_BOX_TO_PARENT( meta, isom_moov_t );
1588     else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_TRAK ) )
1589         ATTACH_EXACTLY_ONE_BOX_TO_PARENT( meta, isom_trak_t );
1590     else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_UDTA ) )
1591         ATTACH_EXACTLY_ONE_BOX_TO_PARENT( meta, isom_udta_t );
1592     else
1593         assert( 0 );
1594     return meta;
1595 }
1596 
DEFINE_SIMPLE_BOX_IN_LIST_ADDER(isom_add_cprt,cprt,udta,ISOM_BOX_TYPE_CPRT,LSMASH_BOX_PRECEDENCE_ISOM_CPRT)1597 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_cprt, cprt, udta, ISOM_BOX_TYPE_CPRT, LSMASH_BOX_PRECEDENCE_ISOM_CPRT )
1598 
1599 isom_udta_t *isom_add_udta( void *parent_box )
1600 {
1601     isom_box_t *parent = (isom_box_t *)parent_box;
1602     if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
1603         return isom_non_existing_udta();
1604     if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_MOOV ) )
1605     {
1606         isom_moov_t *moov = (isom_moov_t *)parent;
1607         ADD_BOX( udta, moov, ISOM_BOX_TYPE_UDTA, LSMASH_BOX_PRECEDENCE_ISOM_UDTA );
1608         return udta;
1609     }
1610     else if( lsmash_check_box_type_identical( parent->type, ISOM_BOX_TYPE_TRAK ) )
1611     {
1612         isom_trak_t *trak = (isom_trak_t *)parent;
1613         ADD_BOX( udta, trak, ISOM_BOX_TYPE_UDTA, LSMASH_BOX_PRECEDENCE_ISOM_UDTA );
1614         return udta;
1615     }
1616     assert( 0 );
1617     return isom_non_existing_udta();
1618 }
1619 
DEFINE_SIMPLE_BOX_ADDER(isom_add_WLOC,WLOC,udta,QT_BOX_TYPE_WLOC,LSMASH_BOX_PRECEDENCE_QTFF_WLOC)1620 DEFINE_SIMPLE_BOX_ADDER        ( isom_add_WLOC, WLOC, udta,   QT_BOX_TYPE_WLOC, LSMASH_BOX_PRECEDENCE_QTFF_WLOC )
1621 DEFINE_SIMPLE_BOX_ADDER        ( isom_add_LOOP, LOOP, udta,   QT_BOX_TYPE_LOOP, LSMASH_BOX_PRECEDENCE_QTFF_LOOP )
1622 DEFINE_SIMPLE_BOX_ADDER        ( isom_add_SelO, SelO, udta,   QT_BOX_TYPE_SELO, LSMASH_BOX_PRECEDENCE_QTFF_SELO )
1623 DEFINE_SIMPLE_BOX_ADDER        ( isom_add_AllF, AllF, udta,   QT_BOX_TYPE_ALLF, LSMASH_BOX_PRECEDENCE_QTFF_ALLF )
1624 DEFINE_SIMPLE_BOX_ADDER        ( isom_add_mvex, mvex, moov, ISOM_BOX_TYPE_MVEX, LSMASH_BOX_PRECEDENCE_ISOM_MVEX )
1625 DEFINE_SIMPLE_BOX_ADDER        ( isom_add_mehd, mehd, mvex, ISOM_BOX_TYPE_MEHD, LSMASH_BOX_PRECEDENCE_ISOM_MEHD )
1626 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_trex, trex, mvex, ISOM_BOX_TYPE_TREX, LSMASH_BOX_PRECEDENCE_ISOM_TREX )
1627 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_moof, moof, file_abstract, ISOM_BOX_TYPE_MOOF, LSMASH_BOX_PRECEDENCE_ISOM_MOOF )
1628 DEFINE_SIMPLE_BOX_ADDER        ( isom_add_mfhd, mfhd, moof, ISOM_BOX_TYPE_MFHD, LSMASH_BOX_PRECEDENCE_ISOM_MFHD )
1629 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_traf, traf, moof, ISOM_BOX_TYPE_TRAF, LSMASH_BOX_PRECEDENCE_ISOM_TRAF )
1630 DEFINE_SIMPLE_BOX_ADDER        ( isom_add_tfhd, tfhd, traf, ISOM_BOX_TYPE_TFHD, LSMASH_BOX_PRECEDENCE_ISOM_TFHD )
1631 DEFINE_SIMPLE_BOX_ADDER        ( isom_add_tfdt, tfdt, traf, ISOM_BOX_TYPE_TFDT, LSMASH_BOX_PRECEDENCE_ISOM_TFDT )
1632 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_trun, trun, traf, ISOM_BOX_TYPE_TRUN, LSMASH_BOX_PRECEDENCE_ISOM_TRUN )
1633 DEFINE_SIMPLE_BOX_ADDER        ( isom_add_mfra, mfra, file_abstract, ISOM_BOX_TYPE_MFRA, LSMASH_BOX_PRECEDENCE_ISOM_MFRA )
1634 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_tfra, tfra, mfra, ISOM_BOX_TYPE_TFRA, LSMASH_BOX_PRECEDENCE_ISOM_TFRA )
1635 DEFINE_SIMPLE_BOX_ADDER        ( isom_add_mfro, mfro, mfra, ISOM_BOX_TYPE_MFRO, LSMASH_BOX_PRECEDENCE_ISOM_MFRO )
1636 
1637 isom_mdat_t *isom_add_mdat( isom_file_abstract_t *file )
1638 {
1639     assert( LSMASH_IS_NON_EXISTING_BOX( file->mdat ) );
1640     CREATE_BOX( mdat, file, ISOM_BOX_TYPE_MDAT, LSMASH_BOX_PRECEDENCE_ISOM_MDAT, 1 );
1641     file->mdat = mdat;
1642     return mdat;
1643 }
1644 
isom_add_free(void * parent_box)1645 isom_free_t *isom_add_free( void *parent_box )
1646 {
1647     isom_box_t *parent = (isom_box_t *)parent_box;
1648     if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
1649         return isom_non_existing_skip();
1650     CREATE_BOX( skip, parent, ISOM_BOX_TYPE_FREE, LSMASH_BOX_PRECEDENCE_ISOM_FREE, 1 );
1651     return skip;
1652 }
1653 
DEFINE_SIMPLE_BOX_IN_LIST_ADDER(isom_add_styp,styp,file_abstract,ISOM_BOX_TYPE_STYP,LSMASH_BOX_PRECEDENCE_ISOM_STYP)1654 DEFINE_SIMPLE_BOX_IN_LIST_ADDER( isom_add_styp, styp, file_abstract, ISOM_BOX_TYPE_STYP, LSMASH_BOX_PRECEDENCE_ISOM_STYP )
1655 
1656 isom_sidx_t *isom_add_sidx( isom_file_abstract_t *file_abstract )
1657 {
1658     ADD_LIST_BOX_IN_LIST( sidx, file_abstract, ISOM_BOX_TYPE_SIDX, LSMASH_BOX_PRECEDENCE_ISOM_SIDX );
1659     return sidx;
1660 }
1661 
1662 #undef ATTACH_EXACTLY_ONE_BOX_TO_PARENT
1663 #undef CREATE_BOX
1664 #undef CREATE_LIST_BOX
1665 #undef ADD_BOX_TEMPLATE
1666 #undef ADD_BOX_IN_LIST_TEMPLATE
1667 #undef ADD_BOX
1668 #undef ADD_BOX_IN_LIST
1669 #undef ADD_LIST_BOX
1670 #undef ADD_LIST_BOX_IN_LIST
1671 #undef DEFINE_SIMPLE_BOX_ADDER_TEMPLATE
1672 #undef DEFINE_SIMPLE_BOX_ADDER_TEMPLATE_6
1673 #undef DEFINE_SIMPLE_BOX_ADDER_TEMPLATE_5
1674 #undef DEFINE_SIMPLE_BOX_ADDER
1675 #undef DEFINE_SIMPLE_BOX_IN_LIST_ADDER
1676 #undef DEFINE_SIMPLE_LIST_BOX_ADDER
1677 
fake_file_read(void * opaque,uint8_t * buf,int size)1678 static int fake_file_read
1679 (
1680     void    *opaque,
1681     uint8_t *buf,
1682     int      size
1683 )
1684 {
1685     fake_file_stream_t *stream = (fake_file_stream_t *)opaque;
1686     int read_size;
1687     if( stream->pos + size > stream->size )
1688         read_size = stream->size - stream->pos;
1689     else
1690         read_size = size;
1691     memcpy( buf, stream->data + stream->pos, read_size );
1692     stream->pos += read_size;
1693     return read_size;
1694 }
1695 
fake_file_seek(void * opaque,int64_t offset,int whence)1696 static int64_t fake_file_seek
1697 (
1698     void   *opaque,
1699     int64_t offset,
1700     int     whence
1701 )
1702 {
1703     fake_file_stream_t *stream = (fake_file_stream_t *)opaque;
1704     if( whence == SEEK_SET )
1705         stream->pos = offset;
1706     else if( whence == SEEK_CUR )
1707         stream->pos += offset;
1708     else if( whence == SEEK_END )
1709         stream->pos = stream->size + offset;
1710     return stream->pos;
1711 }
1712 
1713 /* Public functions */
lsmash_create_root(void)1714 lsmash_root_t *lsmash_create_root( void )
1715 {
1716     lsmash_root_t *root = ALLOCATE_BOX( root_abstract );
1717     if( LSMASH_IS_NON_EXISTING_BOX( root ) )
1718         return NULL;
1719     root->root = root;
1720     return root;
1721 }
1722 
lsmash_destroy_root(lsmash_root_t * root)1723 void lsmash_destroy_root( lsmash_root_t *root )
1724 {
1725     isom_remove_box_by_itself( root );
1726 }
1727 
lsmash_form_extended_box_type(uint32_t fourcc,const uint8_t id[12])1728 lsmash_extended_box_type_t lsmash_form_extended_box_type( uint32_t fourcc, const uint8_t id[12] )
1729 {
1730     return (lsmash_extended_box_type_t){ fourcc, { id[0], id[1], id[2], id[3], id[4],  id[5],
1731                                                    id[6], id[7], id[8], id[9], id[10], id[11] } };
1732 }
1733 
lsmash_form_box_type(lsmash_compact_box_type_t type,lsmash_extended_box_type_t user)1734 lsmash_box_type_t lsmash_form_box_type
1735 (
1736     lsmash_compact_box_type_t  type,
1737     lsmash_extended_box_type_t user
1738 )
1739 {
1740     return (lsmash_box_type_t){ type, user };
1741 }
1742 
lsmash_form_iso_box_type(uint32_t fourcc)1743 lsmash_box_type_t lsmash_form_iso_box_type( uint32_t fourcc )
1744 {
1745     return (lsmash_box_type_t){ fourcc, lsmash_form_extended_box_type( fourcc, LSMASH_ISO_12_BYTES ) };
1746 }
1747 
lsmash_form_qtff_box_type(uint32_t fourcc)1748 lsmash_box_type_t lsmash_form_qtff_box_type( uint32_t fourcc )
1749 {
1750     return (lsmash_box_type_t){ fourcc, lsmash_form_extended_box_type( fourcc, LSMASH_QTFF_12_BYTES ) };
1751 }
1752 
1753 #define CHECK_BOX_TYPE_IDENTICAL( a, b ) \
1754        a.fourcc      == b.fourcc         \
1755     && a.user.fourcc == b.user.fourcc    \
1756     && a.user.id[0]  == b.user.id[0]     \
1757     && a.user.id[1]  == b.user.id[1]     \
1758     && a.user.id[2]  == b.user.id[2]     \
1759     && a.user.id[3]  == b.user.id[3]     \
1760     && a.user.id[4]  == b.user.id[4]     \
1761     && a.user.id[5]  == b.user.id[5]     \
1762     && a.user.id[6]  == b.user.id[6]     \
1763     && a.user.id[7]  == b.user.id[7]     \
1764     && a.user.id[8]  == b.user.id[8]     \
1765     && a.user.id[9]  == b.user.id[9]     \
1766     && a.user.id[10] == b.user.id[10]    \
1767     && a.user.id[11] == b.user.id[11]
1768 
lsmash_check_box_type_identical(lsmash_box_type_t a,lsmash_box_type_t b)1769 int lsmash_check_box_type_identical( lsmash_box_type_t a, lsmash_box_type_t b )
1770 {
1771     return CHECK_BOX_TYPE_IDENTICAL( a, b );
1772 }
1773 
lsmash_check_codec_type_identical(lsmash_codec_type_t a,lsmash_codec_type_t b)1774 int lsmash_check_codec_type_identical( lsmash_codec_type_t a, lsmash_codec_type_t b )
1775 {
1776     return CHECK_BOX_TYPE_IDENTICAL( a, b );
1777 }
1778 
lsmash_check_box_type_specified(const lsmash_box_type_t * box_type)1779 int lsmash_check_box_type_specified( const lsmash_box_type_t *box_type )
1780 {
1781     assert( box_type );
1782     if( !box_type )
1783         return 0;
1784     return !!(box_type->fourcc
1785             | box_type->user.fourcc
1786             | box_type->user.id[0] | box_type->user.id[1] | box_type->user.id[2]  | box_type->user.id[3]
1787             | box_type->user.id[4] | box_type->user.id[5] | box_type->user.id[6]  | box_type->user.id[7]
1788             | box_type->user.id[8] | box_type->user.id[9] | box_type->user.id[10] | box_type->user.id[11]);
1789 }
1790 
lsmash_get_box(lsmash_box_t * parent,const lsmash_box_path_t box_path[])1791 lsmash_box_t *lsmash_get_box
1792 (
1793     lsmash_box_t           *parent,
1794     const lsmash_box_path_t box_path[]
1795 )
1796 {
1797     lsmash_entry_t *entry = isom_get_entry_of_box( parent, box_path );
1798     return (lsmash_box_t *)(entry ? entry->data : NULL);
1799 }
1800 
lsmash_create_box(lsmash_box_type_t type,uint8_t * data,uint32_t size,uint64_t precedence)1801 lsmash_box_t *lsmash_create_box
1802 (
1803     lsmash_box_type_t type,
1804     uint8_t          *data,
1805     uint32_t          size,
1806     uint64_t          precedence
1807 )
1808 {
1809     if( !lsmash_check_box_type_specified( &type ) )
1810         return NULL;
1811     isom_unknown_box_t *box = ALLOCATE_BOX( unknown );
1812     if( LSMASH_IS_NON_EXISTING_BOX( box ) )
1813         return NULL;
1814     if( size && data )
1815     {
1816         box->unknown_size  = size;
1817         box->unknown_field = lsmash_memdup( data, size );
1818         if( !box->unknown_field )
1819         {
1820             lsmash_free( box );
1821             return NULL;
1822         }
1823     }
1824     else
1825     {
1826         box->unknown_size  = 0;
1827         box->unknown_field = NULL;
1828         size = 0;
1829     }
1830     box->class      = &lsmash_box_class;
1831     box->root       = isom_non_existing_root_abstract();
1832     box->file       = isom_non_existing_file_abstract();
1833     box->parent     = (isom_box_t *)isom_non_existing_unknown();
1834     box->destruct   = (isom_extension_destructor_t)isom_remove_unknown_box;
1835     box->manager    = LSMASH_UNKNOWN_BOX;
1836     box->precedence = precedence;
1837     box->size       = ISOM_BASEBOX_COMMON_SIZE + size + (type.fourcc == ISOM_BOX_TYPE_UUID.fourcc ? 16 : 0);
1838     box->type       = type;
1839     isom_set_box_writer( (isom_box_t *)box );
1840     return (lsmash_box_t *)box;
1841 }
1842 
lsmash_add_box(lsmash_box_t * parent,lsmash_box_t * box)1843 int lsmash_add_box
1844 (
1845     lsmash_box_t *parent,
1846     lsmash_box_t *box
1847 )
1848 {
1849     if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
1850         /* You cannot add any box without a box being its parent. */
1851         return LSMASH_ERR_FUNCTION_PARAM;
1852     if( LSMASH_IS_NON_EXISTING_BOX( box ) || box->size < ISOM_BASEBOX_COMMON_SIZE )
1853         return LSMASH_ERR_FUNCTION_PARAM;
1854     if( parent->root == (lsmash_root_t *)parent )
1855     {
1856         /* Only files can be added into any ROOT.
1857          * For backward compatibility, use the active file as the parent. */
1858         if( LSMASH_IS_EXISTING_BOX( parent->file ) )
1859             parent = (isom_box_t *)parent->file;
1860         else
1861             return LSMASH_ERR_FUNCTION_PARAM;
1862     }
1863     /* Add a box as a child box. */
1864     box->class  = &lsmash_box_class;
1865     box->root   = parent->root;
1866     box->file   = parent->file;
1867     box->parent = parent;
1868     return isom_add_box_to_extension_list( parent, box );
1869 }
1870 
lsmash_add_box_ex(lsmash_box_t * parent,lsmash_box_t ** p_box)1871 int lsmash_add_box_ex
1872 (
1873     lsmash_box_t  *parent,
1874     lsmash_box_t **p_box
1875 )
1876 {
1877     if( LSMASH_IS_NON_EXISTING_BOX( parent ) )
1878         /* You cannot add any box without a box being its parent. */
1879         return LSMASH_ERR_FUNCTION_PARAM;
1880     isom_unknown_box_t *box = (isom_unknown_box_t *)*p_box;
1881     if( LSMASH_IS_NON_EXISTING_BOX( box ) || box->size < ISOM_BASEBOX_COMMON_SIZE )
1882         return LSMASH_ERR_FUNCTION_PARAM;
1883     if( !(box->manager & LSMASH_UNKNOWN_BOX) )
1884         /* Simply add the box. */
1885         return lsmash_add_box( parent, *p_box );
1886     /* Check if the size of the box to be added is valid. */
1887     if( box->size != ISOM_BASEBOX_COMMON_SIZE + box->unknown_size + (box->type.fourcc == ISOM_BOX_TYPE_UUID.fourcc ? 16 : 0) )
1888         return LSMASH_ERR_FUNCTION_PARAM;
1889     if( LSMASH_IS_NON_EXISTING_BOX( parent->file ) || parent->file == (lsmash_file_t *)box )
1890         return LSMASH_ERR_FUNCTION_PARAM;
1891     if( parent->root == (lsmash_root_t *)parent )
1892         /* Only files can be added into any ROOT.
1893          * For backward compatibility, use the active file as the parent. */
1894         parent = (isom_box_t *)parent->file;
1895     /* Switch to the fake-file stream mode. */
1896     lsmash_file_t *file      = parent->file;
1897     lsmash_bs_t   *bs_backup = file->bs;
1898     lsmash_bs_t   *bs        = lsmash_bs_create();
1899     if( !bs )
1900         return LSMASH_ERR_MEMORY_ALLOC;
1901     uint8_t *buf = lsmash_malloc( box->size );
1902     if( !buf )
1903     {
1904         lsmash_bs_cleanup( bs );
1905         return LSMASH_ERR_MEMORY_ALLOC;
1906     }
1907     fake_file_stream_t fake_file =
1908         {
1909             .size = box->size,
1910             .data = buf,
1911             .pos  = 0
1912         };
1913     bs->stream = &fake_file;
1914     bs->read   = fake_file_read;
1915     bs->write  = NULL;
1916     bs->seek   = fake_file_seek;
1917     file->bs             = bs;
1918     file->fake_file_mode = 1;
1919     /* Make the byte string representing the given box. */
1920     LSMASH_SET_BE32( &buf[0], box->size );
1921     LSMASH_SET_BE32( &buf[4], box->type.fourcc );
1922     if( box->type.fourcc == ISOM_BOX_TYPE_UUID.fourcc )
1923     {
1924         LSMASH_SET_BE32( &buf[8], box->type.user.fourcc );
1925         memcpy( &buf[12], box->type.user.id, 12 );
1926     }
1927     memcpy( buf + (uintptr_t)(box->size - box->unknown_size), box->unknown_field, box->unknown_size );
1928     /* Add a box as a child box and try to expand into struct format. */
1929     lsmash_box_t dummy = { 0 };
1930     int ret = isom_read_box( file, &dummy, parent, 0, 0 );
1931     lsmash_free( buf );
1932     lsmash_bs_cleanup( bs );
1933     file->bs             = bs_backup;   /* Switch back to the normal file stream mode. */
1934     file->fake_file_mode = 0;
1935     if( ret < 0 )
1936         return ret;
1937     /* Reorder the added box by 'precedence'. */
1938     *p_box = (lsmash_box_t *)parent->extensions.tail->data;
1939     (*p_box)->precedence = box->precedence;
1940     isom_reorder_tail_box( parent );
1941     /* Do also its children by the same way. */
1942     lsmash_entry_list_t extensions = box->extensions;
1943     lsmash_list_init_simple( &box->extensions );    /* to avoid freeing the children */
1944     isom_remove_box_by_itself( box );
1945     for( lsmash_entry_t *entry = extensions.head; entry; entry = entry->next )
1946     {
1947         if( !entry->data )
1948             continue;
1949         lsmash_box_t *child = (lsmash_box_t *)entry->data;
1950         if( lsmash_add_box_ex( *p_box, &child ) == 0 )
1951         {
1952             (*p_box)->size += child->size;
1953             /* Avoid freeing at the end of this function. */
1954             entry->data = NULL;
1955         }
1956     }
1957     isom_remove_all_extension_boxes( &extensions );
1958     return 0;
1959 }
1960 
lsmash_destroy_box(lsmash_box_t * box)1961 void lsmash_destroy_box
1962 (
1963     lsmash_box_t *box
1964 )
1965 {
1966     isom_remove_box_by_itself( box );
1967 }
1968 
lsmash_destroy_children(lsmash_box_t * box)1969 void lsmash_destroy_children
1970 (
1971     lsmash_box_t *box
1972 )
1973 {
1974     if( LSMASH_IS_EXISTING_BOX( box ) )
1975         isom_remove_all_extension_boxes( &box->extensions );
1976 }
1977 
lsmash_get_box_precedence(lsmash_box_t * box,uint64_t * precedence)1978 int lsmash_get_box_precedence
1979 (
1980     lsmash_box_t *box,
1981     uint64_t     *precedence
1982 )
1983 {
1984     if( !box || !precedence )
1985         return LSMASH_ERR_FUNCTION_PARAM;
1986     *precedence = box->precedence;
1987     return 0;
1988 }
1989 
lsmash_root_as_box(lsmash_root_t * root)1990 lsmash_box_t *lsmash_root_as_box
1991 (
1992     lsmash_root_t *root
1993 )
1994 {
1995     return (lsmash_box_t *)root;
1996 }
1997 
lsmash_file_as_box(lsmash_file_t * file)1998 lsmash_box_t *lsmash_file_as_box
1999 (
2000     lsmash_file_t *file
2001 )
2002 {
2003     return (lsmash_box_t *)file;
2004 }
2005 
lsmash_write_top_level_box(lsmash_box_t * box)2006 int lsmash_write_top_level_box
2007 (
2008     lsmash_box_t *box
2009 )
2010 {
2011     if( !box || (isom_box_t *)box->file != box->parent )
2012         return LSMASH_ERR_FUNCTION_PARAM;
2013     int ret = isom_write_box( box->file->bs, box );
2014     if( ret < 0 )
2015         return ret;
2016     box->file->size += box->size;
2017     return 0;
2018 }
2019 
lsmash_export_box(lsmash_box_t * box,uint32_t * size)2020 uint8_t *lsmash_export_box
2021 (
2022     lsmash_box_t *box,
2023     uint32_t     *size
2024 )
2025 {
2026     if( !box || !size )
2027         return NULL;
2028     lsmash_bs_t *bs = lsmash_bs_create();
2029     if( !bs )
2030         return NULL;
2031     if( isom_write_box( bs, box ) < 0 )
2032     {
2033         lsmash_bs_cleanup( bs );
2034         return NULL;
2035     }
2036     *size = bs->buffer.store;
2037     uint8_t *data = bs->buffer.data;
2038     bs->buffer.data = NULL;
2039     lsmash_bs_cleanup( bs );
2040     return data;
2041 }
2042