1 /*****************************************************************************
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 */
30 int isom_check_compatibility
37 /* Clear flags for compatibility. */
38 ptrdiff_t compat_offset
= offsetof( lsmash_file_t
, qt_compatible
);
39 memset( (int8_t *)file
+ compat_offset
, 0, sizeof(lsmash_file_t
) - compat_offset
);
40 file
->min_isom_version
= UINT8_MAX
; /* undefined value */
41 /* Get the brand container. */
42 isom_ftyp_t
*ftyp
= file
->ftyp
? file
->ftyp
: (isom_ftyp_t
*)lsmash_get_entry_data( &file
->styp_list
, 1 );
43 /* Check brand to decide mandatory boxes. */
46 /* No brand declaration means this file is a MP4 version 1 or QuickTime file format. */
50 file
->mp4_version1
= 1;
51 file
->isom_compatible
= 1;
55 file
->qt_compatible
= 1;
56 file
->undefined_64_ver
= 1;
60 for( uint32_t i
= 0; i
<= ftyp
->brand_count
; i
++ )
62 uint32_t brand
= (i
== ftyp
->brand_count
? ftyp
->major_brand
: ftyp
->compatible_brands
[i
]);
65 case ISOM_BRAND_TYPE_QT
:
66 file
->qt_compatible
= 1;
68 case ISOM_BRAND_TYPE_MP41
:
69 file
->mp4_version1
= 1;
71 case ISOM_BRAND_TYPE_MP42
:
72 file
->mp4_version2
= 1;
74 case ISOM_BRAND_TYPE_AVC1
:
75 case ISOM_BRAND_TYPE_ISOM
:
76 file
->max_isom_version
= LSMASH_MAX( file
->max_isom_version
, 1 );
77 file
->min_isom_version
= LSMASH_MIN( file
->min_isom_version
, 1 );
79 case ISOM_BRAND_TYPE_ISO2
:
80 file
->max_isom_version
= LSMASH_MAX( file
->max_isom_version
, 2 );
81 file
->min_isom_version
= LSMASH_MIN( file
->min_isom_version
, 2 );
83 case ISOM_BRAND_TYPE_ISO3
:
84 file
->max_isom_version
= LSMASH_MAX( file
->max_isom_version
, 3 );
85 file
->min_isom_version
= LSMASH_MIN( file
->min_isom_version
, 3 );
87 case ISOM_BRAND_TYPE_ISO4
:
88 file
->max_isom_version
= LSMASH_MAX( file
->max_isom_version
, 4 );
89 file
->min_isom_version
= LSMASH_MIN( file
->min_isom_version
, 4 );
91 case ISOM_BRAND_TYPE_ISO5
:
92 file
->max_isom_version
= LSMASH_MAX( file
->max_isom_version
, 5 );
93 file
->min_isom_version
= LSMASH_MIN( file
->min_isom_version
, 5 );
95 case ISOM_BRAND_TYPE_ISO6
:
96 file
->max_isom_version
= LSMASH_MAX( file
->max_isom_version
, 6 );
97 file
->min_isom_version
= LSMASH_MIN( file
->min_isom_version
, 6 );
99 case ISOM_BRAND_TYPE_ISO7
:
100 file
->max_isom_version
= LSMASH_MAX( file
->max_isom_version
, 7 );
101 file
->min_isom_version
= LSMASH_MIN( file
->min_isom_version
, 7 );
103 case ISOM_BRAND_TYPE_M4A
:
104 case ISOM_BRAND_TYPE_M4B
:
105 case ISOM_BRAND_TYPE_M4P
:
106 case ISOM_BRAND_TYPE_M4V
:
107 file
->itunes_movie
= 1;
109 case ISOM_BRAND_TYPE_3GP4
:
110 file
->max_3gpp_version
= LSMASH_MAX( file
->max_3gpp_version
, 4 );
112 case ISOM_BRAND_TYPE_3GP5
:
113 file
->max_3gpp_version
= LSMASH_MAX( file
->max_3gpp_version
, 5 );
115 case ISOM_BRAND_TYPE_3GE6
:
116 case ISOM_BRAND_TYPE_3GG6
:
117 case ISOM_BRAND_TYPE_3GP6
:
118 case ISOM_BRAND_TYPE_3GR6
:
119 case ISOM_BRAND_TYPE_3GS6
:
120 file
->max_3gpp_version
= LSMASH_MAX( file
->max_3gpp_version
, 6 );
122 case ISOM_BRAND_TYPE_3GP7
:
123 file
->max_3gpp_version
= LSMASH_MAX( file
->max_3gpp_version
, 7 );
125 case ISOM_BRAND_TYPE_3GP8
:
126 file
->max_3gpp_version
= LSMASH_MAX( file
->max_3gpp_version
, 8 );
128 case ISOM_BRAND_TYPE_3GE9
:
129 case ISOM_BRAND_TYPE_3GF9
:
130 case ISOM_BRAND_TYPE_3GG9
:
131 case ISOM_BRAND_TYPE_3GH9
:
132 case ISOM_BRAND_TYPE_3GM9
:
133 case ISOM_BRAND_TYPE_3GP9
:
134 case ISOM_BRAND_TYPE_3GR9
:
135 case ISOM_BRAND_TYPE_3GS9
:
136 case ISOM_BRAND_TYPE_3GT9
:
137 file
->max_3gpp_version
= LSMASH_MAX( file
->max_3gpp_version
, 9 );
144 case ISOM_BRAND_TYPE_AVC1
:
145 case ISOM_BRAND_TYPE_ISO2
:
146 case ISOM_BRAND_TYPE_ISO3
:
147 case ISOM_BRAND_TYPE_ISO4
:
148 case ISOM_BRAND_TYPE_ISO5
:
149 case ISOM_BRAND_TYPE_ISO6
:
150 file
->avc_extensions
= 1;
152 case ISOM_BRAND_TYPE_3GP4
:
153 case ISOM_BRAND_TYPE_3GP5
:
154 case ISOM_BRAND_TYPE_3GP6
:
155 case ISOM_BRAND_TYPE_3GP7
:
156 case ISOM_BRAND_TYPE_3GP8
:
157 case ISOM_BRAND_TYPE_3GP9
:
158 file
->forbid_tref
= 1;
160 case ISOM_BRAND_TYPE_3GH9
:
161 case ISOM_BRAND_TYPE_3GM9
:
162 case ISOM_BRAND_TYPE_DASH
:
163 case ISOM_BRAND_TYPE_DSMS
:
164 case ISOM_BRAND_TYPE_LMSG
:
165 case ISOM_BRAND_TYPE_MSDH
:
166 case ISOM_BRAND_TYPE_MSIX
:
167 case ISOM_BRAND_TYPE_SIMS
:
168 file
->media_segment
= 1;
174 file
->isom_compatible
= !file
->qt_compatible
175 || file
->mp4_version1
176 || file
->mp4_version2
177 || file
->itunes_movie
178 || file
->max_3gpp_version
;
179 file
->undefined_64_ver
= file
->qt_compatible
|| file
->itunes_movie
;
180 if( file
->flags
& LSMASH_FILE_MODE_WRITE
)
182 /* Media Segment is incompatible with ISO Base Media File Format version 4 or former must be compatible with
183 * version 6 or later since it requires default-base-is-moof and Track Fragment Base Media Decode Time Box. */
184 if( file
->media_segment
&& (file
->min_isom_version
< 5 || (file
->max_isom_version
&& file
->max_isom_version
< 6)) )
186 file
->allow_moof_base
= (file
->max_isom_version
>= 5 && file
->min_isom_version
>= 5)
187 || (file
->max_isom_version
== 0 && file
->min_isom_version
== UINT8_MAX
&& file
->media_segment
);
192 int isom_check_mandatory_boxes
199 || !file
->moov
->mvhd
)
201 /* A movie requires at least one track. */
202 if( !file
->moov
->trak_list
.head
)
204 for( lsmash_entry_t
*entry
= file
->moov
->trak_list
.head
; entry
; entry
= entry
->next
)
206 isom_trak_t
*trak
= (isom_trak_t
*)entry
->data
;
213 || !trak
->mdia
->minf
->dinf
214 || !trak
->mdia
->minf
->dinf
->dref
215 || !trak
->mdia
->minf
->stbl
216 || !trak
->mdia
->minf
->stbl
->stsd
217 || !trak
->mdia
->minf
->stbl
->stsz
218 || !trak
->mdia
->minf
->stbl
->stts
219 || !trak
->mdia
->minf
->stbl
->stsc
220 || !trak
->mdia
->minf
->stbl
->stco
)
222 if( file
->qt_compatible
&& !trak
->mdia
->minf
->hdlr
)
224 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
225 if( !stbl
->stsd
->list
.head
)
228 && (!stbl
->stsd
->list
.head
229 || !stbl
->stts
->list
|| !stbl
->stts
->list
->head
230 || !stbl
->stsc
->list
|| !stbl
->stsc
->list
->head
231 || !stbl
->stco
->list
|| !stbl
->stco
->list
->head
) )
234 if( !file
->fragment
)
236 if( !file
->moov
->mvex
)
238 for( lsmash_entry_t
*entry
= file
->moov
->mvex
->trex_list
.head
; entry
; entry
= entry
->next
)
239 if( !entry
->data
) /* trex */
244 static int isom_set_brands
247 lsmash_brand_type major_brand
,
248 uint32_t minor_version
,
249 lsmash_brand_type
*brands
,
253 if( brand_count
> 50 )
254 return -1; /* We support setting brands up to 50. */
255 if( major_brand
== 0 || brand_count
== 0 )
257 /* Absence of File Type Box means this file is a QuickTime or MP4 version 1 format file. */
258 isom_remove_box_by_itself( file
->ftyp
);
259 /* Anyway we use QTFF as a default file format. */
260 file
->qt_compatible
= 1;
264 if( file
->flags
& LSMASH_FILE_MODE_INITIALIZATION
)
266 /* Add File Type Box if absent yet. */
267 if( !file
->ftyp
&& !isom_add_ftyp( file
) )
273 /* Add Segment Type Box if absent yet. */
274 ftyp
= file
->styp_list
.head
&& file
->styp_list
.head
->data
275 ? (isom_styp_t
*)file
->styp_list
.head
->data
276 : isom_add_styp( file
);
280 /* Allocate an array of compatible brands.
281 * ISO/IEC 14496-12 doesn't forbid the absence of brands in the compatible brand list.
282 * For a reason of safety, however, we set at least one brand in the list. */
283 size_t alloc_size
= (brand_count
? brand_count
: 1) * sizeof(uint32_t);
284 lsmash_brand_type
*compatible_brands
;
285 if( !file
->compatible_brands
)
286 compatible_brands
= lsmash_malloc( alloc_size
);
288 compatible_brands
= lsmash_realloc( file
->compatible_brands
, alloc_size
);
289 if( !compatible_brands
)
291 /* Set compatible brands. */
293 for( uint32_t i
= 0; i
< brand_count
; i
++ )
294 compatible_brands
[i
] = brands
[i
];
297 /* At least one compatible brand. */
298 compatible_brands
[0] = major_brand
;
301 file
->compatible_brands
= compatible_brands
;
302 /* Duplicate an array of compatible brands. */
303 lsmash_free( ftyp
->compatible_brands
);
304 ftyp
->compatible_brands
= lsmash_memdup( compatible_brands
, alloc_size
);
305 if( !ftyp
->compatible_brands
)
307 lsmash_freep( &file
->compatible_brands
);
310 ftyp
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 8 + brand_count
* 4;
311 ftyp
->major_brand
= major_brand
;
312 ftyp
->minor_version
= minor_version
;
313 ftyp
->brand_count
= brand_count
;
314 file
->brand_count
= brand_count
;
315 return isom_check_compatibility( file
);
318 /*******************************
320 *******************************/
322 void lsmash_discard_boxes
327 if( !root
|| !root
->file
)
329 isom_remove_all_extension_boxes( &root
->file
->extensions
);
334 const char *filename
,
336 lsmash_file_parameters_t
*param
339 if( !filename
|| !param
)
341 char mode
[4] = { 0 };
342 lsmash_file_mode file_mode
= 0;
345 memcpy( mode
, "w+b", 4 );
346 file_mode
= LSMASH_FILE_MODE_WRITE
347 | LSMASH_FILE_MODE_BOX
348 | LSMASH_FILE_MODE_INITIALIZATION
349 | LSMASH_FILE_MODE_MEDIA
;
351 #ifdef LSMASH_DEMUXER_ENABLED
352 else if( open_mode
== 1 )
354 memcpy( mode
, "rb", 3 );
355 file_mode
= LSMASH_FILE_MODE_READ
;
362 if( !strcmp( filename
, "-" ) )
364 if( file_mode
& LSMASH_FILE_MODE_READ
)
369 else if( file_mode
& LSMASH_FILE_MODE_WRITE
)
373 file_mode
|= LSMASH_FILE_MODE_FRAGMENTED
;
377 stream
= lsmash_fopen( filename
, mode
);
380 memset( param
, 0, sizeof(lsmash_file_parameters_t
) );
381 param
->mode
= file_mode
;
382 param
->opaque
= (void *)stream
;
383 param
->read
= lsmash_fread_wrapper
;
384 param
->write
= lsmash_fwrite_wrapper
;
385 param
->seek
= seekable
? lsmash_fseek_wrapper
: NULL
;
386 param
->major_brand
= 0;
387 param
->brands
= NULL
;
388 param
->brand_count
= 0;
389 param
->minor_version
= 0;
390 param
->max_chunk_duration
= 0.5;
391 param
->max_async_tolerance
= 2.0;
392 param
->max_chunk_size
= 4 * 1024 * 1024;
393 param
->max_read_size
= 4 * 1024 * 1024;
397 int lsmash_close_file
399 lsmash_file_parameters_t
*param
406 int ret
= fclose( (FILE *)param
->opaque
);
407 param
->opaque
= NULL
;
411 lsmash_file_t
*lsmash_set_file
414 lsmash_file_parameters_t
*param
417 if( !root
|| !param
)
419 lsmash_file_t
*file
= isom_add_file( root
);
422 lsmash_bs_t
*bs
= lsmash_bs_create();
426 file
->flags
= param
->mode
;
427 file
->bs
->stream
= param
->opaque
;
428 file
->bs
->read
= param
->read
;
429 file
->bs
->write
= param
->write
;
430 file
->bs
->seek
= param
->seek
;
431 file
->bs
->unseekable
= (param
->seek
== NULL
);
432 file
->bs
->buffer
.max_size
= param
->max_read_size
;
433 file
->max_chunk_duration
= param
->max_chunk_duration
;
434 file
->max_async_tolerance
= LSMASH_MAX( param
->max_async_tolerance
, 2 * param
->max_chunk_duration
);
435 file
->max_chunk_size
= param
->max_chunk_size
;
436 if( (file
->flags
& LSMASH_FILE_MODE_WRITE
)
437 && (file
->flags
& LSMASH_FILE_MODE_BOX
) )
439 /* Establish the fragment handler if required. */
440 if( file
->flags
& LSMASH_FILE_MODE_FRAGMENTED
)
442 file
->fragment
= lsmash_malloc_zero( sizeof(isom_fragment_manager_t
) );
443 if( !file
->fragment
)
445 file
->fragment
->pool
= lsmash_create_entry_list();
446 if( !file
->fragment
->pool
)
449 else if( file
->bs
->unseekable
)
450 /* For unseekable output operations, LSMASH_FILE_MODE_FRAGMENTED shall be set. */
452 /* Establish file types. */
453 if( isom_set_brands( file
, param
->major_brand
,
454 param
->minor_version
,
455 param
->brands
, param
->brand_count
) < 0 )
457 /* Create the movie header if the initialization of the streams is required. */
458 if( file
->flags
& LSMASH_FILE_MODE_INITIALIZATION
)
460 if( !isom_add_moov( file
)
461 || !isom_add_mvhd( file
->moov
) )
463 /* Default Movie Header Box. */
464 isom_mvhd_t
*mvhd
= file
->moov
->mvhd
;
465 mvhd
->rate
= 0x00010000;
466 mvhd
->volume
= 0x0100;
467 mvhd
->matrix
[0] = 0x00010000;
468 mvhd
->matrix
[4] = 0x00010000;
469 mvhd
->matrix
[8] = 0x40000000;
470 mvhd
->next_track_ID
= 1;
477 isom_remove_box_by_itself( file
);
481 int64_t lsmash_read_file
484 lsmash_file_parameters_t
*param
487 #ifdef LSMASH_DEMUXER_ENABLED
488 if( !file
|| !file
->bs
)
491 if( file
->flags
& (LSMASH_FILE_MODE_READ
| LSMASH_FILE_MODE_DUMP
) )
493 /* Get the file size if seekable when reading. */
494 if( !file
->bs
->unseekable
)
496 ret
= lsmash_bs_read_seek( file
->bs
, 0, SEEK_END
);
499 file
->bs
->written
= ret
;
500 lsmash_bs_read_seek( file
->bs
, 0, SEEK_SET
);
504 /* Read whole boxes. */
505 if( isom_read_file( file
) < 0 )
512 isom_ftyp_t
*ftyp
= file
->ftyp
;
513 param
->major_brand
= ftyp
->major_brand
? ftyp
->major_brand
: ISOM_BRAND_TYPE_QT
;
514 param
->minor_version
= ftyp
->minor_version
;
515 param
->brands
= file
->compatible_brands
;
516 param
->brand_count
= file
->brand_count
;
518 else if( file
->styp_list
.head
&& file
->styp_list
.head
->data
)
521 isom_styp_t
*styp
= (isom_styp_t
*)file
->styp_list
.head
->data
;
522 param
->major_brand
= styp
->major_brand
? styp
->major_brand
: ISOM_BRAND_TYPE_QT
;
523 param
->minor_version
= styp
->minor_version
;
524 param
->brands
= file
->compatible_brands
;
525 param
->brand_count
= file
->brand_count
;
529 param
->major_brand
= file
->mp4_version1
? ISOM_BRAND_TYPE_MP41
: ISOM_BRAND_TYPE_QT
;
530 param
->minor_version
= 0;
531 param
->brands
= NULL
;
532 param
->brand_count
= 0;
542 int lsmash_activate_file
548 if( !root
|| !file
|| file
->root
!= root
)