importer: Add fake movie maker.
[L-SMASH.git] / core / file.c
blob219d6fea41c951c9c5c6f18e82a2b94e92469c3a
1 /*****************************************************************************
2 * file.c
3 *****************************************************************************
4 * Copyright (C) 2010-2014 L-SMASH project
6 * Authors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 *****************************************************************************/
21 /* This file is available under an ISC license. */
23 #include "common/internal.h" /* must be placed first */
25 #include <string.h>
26 #include <fcntl.h>
28 #include "box.h"
29 #include "read.h"
30 #include "fragment.h"
32 #include "importer/importer.h"
34 static void isom_clear_compat_flags
36 lsmash_file_t *file
39 /* Clear flags for compatibility. */
40 memset( (int8_t *)file + COMPAT_FLAGS_OFFSET, 0, sizeof(lsmash_file_t) - COMPAT_FLAGS_OFFSET );
41 file->min_isom_version = UINT8_MAX; /* undefined value */
44 int isom_check_compatibility
46 lsmash_file_t *file
49 if( !file )
50 return LSMASH_ERR_FUNCTION_PARAM;
51 isom_clear_compat_flags( file );
52 /* Get the brand container. */
53 isom_ftyp_t *ftyp = file->ftyp ? file->ftyp : (isom_ftyp_t *)lsmash_get_entry_data( &file->styp_list, 1 );
54 /* Check brand to decide mandatory boxes. */
55 if( !ftyp )
57 /* No brand declaration means this file is a MP4 version 1 or QuickTime file format. */
58 if( file->moov
59 && file->moov->iods )
61 file->mp4_version1 = 1;
62 file->isom_compatible = 1;
64 else
66 file->qt_compatible = 1;
67 file->undefined_64_ver = 1;
69 return 0;
71 for( uint32_t i = 0; i <= ftyp->brand_count; i++ )
73 uint32_t brand = (i == ftyp->brand_count ? ftyp->major_brand : ftyp->compatible_brands[i]);
74 switch( brand )
76 case ISOM_BRAND_TYPE_QT :
77 file->qt_compatible = 1;
78 break;
79 case ISOM_BRAND_TYPE_MP41 :
80 file->mp4_version1 = 1;
81 break;
82 case ISOM_BRAND_TYPE_MP42 :
83 file->mp4_version2 = 1;
84 break;
85 case ISOM_BRAND_TYPE_AVC1 :
86 case ISOM_BRAND_TYPE_ISOM :
87 file->max_isom_version = LSMASH_MAX( file->max_isom_version, 1 );
88 file->min_isom_version = LSMASH_MIN( file->min_isom_version, 1 );
89 break;
90 case ISOM_BRAND_TYPE_ISO2 :
91 file->max_isom_version = LSMASH_MAX( file->max_isom_version, 2 );
92 file->min_isom_version = LSMASH_MIN( file->min_isom_version, 2 );
93 break;
94 case ISOM_BRAND_TYPE_ISO3 :
95 file->max_isom_version = LSMASH_MAX( file->max_isom_version, 3 );
96 file->min_isom_version = LSMASH_MIN( file->min_isom_version, 3 );
97 break;
98 case ISOM_BRAND_TYPE_ISO4 :
99 file->max_isom_version = LSMASH_MAX( file->max_isom_version, 4 );
100 file->min_isom_version = LSMASH_MIN( file->min_isom_version, 4 );
101 break;
102 case ISOM_BRAND_TYPE_ISO5 :
103 file->max_isom_version = LSMASH_MAX( file->max_isom_version, 5 );
104 file->min_isom_version = LSMASH_MIN( file->min_isom_version, 5 );
105 break;
106 case ISOM_BRAND_TYPE_ISO6 :
107 file->max_isom_version = LSMASH_MAX( file->max_isom_version, 6 );
108 file->min_isom_version = LSMASH_MIN( file->min_isom_version, 6 );
109 break;
110 case ISOM_BRAND_TYPE_ISO7 :
111 file->max_isom_version = LSMASH_MAX( file->max_isom_version, 7 );
112 file->min_isom_version = LSMASH_MIN( file->min_isom_version, 7 );
113 break;
114 case ISOM_BRAND_TYPE_M4A :
115 case ISOM_BRAND_TYPE_M4B :
116 case ISOM_BRAND_TYPE_M4P :
117 case ISOM_BRAND_TYPE_M4V :
118 file->itunes_movie = 1;
119 break;
120 case ISOM_BRAND_TYPE_3GP4 :
121 file->max_3gpp_version = LSMASH_MAX( file->max_3gpp_version, 4 );
122 break;
123 case ISOM_BRAND_TYPE_3GP5 :
124 file->max_3gpp_version = LSMASH_MAX( file->max_3gpp_version, 5 );
125 break;
126 case ISOM_BRAND_TYPE_3GE6 :
127 case ISOM_BRAND_TYPE_3GG6 :
128 case ISOM_BRAND_TYPE_3GP6 :
129 case ISOM_BRAND_TYPE_3GR6 :
130 case ISOM_BRAND_TYPE_3GS6 :
131 file->max_3gpp_version = LSMASH_MAX( file->max_3gpp_version, 6 );
132 break;
133 case ISOM_BRAND_TYPE_3GP7 :
134 file->max_3gpp_version = LSMASH_MAX( file->max_3gpp_version, 7 );
135 break;
136 case ISOM_BRAND_TYPE_3GP8 :
137 file->max_3gpp_version = LSMASH_MAX( file->max_3gpp_version, 8 );
138 break;
139 case ISOM_BRAND_TYPE_3GE9 :
140 case ISOM_BRAND_TYPE_3GF9 :
141 case ISOM_BRAND_TYPE_3GG9 :
142 case ISOM_BRAND_TYPE_3GH9 :
143 case ISOM_BRAND_TYPE_3GM9 :
144 case ISOM_BRAND_TYPE_3GP9 :
145 case ISOM_BRAND_TYPE_3GR9 :
146 case ISOM_BRAND_TYPE_3GS9 :
147 case ISOM_BRAND_TYPE_3GT9 :
148 file->max_3gpp_version = LSMASH_MAX( file->max_3gpp_version, 9 );
149 break;
150 default :
151 break;
153 switch( brand )
155 case ISOM_BRAND_TYPE_AVC1 :
156 case ISOM_BRAND_TYPE_ISO2 :
157 case ISOM_BRAND_TYPE_ISO3 :
158 case ISOM_BRAND_TYPE_ISO4 :
159 case ISOM_BRAND_TYPE_ISO5 :
160 case ISOM_BRAND_TYPE_ISO6 :
161 file->avc_extensions = 1;
162 break;
163 case ISOM_BRAND_TYPE_3GP4 :
164 case ISOM_BRAND_TYPE_3GP5 :
165 case ISOM_BRAND_TYPE_3GP6 :
166 case ISOM_BRAND_TYPE_3GP7 :
167 case ISOM_BRAND_TYPE_3GP8 :
168 case ISOM_BRAND_TYPE_3GP9 :
169 file->forbid_tref = 1;
170 break;
171 case ISOM_BRAND_TYPE_3GH9 :
172 case ISOM_BRAND_TYPE_3GM9 :
173 case ISOM_BRAND_TYPE_DASH :
174 case ISOM_BRAND_TYPE_DSMS :
175 case ISOM_BRAND_TYPE_LMSG :
176 case ISOM_BRAND_TYPE_MSDH :
177 case ISOM_BRAND_TYPE_MSIX :
178 case ISOM_BRAND_TYPE_SIMS :
179 file->media_segment = 1;
180 break;
181 default :
182 break;
185 file->isom_compatible = !file->qt_compatible
186 || file->mp4_version1
187 || file->mp4_version2
188 || file->itunes_movie
189 || file->max_3gpp_version;
190 file->undefined_64_ver = file->qt_compatible || file->itunes_movie;
191 if( file->flags & LSMASH_FILE_MODE_WRITE )
193 /* Media Segment is incompatible with ISO Base Media File Format version 4 or former must be compatible with
194 * version 6 or later since it requires default-base-is-moof and Track Fragment Base Media Decode Time Box. */
195 if( file->media_segment && (file->min_isom_version < 5 || (file->max_isom_version && file->max_isom_version < 6)) )
196 return LSMASH_ERR_INVALID_DATA;
197 file->allow_moof_base = (file->max_isom_version >= 5 && file->min_isom_version >= 5)
198 || (file->max_isom_version == 0 && file->min_isom_version == UINT8_MAX && file->media_segment);
200 return 0;
203 int isom_check_mandatory_boxes
205 lsmash_file_t *file
208 if( !file
209 || !file->moov
210 || !file->moov->mvhd )
211 return LSMASH_ERR_INVALID_DATA;
212 /* A movie requires at least one track. */
213 if( !file->moov->trak_list.head )
214 return LSMASH_ERR_INVALID_DATA;
215 for( lsmash_entry_t *entry = file->moov->trak_list.head; entry; entry = entry->next )
217 isom_trak_t *trak = (isom_trak_t *)entry->data;
218 if( !trak
219 || !trak->tkhd
220 || !trak->mdia
221 || !trak->mdia->mdhd
222 || !trak->mdia->hdlr
223 || !trak->mdia->minf
224 || !trak->mdia->minf->dinf
225 || !trak->mdia->minf->dinf->dref
226 || !trak->mdia->minf->stbl
227 || !trak->mdia->minf->stbl->stsd
228 || !trak->mdia->minf->stbl->stsz
229 || !trak->mdia->minf->stbl->stts
230 || !trak->mdia->minf->stbl->stsc
231 || !trak->mdia->minf->stbl->stco )
232 return LSMASH_ERR_INVALID_DATA;
233 if( file->qt_compatible && !trak->mdia->minf->hdlr )
234 return LSMASH_ERR_INVALID_DATA;
235 isom_stbl_t *stbl = trak->mdia->minf->stbl;
236 if( !stbl->stsd->list.head )
237 return LSMASH_ERR_INVALID_DATA;
238 if( !file->fragment
239 && (!stbl->stsd->list.head
240 || !stbl->stts->list || !stbl->stts->list->head
241 || !stbl->stsc->list || !stbl->stsc->list->head
242 || !stbl->stco->list || !stbl->stco->list->head) )
243 return LSMASH_ERR_INVALID_DATA;
245 if( !file->fragment )
246 return 0;
247 if( !file->moov->mvex )
248 return LSMASH_ERR_INVALID_DATA;
249 for( lsmash_entry_t *entry = file->moov->mvex->trex_list.head; entry; entry = entry->next )
250 if( !entry->data ) /* trex */
251 return LSMASH_ERR_INVALID_DATA;
252 return 0;
255 int isom_rearrange_data
257 lsmash_file_t *file,
258 lsmash_adhoc_remux_t *remux,
259 uint8_t *buf[2],
260 size_t read_num,
261 size_t size,
262 uint64_t read_pos,
263 uint64_t write_pos,
264 uint64_t file_size
267 assert( remux );
268 /* Copy-pastan */
269 int buf_switch = 1;
270 lsmash_bs_t *bs = file->bs;
271 int ret;
272 int64_t ret64;
273 while( read_num == size )
275 ret64 = lsmash_bs_write_seek( bs, read_pos, SEEK_SET );
276 if( ret64 < 0 )
277 return ret64;
278 ret = lsmash_bs_read_data( bs, buf[buf_switch], &read_num );
279 if( ret < 0 )
280 return ret;
281 read_pos = bs->offset;
282 buf_switch ^= 0x1;
283 ret64 = lsmash_bs_write_seek( bs, write_pos, SEEK_SET );
284 if( ret64 < 0 )
285 return ret64;
286 ret = lsmash_bs_write_data( bs, buf[buf_switch], size );
287 if( ret < 0 )
288 return ret;
289 write_pos = bs->offset;
290 if( remux->func )
291 remux->func( remux->param, write_pos, file_size ); // FIXME:
293 ret = lsmash_bs_write_data( bs, buf[buf_switch ^ 0x1], read_num );
294 if( ret < 0 )
295 return ret;
296 if( remux->func )
297 remux->func( remux->param, file_size, file_size ); // FIXME:
298 return 0;
301 static int isom_set_brands
303 lsmash_file_t *file,
304 lsmash_brand_type major_brand,
305 uint32_t minor_version,
306 lsmash_brand_type *brands,
307 uint32_t brand_count
310 if( brand_count > 50 )
311 return LSMASH_ERR_FUNCTION_PARAM; /* We support setting brands up to 50. */
312 if( major_brand == 0 || brand_count == 0 )
314 if( file->flags & LSMASH_FILE_MODE_INITIALIZATION )
316 /* Absence of File Type Box means this file is a QuickTime or MP4 version 1 format file. */
317 isom_remove_box_by_itself( file->ftyp );
318 /* Anyway we use QTFF as a default file format. */
319 isom_clear_compat_flags( file );
320 file->qt_compatible = 1;
322 else
324 /* The absence of the Segment Type Box is allowed.
325 * We set brands from the initialization segment after switching to this segment. */
326 for( lsmash_entry_t *entry = file->styp_list.head; entry; entry = entry->next )
327 isom_remove_box_by_itself( entry->data );
328 if( file->initializer )
330 /* Copy flags for compatibility. */
331 memcpy( (int8_t *)file + COMPAT_FLAGS_OFFSET, file->initializer, sizeof(lsmash_file_t) - COMPAT_FLAGS_OFFSET );
332 file->isom_compatible = 1;
333 file->allow_moof_base = 1;
334 file->media_segment = 1;
335 if( file->min_isom_version < 5 )
336 file->min_isom_version = 5;
337 if( file->max_isom_version < 6 )
338 file->max_isom_version = 6;
341 return 0;
343 isom_ftyp_t *ftyp;
344 if( file->flags & LSMASH_FILE_MODE_INITIALIZATION )
346 /* Add File Type Box if absent yet. */
347 if( !file->ftyp && !isom_add_ftyp( file ) )
348 return LSMASH_ERR_NAMELESS;
349 ftyp = file->ftyp;
351 else
353 /* Add Segment Type Box if absent yet. */
354 ftyp = file->styp_list.head && file->styp_list.head->data
355 ? (isom_styp_t *)file->styp_list.head->data
356 : isom_add_styp( file );
357 if( !ftyp )
358 return LSMASH_ERR_NAMELESS;
360 /* Allocate an array of compatible brands.
361 * ISO/IEC 14496-12 doesn't forbid the absence of brands in the compatible brand list.
362 * For a reason of safety, however, we set at least one brand in the list. */
363 size_t alloc_size = (brand_count ? brand_count : 1) * sizeof(uint32_t);
364 lsmash_brand_type *compatible_brands;
365 if( !file->compatible_brands )
366 compatible_brands = lsmash_malloc( alloc_size );
367 else
368 compatible_brands = lsmash_realloc( file->compatible_brands, alloc_size );
369 if( !compatible_brands )
370 return LSMASH_ERR_MEMORY_ALLOC;
371 /* Set compatible brands. */
372 if( brand_count )
373 for( uint32_t i = 0; i < brand_count; i++ )
374 compatible_brands[i] = brands[i];
375 else
377 /* At least one compatible brand. */
378 compatible_brands[0] = major_brand;
379 brand_count = 1;
381 file->compatible_brands = compatible_brands;
382 /* Duplicate an array of compatible brands. */
383 lsmash_free( ftyp->compatible_brands );
384 ftyp->compatible_brands = lsmash_memdup( compatible_brands, alloc_size );
385 if( !ftyp->compatible_brands )
387 lsmash_freep( &file->compatible_brands );
388 return LSMASH_ERR_MEMORY_ALLOC;
390 ftyp->size = ISOM_BASEBOX_COMMON_SIZE + 8 + brand_count * 4;
391 ftyp->major_brand = major_brand;
392 ftyp->minor_version = minor_version;
393 ftyp->brand_count = brand_count;
394 file->brand_count = brand_count;
395 return isom_check_compatibility( file );
398 /*******************************
399 public interfaces
400 *******************************/
402 void lsmash_discard_boxes
404 lsmash_root_t *root
407 if( !root || !root->file )
408 return;
409 isom_remove_all_extension_boxes( &root->file->extensions );
412 int lsmash_open_file
414 const char *filename,
415 int open_mode,
416 lsmash_file_parameters_t *param
419 if( !filename || !param )
420 return LSMASH_ERR_FUNCTION_PARAM;
421 char mode[4] = { 0 };
422 lsmash_file_mode file_mode = 0;
423 if( open_mode == 0 )
425 memcpy( mode, "w+b", 4 );
426 file_mode = LSMASH_FILE_MODE_WRITE
427 | LSMASH_FILE_MODE_BOX
428 | LSMASH_FILE_MODE_INITIALIZATION
429 | LSMASH_FILE_MODE_MEDIA;
431 #ifdef LSMASH_DEMUXER_ENABLED
432 else if( open_mode == 1 )
434 memcpy( mode, "rb", 3 );
435 file_mode = LSMASH_FILE_MODE_READ;
437 #endif
438 if( file_mode == 0 )
439 return LSMASH_ERR_FUNCTION_PARAM;
440 #ifdef _WIN32
441 _setmode( _fileno( stdin ), _O_BINARY );
442 _setmode( _fileno( stdout ), _O_BINARY );
443 _setmode( _fileno( stderr ), _O_BINARY );
444 #endif
445 FILE *stream = NULL;
446 int seekable = 1;
447 if( !strcmp( filename, "-" ) )
449 if( file_mode & LSMASH_FILE_MODE_READ )
451 stream = stdin;
452 seekable = 0;
454 else if( file_mode & LSMASH_FILE_MODE_WRITE )
456 stream = stdout;
457 seekable = 0;
458 file_mode |= LSMASH_FILE_MODE_FRAGMENTED;
461 else
462 stream = lsmash_fopen( filename, mode );
463 if( !stream )
464 return LSMASH_ERR_NAMELESS;
465 memset( param, 0, sizeof(lsmash_file_parameters_t) );
466 param->mode = file_mode;
467 param->opaque = (void *)stream;
468 param->read = lsmash_fread_wrapper;
469 param->write = lsmash_fwrite_wrapper;
470 param->seek = seekable ? lsmash_fseek_wrapper : NULL;
471 param->major_brand = 0;
472 param->brands = NULL;
473 param->brand_count = 0;
474 param->minor_version = 0;
475 param->max_chunk_duration = 0.5;
476 param->max_async_tolerance = 2.0;
477 param->max_chunk_size = 4 * 1024 * 1024;
478 param->max_read_size = 4 * 1024 * 1024;
479 return 0;
482 int lsmash_close_file
484 lsmash_file_parameters_t *param
487 if( !param )
488 return LSMASH_ERR_NAMELESS;
489 if( !param->opaque )
490 return 0;
491 int ret = fclose( (FILE *)param->opaque );
492 param->opaque = NULL;
493 return ret == 0 ? 0 : LSMASH_ERR_UNKNOWN;
496 lsmash_file_t *lsmash_set_file
498 lsmash_root_t *root,
499 lsmash_file_parameters_t *param
502 if( !root || !param )
503 return NULL;
504 lsmash_file_t *file = isom_add_file( root );
505 if( !file )
506 return NULL;
507 lsmash_bs_t *bs = lsmash_bs_create();
508 if( !bs )
509 goto fail;
510 file->bs = bs;
511 file->flags = param->mode;
512 file->bs->stream = param->opaque;
513 file->bs->read = param->read;
514 file->bs->write = param->write;
515 file->bs->seek = param->seek;
516 file->bs->unseekable = (param->seek == NULL);
517 file->bs->buffer.max_size = param->max_read_size;
518 file->max_chunk_duration = param->max_chunk_duration;
519 file->max_async_tolerance = LSMASH_MAX( param->max_async_tolerance, 2 * param->max_chunk_duration );
520 file->max_chunk_size = param->max_chunk_size;
521 if( (file->flags & LSMASH_FILE_MODE_WRITE)
522 && (file->flags & LSMASH_FILE_MODE_BOX) )
524 /* Construction of Segment Index Box requires seekability at our current implementation.
525 * If segment is not so large, data rearrangement can be avoided by buffering i.e. the
526 * seekability is not essential, but at present we don't support buffering of all materials
527 * within segment. */
528 if( (file->flags & LSMASH_FILE_MODE_INDEX) && file->bs->unseekable )
529 goto fail;
530 /* Establish the fragment handler if required. */
531 if( file->flags & LSMASH_FILE_MODE_FRAGMENTED )
533 file->fragment = lsmash_malloc_zero( sizeof(isom_fragment_manager_t) );
534 if( !file->fragment )
535 goto fail;
536 file->fragment->first_moof_pos = FIRST_MOOF_POS_UNDETERMINED;
537 file->fragment->pool = lsmash_create_entry_list();
538 if( !file->fragment->pool )
539 goto fail;
541 else if( file->bs->unseekable )
542 /* For unseekable output operations, LSMASH_FILE_MODE_FRAGMENTED shall be set. */
543 goto fail;
544 /* Establish file types. */
545 if( isom_set_brands( file, param->major_brand,
546 param->minor_version,
547 param->brands, param->brand_count ) < 0 )
548 goto fail;
549 /* Create the movie header if the initialization of the streams is required. */
550 if( (file->flags & LSMASH_FILE_MODE_INITIALIZATION) && !isom_movie_create( file ) )
551 goto fail;
553 if( !root->file )
554 root->file = file;
555 return file;
556 fail:
557 isom_remove_box_by_itself( file );
558 return NULL;
561 int64_t lsmash_read_file
563 lsmash_file_t *file,
564 lsmash_file_parameters_t *param
567 #ifdef LSMASH_DEMUXER_ENABLED
568 if( !file )
569 return (int64_t)LSMASH_ERR_FUNCTION_PARAM;
570 if( !file->bs )
571 return (int64_t)LSMASH_ERR_NAMELESS;
572 int64_t ret = LSMASH_ERR_NAMELESS;
573 if( file->flags & (LSMASH_FILE_MODE_READ | LSMASH_FILE_MODE_DUMP) )
575 importer_t *importer = lsmash_importer_alloc();
576 if( !importer )
577 return (int64_t)LSMASH_ERR_MEMORY_ALLOC;
578 file->importer = importer;
579 lsmash_importer_set_file( importer, file );
580 ret = lsmash_importer_find( importer, "ISOBMFF/QTFF", !file->bs->unseekable );
581 if( ret < 0 )
582 return ret;
583 if( param )
585 if( file->ftyp )
587 /* file types */
588 isom_ftyp_t *ftyp = file->ftyp;
589 param->major_brand = ftyp->major_brand ? ftyp->major_brand : ISOM_BRAND_TYPE_QT;
590 param->minor_version = ftyp->minor_version;
591 param->brands = file->compatible_brands;
592 param->brand_count = file->brand_count;
594 else if( file->styp_list.head && file->styp_list.head->data )
596 /* segment types */
597 isom_styp_t *styp = (isom_styp_t *)file->styp_list.head->data;
598 param->major_brand = styp->major_brand ? styp->major_brand : ISOM_BRAND_TYPE_QT;
599 param->minor_version = styp->minor_version;
600 param->brands = file->compatible_brands;
601 param->brand_count = file->brand_count;
603 else
605 param->major_brand = file->mp4_version1 ? ISOM_BRAND_TYPE_MP41 : ISOM_BRAND_TYPE_QT;
606 param->minor_version = 0;
607 param->brands = NULL;
608 param->brand_count = 0;
612 return ret;
613 #else
614 return (int64_t)LSMASH_ERR_NAMELESS;
615 #endif
618 int lsmash_activate_file
620 lsmash_root_t *root,
621 lsmash_file_t *file
624 if( !root || !file || file->root != root )
625 return LSMASH_ERR_FUNCTION_PARAM;
626 root->file = file;
627 return 0;
630 int lsmash_switch_media_segment
632 lsmash_root_t *root,
633 lsmash_file_t *successor,
634 lsmash_adhoc_remux_t *remux
637 if( !root || !remux )
638 return LSMASH_ERR_FUNCTION_PARAM;
639 lsmash_file_t *predecessor = root->file;
640 if( !predecessor || !successor
641 || predecessor == successor
642 || predecessor->root != successor->root
643 || !predecessor->root || !successor->root
644 || predecessor->root != root || successor->root != root
645 || (successor->flags & LSMASH_FILE_MODE_INITIALIZATION)
646 || !(successor->flags & LSMASH_FILE_MODE_MEDIA)
647 || !(predecessor->flags & LSMASH_FILE_MODE_WRITE) || !(successor->flags & LSMASH_FILE_MODE_WRITE)
648 || !(predecessor->flags & LSMASH_FILE_MODE_BOX) || !(successor->flags & LSMASH_FILE_MODE_BOX)
649 || !(predecessor->flags & LSMASH_FILE_MODE_FRAGMENTED) || !(successor->flags & LSMASH_FILE_MODE_FRAGMENTED)
650 || !(predecessor->flags & LSMASH_FILE_MODE_SEGMENT) || !(successor->flags & LSMASH_FILE_MODE_SEGMENT)
651 || (!(predecessor->flags & LSMASH_FILE_MODE_MEDIA) && !(predecessor->flags & LSMASH_FILE_MODE_INITIALIZATION)) )
652 return LSMASH_ERR_FUNCTION_PARAM;
653 int ret = isom_finish_final_fragment_movie( predecessor, remux );
654 if( ret < 0 )
655 return ret;
656 if( predecessor->flags & LSMASH_FILE_MODE_INITIALIZATION )
658 if( predecessor->initializer != predecessor )
659 return LSMASH_ERR_INVALID_DATA;
660 successor->initializer = predecessor;
662 else
663 successor->initializer = predecessor->initializer;
664 if( !lsmash_get_entry_data( &successor->styp_list, 1 ) )
666 ret = isom_set_brands( successor, 0, 0, NULL, 0 );
667 if( ret < 0 )
668 return LSMASH_ERR_NAMELESS;
670 successor->fragment_count = predecessor->fragment_count;
671 root->file = successor;
672 return 0;