1 /*****************************************************************************
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 */
37 #include "importer/importer.h"
39 static void isom_clear_compat_flags
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
54 if( LSMASH_IS_NON_EXISTING_BOX( file
) )
55 return LSMASH_ERR_FUNCTION_PARAM
;
56 isom_clear_compat_flags( file
);
57 /* Get the brand container. */
58 isom_ftyp_t
*ftyp
= LSMASH_IS_EXISTING_BOX( file
->ftyp
)
60 : (isom_ftyp_t
*)lsmash_get_entry_data( &file
->styp_list
, 1 );
61 /* Check brand to decide mandatory boxes. */
62 if( LSMASH_IS_NON_EXISTING_BOX( ftyp
) )
64 /* No brand declaration means this file is a MP4 version 1 or QuickTime file format. */
65 if( LSMASH_IS_EXISTING_BOX( file
->moov
->iods
) )
67 file
->mp4_version1
= 1;
68 file
->isom_compatible
= 1;
72 file
->qt_compatible
= 1;
73 file
->undefined_64_ver
= 1;
77 for( uint32_t i
= 0; i
<= ftyp
->brand_count
; i
++ )
79 uint32_t brand
= (i
== ftyp
->brand_count
? ftyp
->major_brand
: ftyp
->compatible_brands
[i
]);
82 case ISOM_BRAND_TYPE_QT
:
83 file
->qt_compatible
= 1;
85 case ISOM_BRAND_TYPE_MP41
:
86 file
->mp4_version1
= 1;
88 case ISOM_BRAND_TYPE_MP42
:
89 file
->mp4_version2
= 1;
91 case ISOM_BRAND_TYPE_AVC1
:
92 case ISOM_BRAND_TYPE_ISOM
:
93 file
->max_isom_version
= LSMASH_MAX( file
->max_isom_version
, 1 );
94 file
->min_isom_version
= LSMASH_MIN( file
->min_isom_version
, 1 );
96 case ISOM_BRAND_TYPE_ISO2
:
97 file
->max_isom_version
= LSMASH_MAX( file
->max_isom_version
, 2 );
98 file
->min_isom_version
= LSMASH_MIN( file
->min_isom_version
, 2 );
100 case ISOM_BRAND_TYPE_ISO3
:
101 file
->max_isom_version
= LSMASH_MAX( file
->max_isom_version
, 3 );
102 file
->min_isom_version
= LSMASH_MIN( file
->min_isom_version
, 3 );
104 case ISOM_BRAND_TYPE_ISO4
:
105 file
->max_isom_version
= LSMASH_MAX( file
->max_isom_version
, 4 );
106 file
->min_isom_version
= LSMASH_MIN( file
->min_isom_version
, 4 );
108 case ISOM_BRAND_TYPE_ISO5
:
109 file
->max_isom_version
= LSMASH_MAX( file
->max_isom_version
, 5 );
110 file
->min_isom_version
= LSMASH_MIN( file
->min_isom_version
, 5 );
112 case ISOM_BRAND_TYPE_ISO6
:
113 file
->max_isom_version
= LSMASH_MAX( file
->max_isom_version
, 6 );
114 file
->min_isom_version
= LSMASH_MIN( file
->min_isom_version
, 6 );
116 case ISOM_BRAND_TYPE_ISO7
:
117 file
->max_isom_version
= LSMASH_MAX( file
->max_isom_version
, 7 );
118 file
->min_isom_version
= LSMASH_MIN( file
->min_isom_version
, 7 );
120 case ISOM_BRAND_TYPE_M4A
:
121 case ISOM_BRAND_TYPE_M4B
:
122 case ISOM_BRAND_TYPE_M4P
:
123 case ISOM_BRAND_TYPE_M4V
:
124 file
->itunes_movie
= 1;
126 case ISOM_BRAND_TYPE_3GP4
:
127 file
->max_3gpp_version
= LSMASH_MAX( file
->max_3gpp_version
, 4 );
129 case ISOM_BRAND_TYPE_3GP5
:
130 file
->max_3gpp_version
= LSMASH_MAX( file
->max_3gpp_version
, 5 );
132 case ISOM_BRAND_TYPE_3GE6
:
133 case ISOM_BRAND_TYPE_3GG6
:
134 case ISOM_BRAND_TYPE_3GP6
:
135 case ISOM_BRAND_TYPE_3GR6
:
136 case ISOM_BRAND_TYPE_3GS6
:
137 file
->max_3gpp_version
= LSMASH_MAX( file
->max_3gpp_version
, 6 );
139 case ISOM_BRAND_TYPE_3GP7
:
140 file
->max_3gpp_version
= LSMASH_MAX( file
->max_3gpp_version
, 7 );
142 case ISOM_BRAND_TYPE_3GP8
:
143 file
->max_3gpp_version
= LSMASH_MAX( file
->max_3gpp_version
, 8 );
145 case ISOM_BRAND_TYPE_3GE9
:
146 case ISOM_BRAND_TYPE_3GF9
:
147 case ISOM_BRAND_TYPE_3GG9
:
148 case ISOM_BRAND_TYPE_3GH9
:
149 case ISOM_BRAND_TYPE_3GM9
:
150 case ISOM_BRAND_TYPE_3GP9
:
151 case ISOM_BRAND_TYPE_3GR9
:
152 case ISOM_BRAND_TYPE_3GS9
:
153 case ISOM_BRAND_TYPE_3GT9
:
154 file
->max_3gpp_version
= LSMASH_MAX( file
->max_3gpp_version
, 9 );
161 case ISOM_BRAND_TYPE_AVC1
:
162 case ISOM_BRAND_TYPE_ISO2
:
163 case ISOM_BRAND_TYPE_ISO3
:
164 case ISOM_BRAND_TYPE_ISO4
:
165 case ISOM_BRAND_TYPE_ISO5
:
166 case ISOM_BRAND_TYPE_ISO6
:
167 file
->avc_extensions
= 1;
169 case ISOM_BRAND_TYPE_3GP4
:
170 case ISOM_BRAND_TYPE_3GP5
:
171 case ISOM_BRAND_TYPE_3GP6
:
172 case ISOM_BRAND_TYPE_3GP7
:
173 case ISOM_BRAND_TYPE_3GP8
:
174 case ISOM_BRAND_TYPE_3GP9
:
175 file
->forbid_tref
= 1;
177 case ISOM_BRAND_TYPE_3GH9
:
178 case ISOM_BRAND_TYPE_3GM9
:
179 case ISOM_BRAND_TYPE_DASH
:
180 case ISOM_BRAND_TYPE_DSMS
:
181 case ISOM_BRAND_TYPE_LMSG
:
182 case ISOM_BRAND_TYPE_MSDH
:
183 case ISOM_BRAND_TYPE_MSIX
:
184 case ISOM_BRAND_TYPE_SIMS
:
185 file
->media_segment
= 1;
191 file
->isom_compatible
= !file
->qt_compatible
192 || file
->mp4_version1
193 || file
->mp4_version2
194 || file
->itunes_movie
195 || file
->max_3gpp_version
;
196 file
->undefined_64_ver
= file
->qt_compatible
|| file
->itunes_movie
;
197 if( file
->flags
& LSMASH_FILE_MODE_WRITE
)
199 /* Media Segment is incompatible with ISO Base Media File Format version 4 or former must be compatible with
200 * version 6 or later since it requires default-base-is-moof and Track Fragment Base Media Decode Time Box. */
201 if( file
->media_segment
&& (file
->min_isom_version
< 5 || (file
->max_isom_version
&& file
->max_isom_version
< 6)) )
202 return LSMASH_ERR_INVALID_DATA
;
203 file
->allow_moof_base
= (file
->max_isom_version
>= 5 && file
->min_isom_version
>= 5)
204 || (file
->max_isom_version
== 0 && file
->min_isom_version
== UINT8_MAX
&& file
->media_segment
);
209 int isom_check_mandatory_boxes
214 assert( LSMASH_IS_EXISTING_BOX( file
) );
215 /* A movie requires at least one track. */
216 if( !file
->moov
->trak_list
.head
)
217 return LSMASH_ERR_INVALID_DATA
;
218 for( lsmash_entry_t
*entry
= file
->moov
->trak_list
.head
; entry
; entry
= entry
->next
)
220 isom_trak_t
*trak
= (isom_trak_t
*)entry
->data
;
221 if( LSMASH_IS_NON_EXISTING_BOX( trak
)
222 || LSMASH_IS_NON_EXISTING_BOX( trak
->tkhd
)
223 || LSMASH_IS_NON_EXISTING_BOX( trak
->mdia
->mdhd
)
224 || LSMASH_IS_NON_EXISTING_BOX( trak
->mdia
->hdlr
)
225 || LSMASH_IS_NON_EXISTING_BOX( trak
->mdia
->minf
->dinf
->dref
)
226 || LSMASH_IS_NON_EXISTING_BOX( trak
->mdia
->minf
->stbl
->stsd
)
227 || (LSMASH_IS_NON_EXISTING_BOX( trak
->mdia
->minf
->stbl
->stsz
)
228 && LSMASH_IS_NON_EXISTING_BOX( trak
->mdia
->minf
->stbl
->stz2
))
229 || LSMASH_IS_NON_EXISTING_BOX( trak
->mdia
->minf
->stbl
->stts
)
230 || LSMASH_IS_NON_EXISTING_BOX( trak
->mdia
->minf
->stbl
->stsc
)
231 || LSMASH_IS_NON_EXISTING_BOX( trak
->mdia
->minf
->stbl
->stco
) )
232 return LSMASH_ERR_INVALID_DATA
;
233 if( file
->qt_compatible
&& LSMASH_IS_NON_EXISTING_BOX( 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
;
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
)
247 if( LSMASH_IS_NON_EXISTING_BOX( 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( LSMASH_IS_NON_EXISTING_BOX( (isom_trex_t
*)entry
->data
) )
251 return LSMASH_ERR_INVALID_DATA
;
255 int isom_rearrange_data
258 lsmash_adhoc_remux_t
*remux
,
270 lsmash_bs_t
*bs
= file
->bs
;
273 while( read_num
== size
)
275 ret64
= lsmash_bs_write_seek( bs
, read_pos
, SEEK_SET
);
278 ret
= lsmash_bs_read_data( bs
, buf
[buf_switch
], &read_num
);
281 read_pos
= bs
->offset
;
283 ret64
= lsmash_bs_write_seek( bs
, write_pos
, SEEK_SET
);
286 ret
= lsmash_bs_write_data( bs
, buf
[buf_switch
], size
);
289 write_pos
= bs
->offset
;
291 remux
->func( remux
->param
, write_pos
, file_size
); // FIXME:
293 ret
= lsmash_bs_write_data( bs
, buf
[buf_switch
^ 0x1], read_num
);
297 remux
->func( remux
->param
, file_size
, file_size
); // FIXME:
301 static int isom_set_brands
304 lsmash_brand_type major_brand
,
305 uint32_t minor_version
,
306 lsmash_brand_type
*brands
,
310 if( brand_count
> 50 )
311 return LSMASH_ERR_FUNCTION_PARAM
; /* We support setting brands up to 50. */
312 if( major_brand
== 0 && (!brands
|| brand_count
== 0 || brands
[0] == 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;
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( LSMASH_IS_EXISTING_BOX( 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;
343 else if( major_brand
== 0 )
345 major_brand
= brands
[0];
346 lsmash_log( NULL
, LSMASH_LOG_WARNING
,
347 "major_brand is not specified. Use the first brand in the compatible brand list as major_brand.\n" );
352 if( file
->flags
& LSMASH_FILE_MODE_INITIALIZATION
)
354 /* Add File Type Box if absent yet. */
355 if( LSMASH_IS_NON_EXISTING_BOX( file
->ftyp
) && LSMASH_IS_BOX_ADDITION_FAILURE( isom_add_ftyp( file
) ) )
356 return LSMASH_ERR_NAMELESS
;
361 /* Add Segment Type Box if absent yet. */
362 ftyp
= file
->styp_list
.head
&& LSMASH_IS_EXISTING_BOX( (isom_styp_t
*)file
->styp_list
.head
->data
)
363 ? (isom_styp_t
*)file
->styp_list
.head
->data
364 : isom_add_styp( file
);
365 if( LSMASH_IS_NON_EXISTING_BOX( ftyp
) )
366 return LSMASH_ERR_NAMELESS
;
368 /* Allocate an array of compatible brands.
369 * ISO/IEC 14496-12 doesn't forbid the absence of brands in the compatible brand list.
370 * For a reason of safety, however, we set at least one brand in the list. */
371 size_t alloc_size
= (brand_count
? brand_count
: 1) * sizeof(uint32_t);
372 lsmash_brand_type
*compatible_brands
;
373 if( !file
->compatible_brands
)
374 compatible_brands
= lsmash_malloc( alloc_size
);
376 compatible_brands
= lsmash_realloc( file
->compatible_brands
, alloc_size
);
377 if( !compatible_brands
)
378 return LSMASH_ERR_MEMORY_ALLOC
;
379 /* Set compatible brands. */
381 for( uint32_t i
= 0; i
< brand_count
; i
++ )
382 compatible_brands
[i
] = brands
[i
];
385 /* At least one compatible brand. */
386 compatible_brands
[0] = major_brand
;
389 file
->compatible_brands
= compatible_brands
;
390 /* Duplicate an array of compatible brands. */
391 lsmash_free( ftyp
->compatible_brands
);
392 ftyp
->compatible_brands
= lsmash_memdup( compatible_brands
, alloc_size
);
393 if( !ftyp
->compatible_brands
)
395 lsmash_freep( &file
->compatible_brands
);
396 return LSMASH_ERR_MEMORY_ALLOC
;
398 ftyp
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 8 + brand_count
* 4;
399 ftyp
->major_brand
= major_brand
;
400 ftyp
->minor_version
= minor_version
;
401 ftyp
->brand_count
= brand_count
;
402 file
->brand_count
= brand_count
;
403 return isom_check_compatibility( file
);
406 /*---- default I/O ----*/
410 int is_standard_stream
; /* If set to 1, 'file_ptr' points to standard stream (i.e. stdin, stdout or stderr).
411 * This flag prevents from accidentally closing standard streams. */
412 lsmash_file_mode file_mode
;
413 } default_io_stream_t
;
415 static default_io_stream_t
*default_io_stream_open( const char *filename
, int open_mode
)
418 _setmode( _fileno( stdin
), _O_BINARY
);
419 _setmode( _fileno( stdout
), _O_BINARY
);
420 _setmode( _fileno( stderr
), _O_BINARY
);
422 default_io_stream_t
*stream
= (default_io_stream_t
*)lsmash_malloc_zero( sizeof(default_io_stream_t
) );
425 char mode
[4] = { 0 };
428 memcpy( mode
, "w+b", 4 );
429 stream
->file_mode
= LSMASH_FILE_MODE_WRITE
430 | LSMASH_FILE_MODE_BOX
431 | LSMASH_FILE_MODE_INITIALIZATION
432 | LSMASH_FILE_MODE_MEDIA
;
434 else if( open_mode
== 1 )
436 memcpy( mode
, "rb", 3 );
437 stream
->file_mode
= LSMASH_FILE_MODE_READ
;
441 if( !strcmp( filename
, "-" ) )
443 if( stream
->file_mode
& LSMASH_FILE_MODE_READ
)
445 stream
->file_ptr
= stdin
;
446 stream
->is_standard_stream
= 1;
448 else if( stream
->file_mode
& LSMASH_FILE_MODE_WRITE
)
450 stream
->file_ptr
= stdout
;
451 stream
->is_standard_stream
= 1;
452 stream
->file_mode
|= LSMASH_FILE_MODE_FRAGMENTED
;
456 stream
->file_ptr
= lsmash_fopen( filename
, mode
);
457 if( stream
->file_ptr
== NULL
)
458 lsmash_freep( &stream
);
462 static int default_io_stream_close( default_io_stream_t
*stream
)
466 int ret
= stream
->is_standard_stream
? 0 : fclose( stream
->file_ptr
);
467 lsmash_free( stream
);
471 static int default_io_stream_read( void *opaque
, uint8_t *buf
, int size
)
473 int read_size
= fread( buf
, 1, size
, ((default_io_stream_t
*)opaque
)->file_ptr
);
474 return ferror( ((default_io_stream_t
*)opaque
)->file_ptr
) ? LSMASH_ERR_NAMELESS
: read_size
;
477 static int default_io_stream_write( void *opaque
, uint8_t *buf
, int size
)
479 return fwrite( buf
, 1, size
, ((default_io_stream_t
*)opaque
)->file_ptr
);
482 static int64_t default_io_stream_seek( void *opaque
, int64_t offset
, int whence
)
484 if( lsmash_fseek( ((default_io_stream_t
*)opaque
)->file_ptr
, offset
, whence
) != 0 )
485 return LSMASH_ERR_NAMELESS
;
486 return lsmash_ftell( ((default_io_stream_t
*)opaque
)->file_ptr
);
489 /*******************************
491 *******************************/
493 void lsmash_discard_boxes
498 if( LSMASH_IS_NON_EXISTING_BOX( root
)
499 || LSMASH_IS_NON_EXISTING_BOX( root
->file
) )
501 isom_remove_all_extension_boxes( &root
->file
->extensions
);
506 const char *filename
,
508 lsmash_file_parameters_t
*param
511 if( !filename
|| !param
|| (open_mode
!= 0 && open_mode
!= 1) )
512 return LSMASH_ERR_FUNCTION_PARAM
;
513 default_io_stream_t
*stream
= default_io_stream_open( filename
, open_mode
);
515 return LSMASH_ERR_NAMELESS
;
516 memset( param
, 0, sizeof(lsmash_file_parameters_t
) );
517 param
->mode
= stream
->file_mode
;
518 param
->opaque
= (void *)stream
;
519 param
->read
= default_io_stream_read
;
520 param
->write
= default_io_stream_write
;
521 param
->seek
= stream
->is_standard_stream
? NULL
: default_io_stream_seek
;
522 param
->major_brand
= 0;
523 param
->brands
= NULL
;
524 param
->brand_count
= 0;
525 param
->minor_version
= 0;
526 param
->max_chunk_duration
= 0.5;
527 param
->max_async_tolerance
= 2.0;
528 param
->max_chunk_size
= 4 * 1024 * 1024;
529 param
->max_read_size
= 4 * 1024 * 1024;
533 int lsmash_close_file
535 lsmash_file_parameters_t
*param
539 return LSMASH_ERR_NAMELESS
;
540 int ret
= default_io_stream_close( (default_io_stream_t
*)param
->opaque
);
541 param
->opaque
= NULL
;
542 return ret
== 0 ? 0 : LSMASH_ERR_UNKNOWN
;
545 lsmash_file_t
*lsmash_set_file
548 lsmash_file_parameters_t
*param
551 if( LSMASH_IS_NON_EXISTING_BOX( root
) || !param
)
553 lsmash_file_t
*file
= isom_add_file_abstract( root
);
554 if( LSMASH_IS_NON_EXISTING_BOX( file
) )
556 lsmash_bs_t
*bs
= lsmash_bs_create();
560 file
->flags
= param
->mode
;
561 file
->bs
->stream
= param
->opaque
;
562 file
->bs
->read
= param
->read
;
563 file
->bs
->write
= param
->write
;
564 file
->bs
->seek
= param
->seek
;
565 file
->bs
->unseekable
= (param
->seek
== NULL
);
566 file
->bs
->buffer
.max_size
= param
->max_read_size
;
567 file
->max_chunk_duration
= param
->max_chunk_duration
;
568 file
->max_async_tolerance
= LSMASH_MAX( param
->max_async_tolerance
, 2 * param
->max_chunk_duration
);
569 file
->max_chunk_size
= param
->max_chunk_size
;
570 if( (file
->flags
& LSMASH_FILE_MODE_WRITE
)
571 && (file
->flags
& LSMASH_FILE_MODE_BOX
) )
573 /* Construction of Segment Index Box requires seekability at our current implementation.
574 * If segment is not so large, data rearrangement can be avoided by buffering i.e. the
575 * seekability is not essential, but at present we don't support buffering of all materials
577 if( (file
->flags
& LSMASH_FILE_MODE_INDEX
) && file
->bs
->unseekable
)
579 /* Establish the fragment handler if required. */
580 if( file
->flags
& LSMASH_FILE_MODE_FRAGMENTED
)
582 file
->fragment
= lsmash_malloc_zero( sizeof(isom_fragment_manager_t
) );
583 if( !file
->fragment
)
585 file
->fragment
->first_moof_pos
= FIRST_MOOF_POS_UNDETERMINED
;
586 file
->fragment
->pool
= lsmash_create_entry_list();
587 if( !file
->fragment
->pool
)
590 else if( file
->bs
->unseekable
)
591 /* For unseekable output operations, LSMASH_FILE_MODE_FRAGMENTED shall be set. */
593 /* Establish file types. */
594 if( isom_set_brands( file
, param
->major_brand
,
595 param
->minor_version
,
596 param
->brands
, param
->brand_count
) < 0 )
598 /* Create the movie header if the initialization of the streams is required. */
599 if( (file
->flags
& LSMASH_FILE_MODE_INITIALIZATION
) && !isom_movie_create( file
) )
602 if( LSMASH_IS_NON_EXISTING_BOX( root
->file
) )
606 isom_remove_box_by_itself( file
);
610 int64_t lsmash_read_file
613 lsmash_file_parameters_t
*param
616 if( LSMASH_IS_NON_EXISTING_BOX( file
) )
617 return (int64_t)LSMASH_ERR_FUNCTION_PARAM
;
619 return (int64_t)LSMASH_ERR_NAMELESS
;
620 int64_t ret
= LSMASH_ERR_NAMELESS
;
621 if( file
->flags
& (LSMASH_FILE_MODE_READ
| LSMASH_FILE_MODE_DUMP
) )
623 importer_t
*importer
= lsmash_importer_alloc( file
->root
);
625 return (int64_t)LSMASH_ERR_MEMORY_ALLOC
;
626 lsmash_importer_set_file( importer
, file
);
627 ret
= lsmash_importer_find( importer
, "ISOBMFF/QTFF", !file
->bs
->unseekable
);
632 if( LSMASH_IS_EXISTING_BOX( file
->ftyp
) )
635 isom_ftyp_t
*ftyp
= file
->ftyp
;
636 param
->major_brand
= ftyp
->major_brand
? ftyp
->major_brand
: ISOM_BRAND_TYPE_QT
;
637 param
->minor_version
= ftyp
->minor_version
;
638 param
->brands
= file
->compatible_brands
;
639 param
->brand_count
= file
->brand_count
;
641 else if( file
->styp_list
.head
&& LSMASH_IS_EXISTING_BOX( (isom_styp_t
*)file
->styp_list
.head
->data
) )
644 isom_styp_t
*styp
= (isom_styp_t
*)file
->styp_list
.head
->data
;
645 param
->major_brand
= styp
->major_brand
? styp
->major_brand
: ISOM_BRAND_TYPE_QT
;
646 param
->minor_version
= styp
->minor_version
;
647 param
->brands
= file
->compatible_brands
;
648 param
->brand_count
= file
->brand_count
;
652 param
->major_brand
= file
->mp4_version1
? ISOM_BRAND_TYPE_MP41
: ISOM_BRAND_TYPE_QT
;
653 param
->minor_version
= 0;
654 param
->brands
= NULL
;
655 param
->brand_count
= 0;
662 int lsmash_activate_file
668 if( !root
|| !file
|| file
->root
!= root
)
669 return LSMASH_ERR_FUNCTION_PARAM
;
674 int lsmash_switch_media_segment
677 lsmash_file_t
*successor
,
678 lsmash_adhoc_remux_t
*remux
681 if( LSMASH_IS_NON_EXISTING_BOX( root
) || !remux
)
682 return LSMASH_ERR_FUNCTION_PARAM
;
683 lsmash_file_t
*predecessor
= root
->file
;
684 if( LSMASH_IS_NON_EXISTING_BOX( predecessor
) || LSMASH_IS_NON_EXISTING_BOX( successor
)
685 || predecessor
== successor
686 || predecessor
->root
!= successor
->root
687 || LSMASH_IS_NON_EXISTING_BOX( predecessor
->root
) || LSMASH_IS_NON_EXISTING_BOX( successor
->root
)
688 || predecessor
->root
!= root
|| successor
->root
!= root
689 || (successor
->flags
& LSMASH_FILE_MODE_INITIALIZATION
)
690 || !(successor
->flags
& LSMASH_FILE_MODE_MEDIA
)
691 || !(predecessor
->flags
& LSMASH_FILE_MODE_WRITE
) || !(successor
->flags
& LSMASH_FILE_MODE_WRITE
)
692 || !(predecessor
->flags
& LSMASH_FILE_MODE_BOX
) || !(successor
->flags
& LSMASH_FILE_MODE_BOX
)
693 || !(predecessor
->flags
& LSMASH_FILE_MODE_FRAGMENTED
) || !(successor
->flags
& LSMASH_FILE_MODE_FRAGMENTED
)
694 || !(predecessor
->flags
& LSMASH_FILE_MODE_SEGMENT
) || !(successor
->flags
& LSMASH_FILE_MODE_SEGMENT
)
695 || (!(predecessor
->flags
& LSMASH_FILE_MODE_MEDIA
) && !(predecessor
->flags
& LSMASH_FILE_MODE_INITIALIZATION
)) )
696 return LSMASH_ERR_FUNCTION_PARAM
;
697 int ret
= isom_finish_final_fragment_movie( predecessor
, remux
);
700 if( predecessor
->flags
& LSMASH_FILE_MODE_INITIALIZATION
)
702 if( predecessor
->initializer
!= predecessor
)
703 return LSMASH_ERR_INVALID_DATA
;
704 successor
->initializer
= predecessor
;
707 successor
->initializer
= predecessor
->initializer
;
708 isom_styp_t
*styp
= (isom_styp_t
*)lsmash_get_entry_data( &successor
->styp_list
, 1 );
709 if( LSMASH_IS_NON_EXISTING_BOX( styp
) )
711 ret
= isom_set_brands( successor
, 0, 0, NULL
, 0 );
713 return LSMASH_ERR_NAMELESS
;
715 successor
->fragment_count
= predecessor
->fragment_count
;
716 root
->file
= successor
;