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