bstream: Add lsmash_bs_get_le16() and lsmash_bs_get_le32().
[L-SMASH.git] / core / file.c
blobbd5a926ff1334cba69a80d801dc4fdd729275c63
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>
27 #include "box.h"
28 #include "read.h"
29 #include "fragment.h"
31 static void isom_clear_compat_flags
33 lsmash_file_t *file
36 /* Clear flags for compatibility. */
37 memset( (int8_t *)file + COMPAT_FLAGS_OFFSET, 0, sizeof(lsmash_file_t) - COMPAT_FLAGS_OFFSET );
38 file->min_isom_version = UINT8_MAX; /* undefined value */
41 int isom_check_compatibility
43 lsmash_file_t *file
46 if( !file )
47 return LSMASH_ERR_FUNCTION_PARAM;
48 isom_clear_compat_flags( file );
49 /* Get the brand container. */
50 isom_ftyp_t *ftyp = file->ftyp ? file->ftyp : (isom_ftyp_t *)lsmash_get_entry_data( &file->styp_list, 1 );
51 /* Check brand to decide mandatory boxes. */
52 if( !ftyp )
54 /* No brand declaration means this file is a MP4 version 1 or QuickTime file format. */
55 if( file->moov
56 && file->moov->iods )
58 file->mp4_version1 = 1;
59 file->isom_compatible = 1;
61 else
63 file->qt_compatible = 1;
64 file->undefined_64_ver = 1;
66 return 0;
68 for( uint32_t i = 0; i <= ftyp->brand_count; i++ )
70 uint32_t brand = (i == ftyp->brand_count ? ftyp->major_brand : ftyp->compatible_brands[i]);
71 switch( brand )
73 case ISOM_BRAND_TYPE_QT :
74 file->qt_compatible = 1;
75 break;
76 case ISOM_BRAND_TYPE_MP41 :
77 file->mp4_version1 = 1;
78 break;
79 case ISOM_BRAND_TYPE_MP42 :
80 file->mp4_version2 = 1;
81 break;
82 case ISOM_BRAND_TYPE_AVC1 :
83 case ISOM_BRAND_TYPE_ISOM :
84 file->max_isom_version = LSMASH_MAX( file->max_isom_version, 1 );
85 file->min_isom_version = LSMASH_MIN( file->min_isom_version, 1 );
86 break;
87 case ISOM_BRAND_TYPE_ISO2 :
88 file->max_isom_version = LSMASH_MAX( file->max_isom_version, 2 );
89 file->min_isom_version = LSMASH_MIN( file->min_isom_version, 2 );
90 break;
91 case ISOM_BRAND_TYPE_ISO3 :
92 file->max_isom_version = LSMASH_MAX( file->max_isom_version, 3 );
93 file->min_isom_version = LSMASH_MIN( file->min_isom_version, 3 );
94 break;
95 case ISOM_BRAND_TYPE_ISO4 :
96 file->max_isom_version = LSMASH_MAX( file->max_isom_version, 4 );
97 file->min_isom_version = LSMASH_MIN( file->min_isom_version, 4 );
98 break;
99 case ISOM_BRAND_TYPE_ISO5 :
100 file->max_isom_version = LSMASH_MAX( file->max_isom_version, 5 );
101 file->min_isom_version = LSMASH_MIN( file->min_isom_version, 5 );
102 break;
103 case ISOM_BRAND_TYPE_ISO6 :
104 file->max_isom_version = LSMASH_MAX( file->max_isom_version, 6 );
105 file->min_isom_version = LSMASH_MIN( file->min_isom_version, 6 );
106 break;
107 case ISOM_BRAND_TYPE_ISO7 :
108 file->max_isom_version = LSMASH_MAX( file->max_isom_version, 7 );
109 file->min_isom_version = LSMASH_MIN( file->min_isom_version, 7 );
110 break;
111 case ISOM_BRAND_TYPE_M4A :
112 case ISOM_BRAND_TYPE_M4B :
113 case ISOM_BRAND_TYPE_M4P :
114 case ISOM_BRAND_TYPE_M4V :
115 file->itunes_movie = 1;
116 break;
117 case ISOM_BRAND_TYPE_3GP4 :
118 file->max_3gpp_version = LSMASH_MAX( file->max_3gpp_version, 4 );
119 break;
120 case ISOM_BRAND_TYPE_3GP5 :
121 file->max_3gpp_version = LSMASH_MAX( file->max_3gpp_version, 5 );
122 break;
123 case ISOM_BRAND_TYPE_3GE6 :
124 case ISOM_BRAND_TYPE_3GG6 :
125 case ISOM_BRAND_TYPE_3GP6 :
126 case ISOM_BRAND_TYPE_3GR6 :
127 case ISOM_BRAND_TYPE_3GS6 :
128 file->max_3gpp_version = LSMASH_MAX( file->max_3gpp_version, 6 );
129 break;
130 case ISOM_BRAND_TYPE_3GP7 :
131 file->max_3gpp_version = LSMASH_MAX( file->max_3gpp_version, 7 );
132 break;
133 case ISOM_BRAND_TYPE_3GP8 :
134 file->max_3gpp_version = LSMASH_MAX( file->max_3gpp_version, 8 );
135 break;
136 case ISOM_BRAND_TYPE_3GE9 :
137 case ISOM_BRAND_TYPE_3GF9 :
138 case ISOM_BRAND_TYPE_3GG9 :
139 case ISOM_BRAND_TYPE_3GH9 :
140 case ISOM_BRAND_TYPE_3GM9 :
141 case ISOM_BRAND_TYPE_3GP9 :
142 case ISOM_BRAND_TYPE_3GR9 :
143 case ISOM_BRAND_TYPE_3GS9 :
144 case ISOM_BRAND_TYPE_3GT9 :
145 file->max_3gpp_version = LSMASH_MAX( file->max_3gpp_version, 9 );
146 break;
147 default :
148 break;
150 switch( brand )
152 case ISOM_BRAND_TYPE_AVC1 :
153 case ISOM_BRAND_TYPE_ISO2 :
154 case ISOM_BRAND_TYPE_ISO3 :
155 case ISOM_BRAND_TYPE_ISO4 :
156 case ISOM_BRAND_TYPE_ISO5 :
157 case ISOM_BRAND_TYPE_ISO6 :
158 file->avc_extensions = 1;
159 break;
160 case ISOM_BRAND_TYPE_3GP4 :
161 case ISOM_BRAND_TYPE_3GP5 :
162 case ISOM_BRAND_TYPE_3GP6 :
163 case ISOM_BRAND_TYPE_3GP7 :
164 case ISOM_BRAND_TYPE_3GP8 :
165 case ISOM_BRAND_TYPE_3GP9 :
166 file->forbid_tref = 1;
167 break;
168 case ISOM_BRAND_TYPE_3GH9 :
169 case ISOM_BRAND_TYPE_3GM9 :
170 case ISOM_BRAND_TYPE_DASH :
171 case ISOM_BRAND_TYPE_DSMS :
172 case ISOM_BRAND_TYPE_LMSG :
173 case ISOM_BRAND_TYPE_MSDH :
174 case ISOM_BRAND_TYPE_MSIX :
175 case ISOM_BRAND_TYPE_SIMS :
176 file->media_segment = 1;
177 break;
178 default :
179 break;
182 file->isom_compatible = !file->qt_compatible
183 || file->mp4_version1
184 || file->mp4_version2
185 || file->itunes_movie
186 || file->max_3gpp_version;
187 file->undefined_64_ver = file->qt_compatible || file->itunes_movie;
188 if( file->flags & LSMASH_FILE_MODE_WRITE )
190 /* Media Segment is incompatible with ISO Base Media File Format version 4 or former must be compatible with
191 * version 6 or later since it requires default-base-is-moof and Track Fragment Base Media Decode Time Box. */
192 if( file->media_segment && (file->min_isom_version < 5 || (file->max_isom_version && file->max_isom_version < 6)) )
193 return LSMASH_ERR_INVALID_DATA;
194 file->allow_moof_base = (file->max_isom_version >= 5 && file->min_isom_version >= 5)
195 || (file->max_isom_version == 0 && file->min_isom_version == UINT8_MAX && file->media_segment);
197 return 0;
200 int isom_check_mandatory_boxes
202 lsmash_file_t *file
205 if( !file
206 || !file->moov
207 || !file->moov->mvhd )
208 return LSMASH_ERR_INVALID_DATA;
209 /* A movie requires at least one track. */
210 if( !file->moov->trak_list.head )
211 return LSMASH_ERR_INVALID_DATA;
212 for( lsmash_entry_t *entry = file->moov->trak_list.head; entry; entry = entry->next )
214 isom_trak_t *trak = (isom_trak_t *)entry->data;
215 if( !trak
216 || !trak->tkhd
217 || !trak->mdia
218 || !trak->mdia->mdhd
219 || !trak->mdia->hdlr
220 || !trak->mdia->minf
221 || !trak->mdia->minf->dinf
222 || !trak->mdia->minf->dinf->dref
223 || !trak->mdia->minf->stbl
224 || !trak->mdia->minf->stbl->stsd
225 || !trak->mdia->minf->stbl->stsz
226 || !trak->mdia->minf->stbl->stts
227 || !trak->mdia->minf->stbl->stsc
228 || !trak->mdia->minf->stbl->stco )
229 return LSMASH_ERR_INVALID_DATA;
230 if( file->qt_compatible && !trak->mdia->minf->hdlr )
231 return LSMASH_ERR_INVALID_DATA;
232 isom_stbl_t *stbl = trak->mdia->minf->stbl;
233 if( !stbl->stsd->list.head )
234 return LSMASH_ERR_INVALID_DATA;
235 if( !file->fragment
236 && (!stbl->stsd->list.head
237 || !stbl->stts->list || !stbl->stts->list->head
238 || !stbl->stsc->list || !stbl->stsc->list->head
239 || !stbl->stco->list || !stbl->stco->list->head) )
240 return LSMASH_ERR_INVALID_DATA;
242 if( !file->fragment )
243 return 0;
244 if( !file->moov->mvex )
245 return LSMASH_ERR_INVALID_DATA;
246 for( lsmash_entry_t *entry = file->moov->mvex->trex_list.head; entry; entry = entry->next )
247 if( !entry->data ) /* trex */
248 return LSMASH_ERR_INVALID_DATA;
249 return 0;
252 int isom_rearrange_data
254 lsmash_file_t *file,
255 lsmash_adhoc_remux_t *remux,
256 uint8_t *buf[2],
257 size_t read_num,
258 size_t size,
259 uint64_t read_pos,
260 uint64_t write_pos,
261 uint64_t file_size
264 assert( remux );
265 /* Copy-pastan */
266 int buf_switch = 1;
267 lsmash_bs_t *bs = file->bs;
268 int ret;
269 int64_t ret64;
270 while( read_num == size )
272 ret64 = lsmash_bs_write_seek( bs, read_pos, SEEK_SET );
273 if( ret64 < 0 )
274 return ret64;
275 ret = lsmash_bs_read_data( bs, buf[buf_switch], &read_num );
276 if( ret < 0 )
277 return ret;
278 read_pos = bs->offset;
279 buf_switch ^= 0x1;
280 ret64 = lsmash_bs_write_seek( bs, write_pos, SEEK_SET );
281 if( ret64 < 0 )
282 return ret64;
283 ret = lsmash_bs_write_data( bs, buf[buf_switch], size );
284 if( ret < 0 )
285 return ret;
286 write_pos = bs->offset;
287 if( remux->func )
288 remux->func( remux->param, write_pos, file_size ); // FIXME:
290 ret = lsmash_bs_write_data( bs, buf[buf_switch ^ 0x1], read_num );
291 if( ret < 0 )
292 return ret;
293 if( remux->func )
294 remux->func( remux->param, file_size, file_size ); // FIXME:
295 return 0;
298 static int isom_set_brands
300 lsmash_file_t *file,
301 lsmash_brand_type major_brand,
302 uint32_t minor_version,
303 lsmash_brand_type *brands,
304 uint32_t brand_count
307 if( brand_count > 50 )
308 return LSMASH_ERR_FUNCTION_PARAM; /* We support setting brands up to 50. */
309 if( major_brand == 0 || brand_count == 0 )
311 if( file->flags & LSMASH_FILE_MODE_INITIALIZATION )
313 /* Absence of File Type Box means this file is a QuickTime or MP4 version 1 format file. */
314 isom_remove_box_by_itself( file->ftyp );
315 /* Anyway we use QTFF as a default file format. */
316 isom_clear_compat_flags( file );
317 file->qt_compatible = 1;
319 else
321 /* The absence of the Segment Type Box is allowed.
322 * We set brands from the initialization segment after switching to this segment. */
323 for( lsmash_entry_t *entry = file->styp_list.head; entry; entry = entry->next )
324 isom_remove_box_by_itself( entry->data );
325 if( file->initializer )
327 /* Copy flags for compatibility. */
328 memcpy( (int8_t *)file + COMPAT_FLAGS_OFFSET, file->initializer, sizeof(lsmash_file_t) - COMPAT_FLAGS_OFFSET );
329 file->isom_compatible = 1;
330 file->allow_moof_base = 1;
331 file->media_segment = 1;
332 if( file->min_isom_version < 5 )
333 file->min_isom_version = 5;
334 if( file->max_isom_version < 6 )
335 file->max_isom_version = 6;
338 return 0;
340 isom_ftyp_t *ftyp;
341 if( file->flags & LSMASH_FILE_MODE_INITIALIZATION )
343 /* Add File Type Box if absent yet. */
344 if( !file->ftyp && !isom_add_ftyp( file ) )
345 return LSMASH_ERR_NAMELESS;
346 ftyp = file->ftyp;
348 else
350 /* Add Segment Type Box if absent yet. */
351 ftyp = file->styp_list.head && file->styp_list.head->data
352 ? (isom_styp_t *)file->styp_list.head->data
353 : isom_add_styp( file );
354 if( !ftyp )
355 return LSMASH_ERR_NAMELESS;
357 /* Allocate an array of compatible brands.
358 * ISO/IEC 14496-12 doesn't forbid the absence of brands in the compatible brand list.
359 * For a reason of safety, however, we set at least one brand in the list. */
360 size_t alloc_size = (brand_count ? brand_count : 1) * sizeof(uint32_t);
361 lsmash_brand_type *compatible_brands;
362 if( !file->compatible_brands )
363 compatible_brands = lsmash_malloc( alloc_size );
364 else
365 compatible_brands = lsmash_realloc( file->compatible_brands, alloc_size );
366 if( !compatible_brands )
367 return LSMASH_ERR_MEMORY_ALLOC;
368 /* Set compatible brands. */
369 if( brand_count )
370 for( uint32_t i = 0; i < brand_count; i++ )
371 compatible_brands[i] = brands[i];
372 else
374 /* At least one compatible brand. */
375 compatible_brands[0] = major_brand;
376 brand_count = 1;
378 file->compatible_brands = compatible_brands;
379 /* Duplicate an array of compatible brands. */
380 lsmash_free( ftyp->compatible_brands );
381 ftyp->compatible_brands = lsmash_memdup( compatible_brands, alloc_size );
382 if( !ftyp->compatible_brands )
384 lsmash_freep( &file->compatible_brands );
385 return LSMASH_ERR_MEMORY_ALLOC;
387 ftyp->size = ISOM_BASEBOX_COMMON_SIZE + 8 + brand_count * 4;
388 ftyp->major_brand = major_brand;
389 ftyp->minor_version = minor_version;
390 ftyp->brand_count = brand_count;
391 file->brand_count = brand_count;
392 return isom_check_compatibility( file );
395 /*******************************
396 public interfaces
397 *******************************/
399 void lsmash_discard_boxes
401 lsmash_root_t *root
404 if( !root || !root->file )
405 return;
406 isom_remove_all_extension_boxes( &root->file->extensions );
409 int lsmash_open_file
411 const char *filename,
412 int open_mode,
413 lsmash_file_parameters_t *param
416 if( !filename || !param )
417 return LSMASH_ERR_FUNCTION_PARAM;
418 char mode[4] = { 0 };
419 lsmash_file_mode file_mode = 0;
420 if( open_mode == 0 )
422 memcpy( mode, "w+b", 4 );
423 file_mode = LSMASH_FILE_MODE_WRITE
424 | LSMASH_FILE_MODE_BOX
425 | LSMASH_FILE_MODE_INITIALIZATION
426 | LSMASH_FILE_MODE_MEDIA;
428 #ifdef LSMASH_DEMUXER_ENABLED
429 else if( open_mode == 1 )
431 memcpy( mode, "rb", 3 );
432 file_mode = LSMASH_FILE_MODE_READ;
434 #endif
435 if( file_mode == 0 )
436 return LSMASH_ERR_FUNCTION_PARAM;
437 FILE *stream = NULL;
438 int seekable = 1;
439 if( !strcmp( filename, "-" ) )
441 if( file_mode & LSMASH_FILE_MODE_READ )
443 stream = stdin;
444 seekable = 0;
446 else if( file_mode & LSMASH_FILE_MODE_WRITE )
448 stream = stdout;
449 seekable = 0;
450 file_mode |= LSMASH_FILE_MODE_FRAGMENTED;
453 else
454 stream = lsmash_fopen( filename, mode );
455 if( !stream )
456 return LSMASH_ERR_NAMELESS;
457 memset( param, 0, sizeof(lsmash_file_parameters_t) );
458 param->mode = file_mode;
459 param->opaque = (void *)stream;
460 param->read = lsmash_fread_wrapper;
461 param->write = lsmash_fwrite_wrapper;
462 param->seek = seekable ? lsmash_fseek_wrapper : NULL;
463 param->major_brand = 0;
464 param->brands = NULL;
465 param->brand_count = 0;
466 param->minor_version = 0;
467 param->max_chunk_duration = 0.5;
468 param->max_async_tolerance = 2.0;
469 param->max_chunk_size = 4 * 1024 * 1024;
470 param->max_read_size = 4 * 1024 * 1024;
471 return 0;
474 int lsmash_close_file
476 lsmash_file_parameters_t *param
479 if( !param )
480 return LSMASH_ERR_NAMELESS;
481 if( !param->opaque )
482 return 0;
483 int ret = fclose( (FILE *)param->opaque );
484 param->opaque = NULL;
485 return ret == 0 ? 0 : LSMASH_ERR_UNKNOWN;
488 lsmash_file_t *lsmash_set_file
490 lsmash_root_t *root,
491 lsmash_file_parameters_t *param
494 if( !root || !param )
495 return NULL;
496 lsmash_file_t *file = isom_add_file( root );
497 if( !file )
498 return NULL;
499 lsmash_bs_t *bs = lsmash_bs_create();
500 if( !bs )
501 goto fail;
502 file->bs = bs;
503 file->flags = param->mode;
504 file->bs->stream = param->opaque;
505 file->bs->read = param->read;
506 file->bs->write = param->write;
507 file->bs->seek = param->seek;
508 file->bs->unseekable = (param->seek == NULL);
509 file->bs->buffer.max_size = param->max_read_size;
510 file->max_chunk_duration = param->max_chunk_duration;
511 file->max_async_tolerance = LSMASH_MAX( param->max_async_tolerance, 2 * param->max_chunk_duration );
512 file->max_chunk_size = param->max_chunk_size;
513 if( (file->flags & LSMASH_FILE_MODE_WRITE)
514 && (file->flags & LSMASH_FILE_MODE_BOX) )
516 /* Construction of Segment Index Box requires seekability at our current implementation.
517 * If segment is not so large, data rearrangement can be avoided by buffering i.e. the
518 * seekability is not essential, but at present we don't support buffering of all materials
519 * within segment. */
520 if( (file->flags & LSMASH_FILE_MODE_INDEX) && file->bs->unseekable )
521 goto fail;
522 /* Establish the fragment handler if required. */
523 if( file->flags & LSMASH_FILE_MODE_FRAGMENTED )
525 file->fragment = lsmash_malloc_zero( sizeof(isom_fragment_manager_t) );
526 if( !file->fragment )
527 goto fail;
528 file->fragment->first_moof_pos = FIRST_MOOF_POS_UNDETERMINED;
529 file->fragment->pool = lsmash_create_entry_list();
530 if( !file->fragment->pool )
531 goto fail;
533 else if( file->bs->unseekable )
534 /* For unseekable output operations, LSMASH_FILE_MODE_FRAGMENTED shall be set. */
535 goto fail;
536 /* Establish file types. */
537 if( isom_set_brands( file, param->major_brand,
538 param->minor_version,
539 param->brands, param->brand_count ) < 0 )
540 goto fail;
541 /* Create the movie header if the initialization of the streams is required. */
542 if( file->flags & LSMASH_FILE_MODE_INITIALIZATION )
544 if( !isom_add_moov( file )
545 || !isom_add_mvhd( file->moov ) )
546 goto fail;
547 /* Default Movie Header Box. */
548 isom_mvhd_t *mvhd = file->moov->mvhd;
549 mvhd->rate = 0x00010000;
550 mvhd->volume = 0x0100;
551 mvhd->matrix[0] = 0x00010000;
552 mvhd->matrix[4] = 0x00010000;
553 mvhd->matrix[8] = 0x40000000;
554 mvhd->next_track_ID = 1;
555 file->initializer = file;
558 if( !root->file )
559 root->file = file;
560 return file;
561 fail:
562 isom_remove_box_by_itself( file );
563 return NULL;
566 int64_t lsmash_read_file
568 lsmash_file_t *file,
569 lsmash_file_parameters_t *param
572 #ifdef LSMASH_DEMUXER_ENABLED
573 if( !file )
574 return (int64_t)LSMASH_ERR_FUNCTION_PARAM;
575 if( !file->bs )
576 return (int64_t)LSMASH_ERR_NAMELESS;
577 int64_t ret = LSMASH_ERR_NAMELESS;
578 if( file->flags & (LSMASH_FILE_MODE_READ | LSMASH_FILE_MODE_DUMP) )
580 /* Get the file size if seekable when reading. */
581 if( !file->bs->unseekable )
583 ret = lsmash_bs_read_seek( file->bs, 0, SEEK_END );
584 if( ret < 0 )
585 return ret;
586 file->bs->written = ret;
587 lsmash_bs_read_seek( file->bs, 0, SEEK_SET );
589 else
590 ret = 0;
591 /* Read whole boxes. */
592 ret = isom_read_file( file );
593 if( ret < 0 )
594 return ret;
595 if( param )
597 if( file->ftyp )
599 /* file types */
600 isom_ftyp_t *ftyp = file->ftyp;
601 param->major_brand = ftyp->major_brand ? ftyp->major_brand : ISOM_BRAND_TYPE_QT;
602 param->minor_version = ftyp->minor_version;
603 param->brands = file->compatible_brands;
604 param->brand_count = file->brand_count;
606 else if( file->styp_list.head && file->styp_list.head->data )
608 /* segment types */
609 isom_styp_t *styp = (isom_styp_t *)file->styp_list.head->data;
610 param->major_brand = styp->major_brand ? styp->major_brand : ISOM_BRAND_TYPE_QT;
611 param->minor_version = styp->minor_version;
612 param->brands = file->compatible_brands;
613 param->brand_count = file->brand_count;
615 else
617 param->major_brand = file->mp4_version1 ? ISOM_BRAND_TYPE_MP41 : ISOM_BRAND_TYPE_QT;
618 param->minor_version = 0;
619 param->brands = NULL;
620 param->brand_count = 0;
624 return ret;
625 #else
626 return (int64_t)LSMASH_ERR_NAMELESS;
627 #endif
630 int lsmash_activate_file
632 lsmash_root_t *root,
633 lsmash_file_t *file
636 if( !root || !file || file->root != root )
637 return LSMASH_ERR_FUNCTION_PARAM;
638 root->file = file;
639 return 0;
642 int lsmash_switch_media_segment
644 lsmash_root_t *root,
645 lsmash_file_t *successor,
646 lsmash_adhoc_remux_t *remux
649 if( !root || !remux )
650 return LSMASH_ERR_FUNCTION_PARAM;
651 lsmash_file_t *predecessor = root->file;
652 if( !predecessor || !successor
653 || predecessor == successor
654 || predecessor->root != successor->root
655 || !predecessor->root || !successor->root
656 || predecessor->root != root || successor->root != root
657 || (successor->flags & LSMASH_FILE_MODE_INITIALIZATION)
658 || !(successor->flags & LSMASH_FILE_MODE_MEDIA)
659 || !(predecessor->flags & LSMASH_FILE_MODE_WRITE) || !(successor->flags & LSMASH_FILE_MODE_WRITE)
660 || !(predecessor->flags & LSMASH_FILE_MODE_BOX) || !(successor->flags & LSMASH_FILE_MODE_BOX)
661 || !(predecessor->flags & LSMASH_FILE_MODE_FRAGMENTED) || !(successor->flags & LSMASH_FILE_MODE_FRAGMENTED)
662 || !(predecessor->flags & LSMASH_FILE_MODE_SEGMENT) || !(successor->flags & LSMASH_FILE_MODE_SEGMENT)
663 || (!(predecessor->flags & LSMASH_FILE_MODE_MEDIA) && !(predecessor->flags & LSMASH_FILE_MODE_INITIALIZATION)) )
664 return LSMASH_ERR_FUNCTION_PARAM;
665 int ret = isom_finish_final_fragment_movie( predecessor, remux );
666 if( ret < 0 )
667 return ret;
668 if( predecessor->flags & LSMASH_FILE_MODE_INITIALIZATION )
670 if( predecessor->initializer != predecessor )
671 return LSMASH_ERR_INVALID_DATA;
672 successor->initializer = predecessor;
674 else
675 successor->initializer = predecessor->initializer;
676 if( !lsmash_get_entry_data( &successor->styp_list, 1 ) )
678 ret = isom_set_brands( successor, 0, 0, NULL, 0 );
679 if( ret < 0 )
680 return LSMASH_ERR_NAMELESS;
682 successor->fragment_count = predecessor->fragment_count;
683 root->file = successor;
684 return 0;