1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2010 L-SMASH project
6 * Authors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
7 * Contributors: Takashi Hirata <silverfilain@gmail.com>
9 * Permission to use, copy, modify, and/or distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 *****************************************************************************/
22 /* This file is available under an ISC license. */
24 #include "internal.h" /* must be placed first */
29 #include <ctype.h> /* for chapter handling */
34 #ifdef LSMASH_DEMUXER_ENABLED
42 /* Return 1 if the box is fullbox, Otherwise return 0. */
43 int isom_is_fullbox( void *box
)
45 uint32_t type
= ((isom_box_t
*)box
)->type
;
46 static const uint32_t fullbox_table
[] = {
88 for( int i
= 0; i
< sizeof(fullbox_table
)/sizeof(uint32_t); i
++ )
89 if( type
== fullbox_table
[i
] )
94 /* Return 1 if the sample type is LPCM audio, Otherwise return 0. */
95 int isom_is_lpcm_audio( uint32_t type
)
97 return type
== QT_CODEC_TYPE_23NI_AUDIO
98 || type
== QT_CODEC_TYPE_NONE_AUDIO
99 || type
== QT_CODEC_TYPE_LPCM_AUDIO
100 || type
== QT_CODEC_TYPE_RAW_AUDIO
101 || type
== QT_CODEC_TYPE_SOWT_AUDIO
102 || type
== QT_CODEC_TYPE_TWOS_AUDIO
103 || type
== QT_CODEC_TYPE_FL32_AUDIO
104 || type
== QT_CODEC_TYPE_FL64_AUDIO
105 || type
== QT_CODEC_TYPE_IN24_AUDIO
106 || type
== QT_CODEC_TYPE_IN32_AUDIO
107 || type
== QT_CODEC_TYPE_NOT_SPECIFIED
;
110 char *isom_4cc2str( uint32_t fourcc
)
113 str
[0] = (fourcc
>> 24) & 0xff;
114 str
[1] = (fourcc
>> 16) & 0xff;
115 str
[2] = (fourcc
>> 8) & 0xff;
116 str
[3] = fourcc
& 0xff;
121 static inline void isom_init_basebox_common( isom_box_t
*box
, isom_box_t
*parent
, uint32_t type
)
123 box
->root
= parent
->root
;
124 box
->parent
= parent
;
127 box
->usertype
= NULL
;
130 static inline void isom_init_fullbox_common( isom_box_t
*box
, isom_box_t
*parent
, uint32_t type
)
132 box
->root
= parent
->root
;
133 box
->parent
= parent
;
136 box
->usertype
= NULL
;
141 void isom_init_box_common( void *box
, void *parent
, uint32_t type
)
143 assert( parent
&& ((isom_box_t
*)parent
)->root
);
144 if( ((isom_box_t
*)parent
)->type
== ISOM_BOX_TYPE_STSD
)
146 isom_init_basebox_common( (isom_box_t
*)box
, (isom_box_t
*)parent
, type
);
149 if( isom_is_fullbox( box
) )
150 isom_init_fullbox_common( (isom_box_t
*)box
, (isom_box_t
*)parent
, type
);
152 isom_init_basebox_common( (isom_box_t
*)box
, (isom_box_t
*)parent
, type
);
155 static void isom_bs_put_basebox_common( lsmash_bs_t
*bs
, isom_box_t
*box
)
157 if( box
->size
> UINT32_MAX
)
159 lsmash_bs_put_be32( bs
, 1 );
160 lsmash_bs_put_be32( bs
, box
->type
);
161 lsmash_bs_put_be64( bs
, box
->size
); /* largesize */
165 lsmash_bs_put_be32( bs
, (uint32_t)box
->size
);
166 lsmash_bs_put_be32( bs
, box
->type
);
168 if( box
->type
== ISOM_BOX_TYPE_UUID
)
169 lsmash_bs_put_bytes( bs
, box
->usertype
, 16 );
172 static void isom_bs_put_fullbox_common( lsmash_bs_t
*bs
, isom_box_t
*box
)
174 isom_bs_put_basebox_common( bs
, box
);
175 lsmash_bs_put_byte( bs
, box
->version
);
176 lsmash_bs_put_be24( bs
, box
->flags
);
179 static void isom_bs_put_box_common( lsmash_bs_t
*bs
, void *box
)
186 isom_box_t
*parent
= ((isom_box_t
*)box
)->parent
;
187 if( parent
&& parent
->type
== ISOM_BOX_TYPE_STSD
)
189 isom_bs_put_basebox_common( bs
, (isom_box_t
*)box
);
192 if( isom_is_fullbox( box
) )
193 isom_bs_put_fullbox_common( bs
, (isom_box_t
*)box
);
195 isom_bs_put_basebox_common( bs
, (isom_box_t
*)box
);
198 isom_trak_entry_t
*isom_get_trak( lsmash_root_t
*root
, uint32_t track_ID
)
200 if( !track_ID
|| !root
|| !root
->moov
|| !root
->moov
->trak_list
)
202 for( lsmash_entry_t
*entry
= root
->moov
->trak_list
->head
; entry
; entry
= entry
->next
)
204 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)entry
->data
;
205 if( !trak
|| !trak
->tkhd
)
207 if( trak
->tkhd
->track_ID
== track_ID
)
213 static isom_trex_entry_t
*isom_get_trex( isom_mvex_t
*mvex
, uint32_t track_ID
)
215 if( !track_ID
|| !mvex
|| !mvex
->trex_list
)
217 for( lsmash_entry_t
*entry
= mvex
->trex_list
->head
; entry
; entry
= entry
->next
)
219 isom_trex_entry_t
*trex
= (isom_trex_entry_t
*)entry
->data
;
222 if( trex
->track_ID
== track_ID
)
228 static isom_traf_entry_t
*isom_get_traf( isom_moof_entry_t
*moof
, uint32_t track_ID
)
230 if( !track_ID
|| !moof
|| !moof
->traf_list
)
232 for( lsmash_entry_t
*entry
= moof
->traf_list
->head
; entry
; entry
= entry
->next
)
234 isom_traf_entry_t
*traf
= (isom_traf_entry_t
*)entry
->data
;
235 if( !traf
|| !traf
->tfhd
)
237 if( traf
->tfhd
->track_ID
== track_ID
)
243 static isom_tfra_entry_t
*isom_get_tfra( isom_mfra_t
*mfra
, uint32_t track_ID
)
245 if( !track_ID
|| !mfra
|| !mfra
->tfra_list
)
247 for( lsmash_entry_t
*entry
= mfra
->tfra_list
->head
; entry
; entry
= entry
->next
)
249 isom_tfra_entry_t
*tfra
= (isom_tfra_entry_t
*)entry
->data
;
252 if( tfra
->track_ID
== track_ID
)
258 static int isom_add_elst_entry( isom_elst_t
*elst
, uint64_t segment_duration
, int64_t media_time
, int32_t media_rate
)
260 isom_elst_entry_t
*data
= malloc( sizeof(isom_elst_entry_t
) );
263 data
->segment_duration
= segment_duration
;
264 data
->media_time
= media_time
;
265 data
->media_rate
= media_rate
;
266 if( lsmash_add_entry( elst
->list
, data
) )
271 if( data
->segment_duration
> UINT32_MAX
|| data
->media_time
> INT32_MAX
|| data
->media_time
< INT32_MIN
)
276 static isom_tref_type_t
*isom_add_track_reference_type( isom_tref_t
*tref
, lsmash_track_reference_type_code type
, uint32_t ref_count
, uint32_t *track_ID
)
278 if( !tref
|| !tref
->ref_list
)
280 isom_tref_type_t
*ref
= malloc( sizeof(isom_tref_type_t
) );
283 isom_init_box_common( ref
, tref
, type
);
284 ref
->ref_count
= ref_count
;
285 ref
->track_ID
= track_ID
;
286 if( lsmash_add_entry( tref
->ref_list
, ref
) )
294 static int isom_add_dref_entry( isom_dref_t
*dref
, uint32_t flags
, char *name
, char *location
)
296 if( !dref
|| !dref
->list
)
298 isom_dref_entry_t
*data
= malloc( sizeof(isom_dref_entry_t
) );
301 memset( data
, 0, sizeof(isom_dref_entry_t
) );
302 isom_init_box_common( data
, dref
, name
? ISOM_BOX_TYPE_URN
: ISOM_BOX_TYPE_URL
);
306 data
->location_length
= strlen( location
) + 1;
307 data
->location
= malloc( data
->location_length
);
308 if( !data
->location
)
313 memcpy( data
->location
, location
, data
->location_length
);
317 data
->name_length
= strlen( name
) + 1;
318 data
->name
= malloc( data
->name_length
);
322 free( data
->location
);
326 memcpy( data
->name
, name
, data
->name_length
);
328 if( lsmash_add_entry( dref
->list
, data
) )
331 free( data
->location
);
340 isom_avcC_ps_entry_t
*isom_create_ps_entry( uint8_t *ps
, uint32_t ps_size
)
342 isom_avcC_ps_entry_t
*entry
= malloc( sizeof(isom_avcC_ps_entry_t
) );
345 entry
->parameterSetLength
= ps_size
;
346 entry
->parameterSetNALUnit
= malloc( ps_size
);
347 if( !entry
->parameterSetNALUnit
)
352 memcpy( entry
->parameterSetNALUnit
, ps
, ps_size
);
356 void isom_remove_avcC_ps( isom_avcC_ps_entry_t
*ps
)
360 if( ps
->parameterSetNALUnit
)
361 free( ps
->parameterSetNALUnit
);
365 int lsmash_add_sps_entry( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t entry_number
, uint8_t *sps
, uint32_t sps_size
)
367 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
368 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
|| !trak
->mdia
->minf
->stbl
->stsd
|| !trak
->mdia
->minf
->stbl
->stsd
->list
)
370 isom_visual_entry_t
*data
= (isom_visual_entry_t
*)lsmash_get_entry_data( trak
->mdia
->minf
->stbl
->stsd
->list
, entry_number
);
371 if( !data
|| !data
->avcC
)
373 isom_avcC_t
*avcC
= (isom_avcC_t
*)data
->avcC
;
374 isom_avcC_ps_entry_t
*ps
= isom_create_ps_entry( sps
, sps_size
);
377 if( lsmash_add_entry( avcC
->sequenceParameterSets
, ps
) )
379 isom_remove_avcC_ps( ps
);
382 avcC
->numOfSequenceParameterSets
= avcC
->sequenceParameterSets
->entry_count
;
386 int lsmash_add_pps_entry( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t entry_number
, uint8_t *pps
, uint32_t pps_size
)
388 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
389 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
|| !trak
->mdia
->minf
->stbl
->stsd
|| !trak
->mdia
->minf
->stbl
->stsd
->list
)
391 isom_visual_entry_t
*data
= (isom_visual_entry_t
*)lsmash_get_entry_data( trak
->mdia
->minf
->stbl
->stsd
->list
, entry_number
);
392 if( !data
|| !data
->avcC
)
394 isom_avcC_t
*avcC
= (isom_avcC_t
*)data
->avcC
;
395 isom_avcC_ps_entry_t
*ps
= isom_create_ps_entry( pps
, pps_size
);
398 if( lsmash_add_entry( avcC
->pictureParameterSets
, ps
) )
400 isom_remove_avcC_ps( ps
);
403 avcC
->numOfPictureParameterSets
= avcC
->pictureParameterSets
->entry_count
;
407 int lsmash_add_spsext_entry( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t entry_number
, uint8_t *spsext
, uint32_t spsext_size
)
409 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
410 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
|| !trak
->mdia
->minf
->stbl
->stsd
|| !trak
->mdia
->minf
->stbl
->stsd
->list
)
412 isom_visual_entry_t
*data
= (isom_visual_entry_t
*)lsmash_get_entry_data( trak
->mdia
->minf
->stbl
->stsd
->list
, entry_number
);
413 if( !data
|| !data
->avcC
)
415 isom_avcC_t
*avcC
= (isom_avcC_t
*)data
->avcC
;
416 isom_avcC_ps_entry_t
*ps
= isom_create_ps_entry( spsext
, spsext_size
);
419 if( lsmash_add_entry( avcC
->sequenceParameterSetExt
, ps
) )
421 isom_remove_avcC_ps( ps
);
424 avcC
->numOfSequenceParameterSetExt
= avcC
->sequenceParameterSetExt
->entry_count
;
428 int isom_add_avcC( isom_visual_entry_t
*visual
)
432 isom_create_box( avcC
, visual
, ISOM_BOX_TYPE_AVCC
);
433 avcC
->sequenceParameterSets
= lsmash_create_entry_list();
434 if( !avcC
->sequenceParameterSets
)
439 avcC
->pictureParameterSets
= lsmash_create_entry_list();
440 if( !avcC
->pictureParameterSets
)
442 isom_remove_avcC( avcC
);
445 avcC
->sequenceParameterSetExt
= lsmash_create_entry_list();
446 if( !avcC
->sequenceParameterSetExt
)
448 isom_remove_avcC( avcC
);
455 int isom_add_clap( isom_visual_entry_t
*visual
)
457 if( !visual
|| visual
->clap
)
459 isom_create_box( clap
, visual
, ISOM_BOX_TYPE_CLAP
);
460 clap
->cleanApertureWidthN
= 1;
461 clap
->cleanApertureWidthD
= 1;
462 clap
->cleanApertureHeightN
= 1;
463 clap
->cleanApertureHeightD
= 1;
472 int isom_add_pasp( isom_visual_entry_t
*visual
)
474 if( !visual
|| visual
->pasp
)
476 isom_create_box( pasp
, visual
, ISOM_BOX_TYPE_PASP
);
483 int isom_add_colr( isom_visual_entry_t
*visual
)
485 if( !visual
|| visual
->colr
)
487 isom_create_box( colr
, visual
, QT_BOX_TYPE_COLR
);
488 isom_color_parameter_t
*param
= (isom_color_parameter_t
*)(&isom_color_parameter_tbl
[0]);
489 colr
->color_parameter_type
= QT_COLOR_PARAMETER_TYPE_NCLC
;
490 colr
->primaries_index
= param
->primaries
;
491 colr
->transfer_function_index
= param
->transfer
;
492 colr
->matrix_index
= param
->matrix
;
497 int isom_add_stsl( isom_visual_entry_t
*visual
)
499 if( !visual
|| visual
->stsl
)
501 isom_create_box( stsl
, visual
, ISOM_BOX_TYPE_STSL
);
502 stsl
->scale_method
= ISOM_SCALING_METHOD_HIDDEN
;
507 static void isom_remove_esds( isom_esds_t
*esds
);
508 static void isom_remove_visual_extensions( isom_visual_entry_t
*visual
);
510 static int isom_add_visual_extensions( isom_visual_entry_t
*visual
, lsmash_video_summary_t
*summary
)
512 /* Check if set up Track Aperture Modes. */
513 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)visual
->parent
->parent
->parent
->parent
->parent
;
514 int qt_compatible
= trak
->root
->qt_compatible
;
515 isom_tapt_t
*tapt
= trak
->tapt
;
516 int set_aperture_modes
= qt_compatible
/* Track Aperture Modes is only available under QuickTime file format. */
517 && !summary
->scaling_method
/* Sample scaling method might conflict with this feature. */
518 && tapt
&& tapt
->clef
&& tapt
->prof
&& tapt
->enof
/* Check if required boxes exist. */
519 && !((isom_stsd_t
*)visual
->parent
)->list
->entry_count
; /* Multiple sample description might conflict with this, so in that case, disable this feature.
520 * Note: this sample description isn't added yet here. */
521 if( !set_aperture_modes
)
522 isom_remove_tapt( trak
->tapt
);
523 /* Set up Clean Aperture. */
524 if( set_aperture_modes
|| summary
->crop_top
|| summary
->crop_left
|| summary
->crop_bottom
|| summary
->crop_right
)
526 if( isom_add_clap( visual
) )
528 isom_remove_visual_extensions( visual
);
531 isom_clap_t
*clap
= visual
->clap
;
532 clap
->cleanApertureWidthN
= summary
->width
- (summary
->crop_left
+ summary
->crop_right
);
533 clap
->cleanApertureHeightN
= summary
->height
- (summary
->crop_top
+ summary
->crop_bottom
);
534 clap
->horizOffN
= (int64_t)summary
->crop_left
- summary
->crop_right
;
535 clap
->vertOffN
= (int64_t)summary
->crop_top
- summary
->crop_bottom
;
536 if( !(clap
->horizOffN
& 0x1) )
538 clap
->horizOffN
/= 2;
543 if( !(clap
->vertOffN
& 0x1) )
551 /* Set up Pixel Aspect Ratio. */
552 if( set_aperture_modes
|| (summary
->par_h
&& summary
->par_v
) )
554 if( isom_add_pasp( visual
) )
556 isom_remove_visual_extensions( visual
);
559 isom_pasp_t
*pasp
= visual
->pasp
;
560 pasp
->hSpacing
= summary
->par_h
;
561 pasp
->vSpacing
= summary
->par_v
;
563 /* Set up Color Parameter. */
564 if( qt_compatible
&& (summary
->primaries
|| summary
->transfer
|| summary
->matrix
) )
566 if( isom_add_colr( visual
) )
568 isom_remove_visual_extensions( visual
);
571 isom_colr_t
*colr
= visual
->colr
;
572 uint16_t primaries
= summary
->primaries
;
573 uint16_t transfer
= summary
->transfer
;
574 uint16_t matrix
= summary
->matrix
;
575 /* Set 'nclc' to parameter type, we don't support 'prof'. */
576 colr
->color_parameter_type
= QT_COLOR_PARAMETER_TYPE_NCLC
;
578 if( primaries
>= QT_COLOR_PARAMETER_END
)
580 else if( primaries
> UINT16_MAX
)
581 colr
->primaries_index
= isom_color_parameter_tbl
[primaries
- UINT16_MAX_PLUS_ONE
].primaries
;
583 colr
->primaries_index
= (primaries
== 1 || primaries
== 5 || primaries
== 6) ? primaries
: 2;
585 if( transfer
>= QT_COLOR_PARAMETER_END
)
587 else if( transfer
> UINT16_MAX
)
588 colr
->transfer_function_index
= isom_color_parameter_tbl
[transfer
- UINT16_MAX_PLUS_ONE
].transfer
;
590 colr
->transfer_function_index
= (transfer
== 1 || transfer
== 7) ? transfer
: 2;
592 if( matrix
>= QT_COLOR_PARAMETER_END
)
594 else if( matrix
> UINT16_MAX
)
595 colr
->matrix_index
= isom_color_parameter_tbl
[matrix
- UINT16_MAX_PLUS_ONE
].matrix
;
597 colr
->matrix_index
= (matrix
== 1 || matrix
== 6 || matrix
== 7 ) ? matrix
: 2;
599 /* Set up Sample Scaling. */
600 if( !qt_compatible
&& summary
->scaling_method
)
602 if( isom_add_stsl( visual
) )
604 isom_remove_visual_extensions( visual
);
607 isom_stsl_t
*stsl
= visual
->stsl
;
608 stsl
->constraint_flag
= 1;
609 stsl
->scale_method
= summary
->scaling_method
;
611 /* Set up AVC Decoder Configuration. */
612 static const uint32_t avc_type
[] =
614 ISOM_CODEC_TYPE_AVC1_VIDEO
,
615 ISOM_CODEC_TYPE_AVC2_VIDEO
,
616 ISOM_CODEC_TYPE_AVCP_VIDEO
618 for( int i
= 0; i
< sizeof(avc_type
)/sizeof(avc_type
[0]); i
++ )
619 if( visual
->type
== avc_type
[i
] )
621 if( isom_add_avcC( visual
) )
625 /* Set up Track Apeture Modes. */
626 if( set_aperture_modes
)
628 uint32_t width
= visual
->width
<< 16;
629 uint32_t height
= visual
->height
<< 16;
630 double clap_width
= ((double)visual
->clap
->cleanApertureWidthN
/ visual
->clap
->cleanApertureWidthD
) * (1<<16);
631 double clap_height
= ((double)visual
->clap
->cleanApertureHeightN
/ visual
->clap
->cleanApertureHeightD
) * (1<<16);
632 double par
= (double)visual
->pasp
->hSpacing
/ visual
->pasp
->vSpacing
;
635 tapt
->clef
->width
= clap_width
* par
;
636 tapt
->clef
->height
= clap_height
;
637 tapt
->prof
->width
= width
* par
;
638 tapt
->prof
->height
= height
;
642 tapt
->clef
->width
= clap_width
;
643 tapt
->clef
->height
= clap_height
/ par
;
644 tapt
->prof
->width
= width
;
645 tapt
->prof
->height
= height
/ par
;
647 tapt
->enof
->width
= width
;
648 tapt
->enof
->height
= height
;
653 static int isom_add_visual_entry( isom_stsd_t
*stsd
, uint32_t sample_type
, lsmash_video_summary_t
*summary
)
655 if( !stsd
|| !stsd
->list
|| !summary
)
657 lsmash_entry_list_t
*list
= stsd
->list
;
658 isom_visual_entry_t
*visual
= malloc( sizeof(isom_visual_entry_t
) );
661 memset( visual
, 0, sizeof(isom_visual_entry_t
) );
662 isom_init_box_common( visual
, stsd
, sample_type
);
663 visual
->data_reference_index
= 1;
664 visual
->width
= (uint16_t)summary
->width
;
665 visual
->height
= (uint16_t)summary
->height
;
666 visual
->horizresolution
= visual
->vertresolution
= 0x00480000;
667 visual
->frame_count
= 1;
668 switch( sample_type
)
670 case ISOM_CODEC_TYPE_AVC1_VIDEO
:
671 case ISOM_CODEC_TYPE_AVC2_VIDEO
:
672 strcpy( visual
->compressorname
, "\012AVC Coding" );
674 case ISOM_CODEC_TYPE_AVCP_VIDEO
:
675 strcpy( visual
->compressorname
, "\016AVC Parameters" );
680 visual
->depth
= 0x0018;
681 visual
->color_table_ID
= -1;
682 if( isom_add_visual_extensions( visual
, summary
)
683 || lsmash_add_entry( list
, visual
) )
685 isom_remove_visual_extensions( visual
);
693 static int isom_add_mp4s_entry( isom_stsd_t
*stsd
)
695 if( !stsd
|| !stsd
->list
)
697 isom_mp4s_entry_t
*mp4s
= malloc( sizeof(isom_mp4s_entry_t
) );
700 memset( mp4s
, 0, sizeof(isom_mp4s_entry_t
) );
701 isom_init_box_common( mp4s
, stsd
, ISOM_CODEC_TYPE_MP4S_SYSTEM
);
702 mp4s
->data_reference_index
= 1;
703 if( lsmash_add_entry( stsd
->list
, mp4s
) )
712 int isom_add_wave( isom_audio_entry_t
*audio
)
714 if( !audio
|| audio
->wave
)
716 isom_create_box( wave
, audio
, QT_BOX_TYPE_WAVE
);
721 int isom_add_frma( isom_wave_t
*wave
)
723 if( !wave
|| wave
->frma
)
725 isom_create_box( frma
, wave
, QT_BOX_TYPE_FRMA
);
730 int isom_add_enda( isom_wave_t
*wave
)
732 if( !wave
|| wave
->enda
)
734 isom_create_box( enda
, wave
, QT_BOX_TYPE_ENDA
);
739 int isom_add_mp4a( isom_wave_t
*wave
)
741 if( !wave
|| wave
->mp4a
)
743 isom_create_box( mp4a
, wave
, QT_BOX_TYPE_MP4A
);
748 int isom_add_terminator( isom_wave_t
*wave
)
750 if( !wave
|| wave
->terminator
)
752 isom_create_box( terminator
, wave
, QT_BOX_TYPE_TERMINATOR
);
753 wave
->terminator
= terminator
;
757 int isom_add_chan( isom_audio_entry_t
*audio
)
759 if( !audio
|| audio
->chan
)
761 isom_create_box( chan
, audio
, QT_BOX_TYPE_CHAN
);
762 chan
->channelLayoutTag
= QT_CHANNEL_LAYOUT_UNKNOWN
;
767 static int isom_set_qtff_mp4a_description( isom_audio_entry_t
*audio
)
769 lsmash_audio_summary_t
*summary
= &audio
->summary
;
770 if( isom_add_wave( audio
)
771 || isom_add_frma( audio
->wave
)
772 || isom_add_mp4a( audio
->wave
)
773 || isom_add_terminator( audio
->wave
) )
775 audio
->data_reference_index
= 1;
776 audio
->version
= (summary
->channels
> 2 || summary
->frequency
> UINT16_MAX
) ? 2 : 1;
777 audio
->channelcount
= audio
->version
== 2 ? 3 : LSMASH_MIN( summary
->channels
, 2 );
778 audio
->samplesize
= 16;
779 audio
->compression_ID
= QT_COMPRESSION_ID_VARIABLE_COMPRESSION
;
780 audio
->packet_size
= 0;
781 if( audio
->version
== 1 )
783 audio
->samplerate
= summary
->frequency
<< 16;
784 audio
->samplesPerPacket
= summary
->samples_in_frame
;
785 audio
->bytesPerPacket
= 1; /* Apparently, this field is set to 1. */
786 audio
->bytesPerFrame
= audio
->bytesPerPacket
* summary
->channels
;
787 audio
->bytesPerSample
= 1 + (summary
->bit_depth
!= 8);
789 else /* audio->version == 2 */
791 audio
->samplerate
= 0x00010000;
792 audio
->sizeOfStructOnly
= 72;
793 audio
->audioSampleRate
= (union {double d
; uint64_t i
;}){summary
->frequency
}.i
;
794 audio
->numAudioChannels
= summary
->channels
;
795 audio
->always7F000000
= 0x7F000000;
796 audio
->constBitsPerChannel
= 0; /* compressed audio */
797 audio
->formatSpecificFlags
= 0;
798 audio
->constBytesPerAudioPacket
= 0; /* variable */
799 audio
->constLPCMFramesPerAudioPacket
= summary
->samples_in_frame
;
801 audio
->wave
->frma
->data_format
= audio
->type
;
802 /* create ES Descriptor */
803 isom_esds_t
*esds
= malloc( sizeof(isom_esds_t
) );
806 memset( esds
, 0, sizeof(isom_esds_t
) );
807 isom_init_box_common( esds
, audio
->wave
, ISOM_BOX_TYPE_ESDS
);
808 mp4sys_ES_Descriptor_params_t esd_param
;
809 memset( &esd_param
, 0, sizeof(mp4sys_ES_Descriptor_params_t
) );
810 esd_param
.objectTypeIndication
= summary
->object_type_indication
;
811 esd_param
.streamType
= summary
->stream_type
;
812 esd_param
.dsi_payload
= summary
->exdata
;
813 esd_param
.dsi_payload_length
= summary
->exdata_length
;
814 esds
->ES
= mp4sys_setup_ES_Descriptor( &esd_param
);
817 audio
->wave
->esds
= esds
;
821 static int isom_set_isom_mp4a_description( isom_audio_entry_t
*audio
)
823 lsmash_audio_summary_t
*summary
= &audio
->summary
;
824 if( summary
->stream_type
!= MP4SYS_STREAM_TYPE_AudioStream
)
826 switch( summary
->object_type_indication
)
828 case MP4SYS_OBJECT_TYPE_Audio_ISO_14496_3
:
829 case MP4SYS_OBJECT_TYPE_Audio_ISO_13818_7_Main_Profile
:
830 case MP4SYS_OBJECT_TYPE_Audio_ISO_13818_7_LC_Profile
:
831 case MP4SYS_OBJECT_TYPE_Audio_ISO_13818_7_SSR_Profile
:
832 case MP4SYS_OBJECT_TYPE_Audio_ISO_13818_3
: /* Legacy Interface */
833 case MP4SYS_OBJECT_TYPE_Audio_ISO_11172_3
: /* Legacy Interface */
838 isom_create_box( esds
, audio
, ISOM_BOX_TYPE_ESDS
);
839 mp4sys_ES_Descriptor_params_t esd_param
;
840 esd_param
.ES_ID
= 0; /* This is esds internal, so 0 is allowed. */
841 esd_param
.objectTypeIndication
= summary
->object_type_indication
;
842 esd_param
.streamType
= summary
->stream_type
;
843 esd_param
.bufferSizeDB
= 0; /* NOTE: ISO/IEC 14496-3 does not mention this, so we use 0. */
844 esd_param
.maxBitrate
= 0; /* This will be updated later if needed. or... I think this can be arbitrary value. */
845 esd_param
.avgBitrate
= 0; /* FIXME: 0 if VBR. */
846 esd_param
.dsi_payload
= summary
->exdata
;
847 esd_param
.dsi_payload_length
= summary
->exdata_length
;
848 esds
->ES
= mp4sys_setup_ES_Descriptor( &esd_param
);
851 audio
->data_reference_index
= 1;
852 /* WARNING: This field cannot retain frequency above 65535Hz.
853 This is not "FIXME", I just honestly implemented what the spec says.
854 BTW, who ever expects sampling frequency takes fixed-point decimal??? */
855 audio
->samplerate
= summary
->frequency
<= UINT16_MAX
? summary
->frequency
<< 16 : 0;
856 /* In pure mp4 file, these "template" fields shall be default values according to the spec.
857 But not pure - hybrid with other spec - mp4 file can take other values.
858 Which is to say, these template values shall be ignored in terms of mp4, except some object_type_indications.
859 see 14496-14, "Template fields used". */
860 audio
->channelcount
= 2;
861 audio
->samplesize
= 16;
866 static int isom_set_qtff_lpcm_description( isom_audio_entry_t
*audio
)
868 uint32_t sample_type
= audio
->type
;
869 lsmash_audio_summary_t
*summary
= &audio
->summary
;
870 /* Convert the sample type into 'lpcm' if the description doesn't match the format or version = 2 fields are needed. */
871 if( (sample_type
== QT_CODEC_TYPE_RAW_AUDIO
&& (summary
->bit_depth
!= 8 || summary
->sample_format
))
872 || (sample_type
== QT_CODEC_TYPE_FL32_AUDIO
&& (summary
->bit_depth
!= 32 || !summary
->sample_format
))
873 || (sample_type
== QT_CODEC_TYPE_FL64_AUDIO
&& (summary
->bit_depth
!= 64 || !summary
->sample_format
))
874 || (sample_type
== QT_CODEC_TYPE_IN24_AUDIO
&& (summary
->bit_depth
!= 24 || summary
->sample_format
))
875 || (sample_type
== QT_CODEC_TYPE_IN32_AUDIO
&& (summary
->bit_depth
!= 32 || summary
->sample_format
))
876 || (sample_type
== QT_CODEC_TYPE_23NI_AUDIO
&& (summary
->bit_depth
!= 32 || summary
->sample_format
|| !summary
->endianness
))
877 || (sample_type
== QT_CODEC_TYPE_SOWT_AUDIO
&& (summary
->bit_depth
!= 16 || summary
->sample_format
|| !summary
->endianness
))
878 || (sample_type
== QT_CODEC_TYPE_TWOS_AUDIO
&& ((summary
->bit_depth
!= 16 && summary
->bit_depth
!= 8) || summary
->sample_format
|| summary
->endianness
))
879 || (sample_type
== QT_CODEC_TYPE_NONE_AUDIO
&& ((summary
->bit_depth
!= 16 && summary
->bit_depth
!= 8) || summary
->sample_format
|| summary
->endianness
))
880 || (sample_type
== QT_CODEC_TYPE_NOT_SPECIFIED
&& ((summary
->bit_depth
!= 16 && summary
->bit_depth
!= 8) || summary
->sample_format
|| summary
->endianness
))
881 || (summary
->channels
> 2 || summary
->frequency
> UINT16_MAX
|| summary
->bit_depth
% 8) )
883 audio
->type
= QT_CODEC_TYPE_LPCM_AUDIO
;
886 else if( sample_type
== QT_CODEC_TYPE_LPCM_AUDIO
)
888 else if( summary
->bit_depth
> 16
889 || (sample_type
!= QT_CODEC_TYPE_RAW_AUDIO
&& sample_type
!= QT_CODEC_TYPE_TWOS_AUDIO
890 && sample_type
!= QT_CODEC_TYPE_NONE_AUDIO
&& sample_type
!= QT_CODEC_TYPE_NOT_SPECIFIED
) )
892 audio
->data_reference_index
= 1;
893 /* Set up constBytesPerAudioPacket field.
894 * We use constBytesPerAudioPacket as the actual size of audio frame even when version is not 2. */
895 audio
->constBytesPerAudioPacket
= (summary
->bit_depth
* summary
->channels
) / 8;
896 /* Set up other fields in this description by its version. */
897 if( audio
->version
== 2 )
899 audio
->channelcount
= 3;
900 audio
->samplesize
= 16;
901 audio
->compression_ID
= -2;
902 audio
->samplerate
= 0x00010000;
903 audio
->sizeOfStructOnly
= 72;
904 audio
->audioSampleRate
= (union {double d
; uint64_t i
;}){summary
->frequency
}.i
;
905 audio
->numAudioChannels
= summary
->channels
;
906 audio
->always7F000000
= 0x7F000000;
907 audio
->constBitsPerChannel
= summary
->bit_depth
;
908 audio
->constLPCMFramesPerAudioPacket
= 1;
909 if( summary
->sample_format
)
910 audio
->formatSpecificFlags
|= QT_LPCM_FORMAT_FLAG_FLOAT
;
911 if( sample_type
== QT_CODEC_TYPE_TWOS_AUDIO
|| !summary
->endianness
)
912 audio
->formatSpecificFlags
|= QT_LPCM_FORMAT_FLAG_BIG_ENDIAN
;
913 if( !summary
->sample_format
&& summary
->signedness
)
914 audio
->formatSpecificFlags
|= QT_LPCM_FORMAT_FLAG_SIGNED_INTEGER
;
915 if( summary
->packed
)
916 audio
->formatSpecificFlags
|= QT_LPCM_FORMAT_FLAG_PACKED
;
917 if( !summary
->packed
&& summary
->alignment
)
918 audio
->formatSpecificFlags
|= QT_LPCM_FORMAT_FLAG_ALIGNED_HIGH
;
919 if( !summary
->interleaved
)
920 audio
->formatSpecificFlags
|= QT_LPCM_FORMAT_FLAG_NON_INTERLEAVED
;
922 else if( audio
->version
== 1 )
924 audio
->channelcount
= summary
->channels
;
925 audio
->samplesize
= 16;
926 /* Audio formats other than 'raw ' and 'twos' are treated as compressed audio. */
927 if( sample_type
== QT_CODEC_TYPE_RAW_AUDIO
|| sample_type
== QT_CODEC_TYPE_TWOS_AUDIO
)
928 audio
->compression_ID
= QT_COMPRESSION_ID_NOT_COMPRESSED
;
930 audio
->compression_ID
= QT_COMPRESSION_ID_FIXED_COMPRESSION
;
931 audio
->samplerate
= summary
->frequency
<< 16;
932 audio
->samplesPerPacket
= 1;
933 audio
->bytesPerPacket
= summary
->bit_depth
/ 8;
934 audio
->bytesPerFrame
= audio
->bytesPerPacket
* summary
->channels
; /* sample_size field in stsz box is NOT used. */
935 audio
->bytesPerSample
= 1 + (summary
->bit_depth
!= 8);
936 if( sample_type
== QT_CODEC_TYPE_FL32_AUDIO
|| sample_type
== QT_CODEC_TYPE_FL64_AUDIO
937 || sample_type
== QT_CODEC_TYPE_IN24_AUDIO
|| sample_type
== QT_CODEC_TYPE_IN32_AUDIO
)
939 if( isom_add_wave( audio
)
940 || isom_add_frma( audio
->wave
)
941 || isom_add_enda( audio
->wave
)
942 || isom_add_terminator( audio
->wave
) )
944 audio
->wave
->frma
->data_format
= sample_type
;
945 audio
->wave
->enda
->littleEndian
= summary
->endianness
;
948 else /* audio->version == 0 */
950 audio
->channelcount
= summary
->channels
;
951 audio
->samplesize
= summary
->bit_depth
;
952 audio
->compression_ID
= QT_COMPRESSION_ID_NOT_COMPRESSED
;
953 audio
->samplerate
= summary
->frequency
<< 16;
958 static int isom_set_extra_description( isom_audio_entry_t
*audio
)
960 lsmash_audio_summary_t
*summary
= &audio
->summary
;
961 audio
->data_reference_index
= 1;
962 audio
->samplerate
= summary
->frequency
<= UINT16_MAX
? summary
->frequency
<< 16 : 0;
963 audio
->channelcount
= 2;
964 audio
->samplesize
= 16;
965 if( summary
->exdata
)
967 audio
->exdata_length
= summary
->exdata_length
;
968 audio
->exdata
= malloc( audio
->exdata_length
);
971 memcpy( audio
->exdata
, summary
->exdata
, audio
->exdata_length
);
974 audio
->exdata
= NULL
;
978 static int isom_add_audio_entry( isom_stsd_t
*stsd
, uint32_t sample_type
, lsmash_audio_summary_t
*summary
)
980 if( !stsd
|| !stsd
->list
|| !summary
)
982 isom_audio_entry_t
*audio
= malloc( sizeof(isom_audio_entry_t
) );
985 memset( audio
, 0, sizeof(isom_audio_entry_t
) );
986 isom_init_box_common( audio
, stsd
, sample_type
);
987 memcpy( &audio
->summary
, summary
, sizeof(lsmash_audio_summary_t
) );
989 lsmash_root_t
*root
= stsd
->root
;
990 if( sample_type
== ISOM_CODEC_TYPE_MP4A_AUDIO
)
992 if( root
->ftyp
&& root
->ftyp
->major_brand
== ISOM_BRAND_TYPE_QT
)
993 ret
= isom_set_qtff_mp4a_description( audio
);
995 ret
= isom_set_isom_mp4a_description( audio
);
997 else if( isom_is_lpcm_audio( sample_type
) )
998 ret
= isom_set_qtff_lpcm_description( audio
);
1000 ret
= isom_set_extra_description( audio
);
1003 if( root
->qt_compatible
)
1005 lsmash_channel_layout_tag_code layout_tag
= summary
->layout_tag
;
1006 lsmash_channel_bitmap_code bitmap
= summary
->bitmap
;
1007 if( layout_tag
== QT_CHANNEL_LAYOUT_USE_CHANNEL_DESCRIPTIONS
/* We don't support the feature of Channel Descriptions. */
1008 || (layout_tag
== QT_CHANNEL_LAYOUT_USE_CHANNEL_BITMAP
&& (!bitmap
|| bitmap
> QT_CHANNEL_BIT_FULL
)) )
1010 layout_tag
= summary
->layout_tag
= QT_CHANNEL_LAYOUT_UNKNOWN
| summary
->channels
;
1011 bitmap
= summary
->bitmap
= 0;
1013 /* Don't create Channel Compositor Box if the channel layout is unknown. */
1014 if( (layout_tag
^ QT_CHANNEL_LAYOUT_UNKNOWN
) >> 16 )
1016 if( isom_add_chan( audio
) )
1018 audio
->chan
->channelLayoutTag
= layout_tag
;
1019 audio
->chan
->channelBitmap
= bitmap
;
1022 if( lsmash_add_entry( stsd
->list
, audio
) )
1026 isom_remove_esds( audio
->esds
);
1027 isom_remove_wave( audio
->wave
);
1028 isom_remove_chan( audio
->chan
);
1030 free( audio
->exdata
);
1035 static int isom_add_text_entry( isom_stsd_t
*stsd
)
1037 if( !stsd
|| !stsd
->list
)
1039 isom_text_entry_t
*text
= malloc( sizeof(isom_text_entry_t
) );
1042 memset( text
, 0, sizeof(isom_text_entry_t
) );
1043 isom_init_box_common( text
, stsd
, QT_CODEC_TYPE_TEXT_TEXT
);
1044 text
->data_reference_index
= 1;
1045 if( lsmash_add_entry( stsd
->list
, text
) )
1053 int isom_add_ftab( isom_tx3g_entry_t
*tx3g
)
1057 isom_ftab_t
*ftab
= malloc( sizeof(isom_ftab_t
) );
1060 memset( ftab
, 0, sizeof(isom_ftab_t
) );
1061 isom_init_box_common( ftab
, tx3g
, ISOM_BOX_TYPE_FTAB
);
1062 ftab
->list
= lsmash_create_entry_list();
1072 static int isom_add_tx3g_entry( isom_stsd_t
*stsd
)
1074 if( !stsd
|| !stsd
->list
)
1076 isom_tx3g_entry_t
*tx3g
= malloc( sizeof(isom_tx3g_entry_t
) );
1079 memset( tx3g
, 0, sizeof(isom_tx3g_entry_t
) );
1080 isom_init_box_common( tx3g
, stsd
, ISOM_CODEC_TYPE_TX3G_TEXT
);
1081 tx3g
->data_reference_index
= 1;
1082 if( isom_add_ftab( tx3g
) ||
1083 lsmash_add_entry( stsd
->list
, tx3g
) )
1091 /* This function returns 0 if failed, sample_entry_number if succeeded. */
1092 int lsmash_add_sample_entry( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t sample_type
, void *summary
)
1094 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
1095 if( !trak
|| !trak
->root
|| !trak
->root
->ftyp
|| !trak
->mdia
|| !trak
->mdia
->minf
1096 || !trak
->mdia
->minf
->stbl
|| !trak
->mdia
->minf
->stbl
->stsd
|| !trak
->mdia
->minf
->stbl
->stsd
->list
)
1098 isom_stsd_t
*stsd
= trak
->mdia
->minf
->stbl
->stsd
;
1099 lsmash_entry_list_t
*list
= stsd
->list
;
1101 switch( sample_type
)
1103 case ISOM_CODEC_TYPE_AVC1_VIDEO
:
1105 case ISOM_CODEC_TYPE_AVC2_VIDEO
:
1106 case ISOM_CODEC_TYPE_AVCP_VIDEO
:
1107 case ISOM_CODEC_TYPE_SVC1_VIDEO
:
1108 case ISOM_CODEC_TYPE_MVC1_VIDEO
:
1109 case ISOM_CODEC_TYPE_MVC2_VIDEO
:
1110 case ISOM_CODEC_TYPE_MP4V_VIDEO
:
1111 case ISOM_CODEC_TYPE_DRAC_VIDEO
:
1112 case ISOM_CODEC_TYPE_ENCV_VIDEO
:
1113 case ISOM_CODEC_TYPE_MJP2_VIDEO
:
1114 case ISOM_CODEC_TYPE_S263_VIDEO
:
1115 case ISOM_CODEC_TYPE_VC_1_VIDEO
:
1117 ret
= isom_add_visual_entry( stsd
, sample_type
, (lsmash_video_summary_t
*)summary
);
1120 case ISOM_CODEC_TYPE_MP4S_SYSTEM
:
1121 ret
= isom_add_mp4s_entry( stsd
);
1124 case ISOM_CODEC_TYPE_MP4A_AUDIO
:
1125 case ISOM_CODEC_TYPE_AC_3_AUDIO
:
1126 case ISOM_CODEC_TYPE_ALAC_AUDIO
:
1127 case ISOM_CODEC_TYPE_SAMR_AUDIO
:
1128 case ISOM_CODEC_TYPE_SAWB_AUDIO
:
1129 case QT_CODEC_TYPE_23NI_AUDIO
:
1130 case QT_CODEC_TYPE_NONE_AUDIO
:
1131 case QT_CODEC_TYPE_LPCM_AUDIO
:
1132 case QT_CODEC_TYPE_RAW_AUDIO
:
1133 case QT_CODEC_TYPE_SOWT_AUDIO
:
1134 case QT_CODEC_TYPE_TWOS_AUDIO
:
1135 case QT_CODEC_TYPE_FL32_AUDIO
:
1136 case QT_CODEC_TYPE_FL64_AUDIO
:
1137 case QT_CODEC_TYPE_IN24_AUDIO
:
1138 case QT_CODEC_TYPE_IN32_AUDIO
:
1139 case QT_CODEC_TYPE_NOT_SPECIFIED
:
1141 case ISOM_CODEC_TYPE_DRA1_AUDIO
:
1142 case ISOM_CODEC_TYPE_DTSC_AUDIO
:
1143 case ISOM_CODEC_TYPE_DTSH_AUDIO
:
1144 case ISOM_CODEC_TYPE_DTSL_AUDIO
:
1145 case ISOM_CODEC_TYPE_EC_3_AUDIO
:
1146 case ISOM_CODEC_TYPE_ENCA_AUDIO
:
1147 case ISOM_CODEC_TYPE_G719_AUDIO
:
1148 case ISOM_CODEC_TYPE_G726_AUDIO
:
1149 case ISOM_CODEC_TYPE_M4AE_AUDIO
:
1150 case ISOM_CODEC_TYPE_MLPA_AUDIO
:
1151 case ISOM_CODEC_TYPE_RAW_AUDIO
:
1152 case ISOM_CODEC_TYPE_SAWP_AUDIO
:
1153 case ISOM_CODEC_TYPE_SEVC_AUDIO
:
1154 case ISOM_CODEC_TYPE_SQCP_AUDIO
:
1155 case ISOM_CODEC_TYPE_SSMV_AUDIO
:
1156 case ISOM_CODEC_TYPE_TWOS_AUDIO
:
1158 ret
= isom_add_audio_entry( stsd
, sample_type
, (lsmash_audio_summary_t
*)summary
);
1160 case ISOM_CODEC_TYPE_TX3G_TEXT
:
1161 ret
= isom_add_tx3g_entry( stsd
);
1163 case QT_CODEC_TYPE_TEXT_TEXT
:
1164 ret
= isom_add_text_entry( stsd
);
1169 return ret
? 0 : list
->entry_count
;
1172 static int isom_add_stts_entry( isom_stbl_t
*stbl
, uint32_t sample_delta
)
1174 if( !stbl
|| !stbl
->stts
|| !stbl
->stts
->list
)
1176 isom_stts_entry_t
*data
= malloc( sizeof(isom_stts_entry_t
) );
1179 data
->sample_count
= 1;
1180 data
->sample_delta
= sample_delta
;
1181 if( lsmash_add_entry( stbl
->stts
->list
, data
) )
1189 static int isom_add_ctts_entry( isom_stbl_t
*stbl
, uint32_t sample_offset
)
1191 if( !stbl
|| !stbl
->ctts
|| !stbl
->ctts
->list
)
1193 isom_ctts_entry_t
*data
= malloc( sizeof(isom_ctts_entry_t
) );
1196 data
->sample_count
= 1;
1197 data
->sample_offset
= sample_offset
;
1198 if( lsmash_add_entry( stbl
->ctts
->list
, data
) )
1206 static int isom_add_stsc_entry( isom_stbl_t
*stbl
, uint32_t first_chunk
, uint32_t samples_per_chunk
, uint32_t sample_description_index
)
1208 if( !stbl
|| !stbl
->stsc
|| !stbl
->stsc
->list
)
1210 isom_stsc_entry_t
*data
= malloc( sizeof(isom_stsc_entry_t
) );
1213 data
->first_chunk
= first_chunk
;
1214 data
->samples_per_chunk
= samples_per_chunk
;
1215 data
->sample_description_index
= sample_description_index
;
1216 if( lsmash_add_entry( stbl
->stsc
->list
, data
) )
1224 static int isom_add_stsz_entry( isom_stbl_t
*stbl
, uint32_t entry_size
)
1226 if( !stbl
|| !stbl
->stsz
)
1228 isom_stsz_t
*stsz
= stbl
->stsz
;
1229 /* retrieve initial sample_size */
1230 if( !stsz
->sample_count
)
1231 stsz
->sample_size
= entry_size
;
1232 /* if it seems constant access_unit size at present, update sample_count only */
1233 if( !stsz
->list
&& stsz
->sample_size
== entry_size
)
1235 ++ stsz
->sample_count
;
1238 /* found sample_size varies, create sample_size list */
1241 stsz
->list
= lsmash_create_entry_list();
1244 for( uint32_t i
= 0; i
< stsz
->sample_count
; i
++ )
1246 isom_stsz_entry_t
*data
= malloc( sizeof(isom_stsz_entry_t
) );
1249 data
->entry_size
= stsz
->sample_size
;
1250 if( lsmash_add_entry( stsz
->list
, data
) )
1256 stsz
->sample_size
= 0;
1258 isom_stsz_entry_t
*data
= malloc( sizeof(isom_stsz_entry_t
) );
1261 data
->entry_size
= entry_size
;
1262 if( lsmash_add_entry( stsz
->list
, data
) )
1267 ++ stsz
->sample_count
;
1271 static int isom_add_stss_entry( isom_stbl_t
*stbl
, uint32_t sample_number
)
1273 if( !stbl
|| !stbl
->stss
|| !stbl
->stss
->list
)
1275 isom_stss_entry_t
*data
= malloc( sizeof(isom_stss_entry_t
) );
1278 data
->sample_number
= sample_number
;
1279 if( lsmash_add_entry( stbl
->stss
->list
, data
) )
1287 static int isom_add_stps_entry( isom_stbl_t
*stbl
, uint32_t sample_number
)
1289 if( !stbl
|| !stbl
->stps
|| !stbl
->stps
->list
)
1291 isom_stps_entry_t
*data
= malloc( sizeof(isom_stps_entry_t
) );
1294 data
->sample_number
= sample_number
;
1295 if( lsmash_add_entry( stbl
->stps
->list
, data
) )
1303 static int isom_add_sdtp_entry( isom_stbl_t
*stbl
, lsmash_sample_property_t
*prop
, uint8_t avc_extensions
)
1307 if( !stbl
|| !stbl
->sdtp
|| !stbl
->sdtp
->list
)
1309 isom_sdtp_entry_t
*data
= malloc( sizeof(isom_sdtp_entry_t
) );
1312 /* isom_sdtp_entry_t is smaller than lsmash_sample_property_t. */
1313 data
->is_leading
= (avc_extensions
? prop
->leading
: prop
->allow_earlier
) & 0x03;
1314 data
->sample_depends_on
= prop
->independent
& 0x03;
1315 data
->sample_is_depended_on
= prop
->disposable
& 0x03;
1316 data
->sample_has_redundancy
= prop
->redundant
& 0x03;
1317 if( lsmash_add_entry( stbl
->sdtp
->list
, data
) )
1325 static int isom_add_co64( isom_stbl_t
*stbl
)
1327 if( !stbl
|| stbl
->stco
)
1329 isom_create_list_box( stco
, stbl
, ISOM_BOX_TYPE_CO64
);
1330 stco
->large_presentation
= 1;
1335 static int isom_add_stco( isom_stbl_t
*stbl
)
1337 if( !stbl
|| stbl
->stco
)
1339 isom_create_list_box( stco
, stbl
, ISOM_BOX_TYPE_STCO
);
1340 stco
->large_presentation
= 0;
1345 static int isom_add_co64_entry( isom_stbl_t
*stbl
, uint64_t chunk_offset
)
1347 if( !stbl
|| !stbl
->stco
|| !stbl
->stco
->list
)
1349 isom_co64_entry_t
*data
= malloc( sizeof(isom_co64_entry_t
) );
1352 data
->chunk_offset
= chunk_offset
;
1353 if( lsmash_add_entry( stbl
->stco
->list
, data
) )
1361 static int isom_convert_stco_to_co64( isom_stbl_t
* stbl
)
1364 isom_stco_t
*stco
= stbl
->stco
;
1366 if( isom_add_co64( stbl
) )
1368 /* move chunk_offset to co64 from stco */
1369 for( lsmash_entry_t
*entry
= stco
->list
->head
; entry
; entry
= entry
->next
)
1371 isom_stco_entry_t
*data
= (isom_stco_entry_t
*)entry
->data
;
1372 if( isom_add_co64_entry( stbl
, data
->chunk_offset
) )
1375 lsmash_remove_list( stco
->list
, NULL
);
1380 static int isom_add_stco_entry( isom_stbl_t
*stbl
, uint64_t chunk_offset
)
1382 if( !stbl
|| !stbl
->stco
|| !stbl
->stco
->list
)
1384 if( stbl
->stco
->large_presentation
)
1385 return isom_add_co64_entry( stbl
, chunk_offset
);
1386 if( chunk_offset
> UINT32_MAX
)
1388 if( isom_convert_stco_to_co64( stbl
) )
1390 return isom_add_co64_entry( stbl
, chunk_offset
);
1392 isom_stco_entry_t
*data
= malloc( sizeof(isom_stco_entry_t
) );
1395 data
->chunk_offset
= (uint32_t)chunk_offset
;
1396 if( lsmash_add_entry( stbl
->stco
->list
, data
) )
1404 isom_sgpd_entry_t
*isom_get_sample_group_description( isom_stbl_t
*stbl
, uint32_t grouping_type
)
1406 if( !stbl
->sgpd_list
)
1408 for( lsmash_entry_t
*entry
= stbl
->sgpd_list
->head
; entry
; entry
= entry
->next
)
1410 isom_sgpd_entry_t
*sgpd
= (isom_sgpd_entry_t
*)entry
->data
;
1411 if( !sgpd
|| !sgpd
->list
)
1413 if( sgpd
->grouping_type
== grouping_type
)
1419 isom_sbgp_entry_t
*isom_get_sample_to_group( isom_stbl_t
*stbl
, uint32_t grouping_type
)
1421 if( !stbl
->sbgp_list
)
1423 for( lsmash_entry_t
*entry
= stbl
->sbgp_list
->head
; entry
; entry
= entry
->next
)
1425 isom_sbgp_entry_t
*sbgp
= (isom_sbgp_entry_t
*)entry
->data
;
1426 if( !sbgp
|| !sbgp
->list
)
1428 if( sbgp
->grouping_type
== grouping_type
)
1434 static isom_rap_entry_t
*isom_add_rap_group_entry( isom_sgpd_entry_t
*sgpd
)
1438 isom_rap_entry_t
*data
= malloc( sizeof(isom_rap_entry_t
) );
1441 memset( data
, 0, sizeof(isom_rap_entry_t
) );
1442 if( lsmash_add_entry( sgpd
->list
, data
) )
1450 static isom_roll_entry_t
*isom_add_roll_group_entry( isom_sgpd_entry_t
*sgpd
, int16_t roll_distance
)
1454 isom_roll_entry_t
*data
= malloc( sizeof(isom_roll_entry_t
) );
1457 data
->description_length
= 0;
1458 data
->roll_distance
= roll_distance
;
1459 if( lsmash_add_entry( sgpd
->list
, data
) )
1467 static isom_group_assignment_entry_t
*isom_add_group_assignment_entry( isom_sbgp_entry_t
*sbgp
, uint32_t sample_count
, uint32_t group_description_index
)
1471 isom_group_assignment_entry_t
*data
= malloc( sizeof(isom_group_assignment_entry_t
) );
1474 data
->sample_count
= sample_count
;
1475 data
->group_description_index
= group_description_index
;
1476 if( lsmash_add_entry( sbgp
->list
, data
) )
1484 static int isom_add_chpl_entry( isom_chpl_t
*chpl
, isom_chapter_entry_t
*chap_data
)
1486 if( !chap_data
->chapter_name
|| !chpl
|| !chpl
->list
)
1488 isom_chpl_entry_t
*data
= malloc( sizeof(isom_chpl_entry_t
) );
1491 data
->start_time
= chap_data
->start_time
;
1492 data
->chapter_name_length
= strlen( chap_data
->chapter_name
);
1493 data
->chapter_name
= ( char* )malloc( data
->chapter_name_length
+ 1 );
1494 if( !data
->chapter_name
)
1499 memcpy( data
->chapter_name
, chap_data
->chapter_name
, data
->chapter_name_length
);
1500 data
->chapter_name
[data
->chapter_name_length
] = '\0';
1501 if( lsmash_add_entry( chpl
->list
, data
) )
1503 free( data
->chapter_name
);
1510 static isom_trex_entry_t
*isom_add_trex( isom_mvex_t
*mvex
)
1514 if( !mvex
->trex_list
)
1516 mvex
->trex_list
= lsmash_create_entry_list();
1517 if( !mvex
->trex_list
)
1520 isom_trex_entry_t
*trex
= malloc( sizeof(isom_trex_entry_t
) );
1523 memset( trex
, 0, sizeof(isom_trex_entry_t
) );
1524 isom_init_box_common( trex
, mvex
, ISOM_BOX_TYPE_TREX
);
1525 if( lsmash_add_entry( mvex
->trex_list
, trex
) )
1533 static isom_trun_entry_t
*isom_add_trun( isom_traf_entry_t
*traf
)
1537 if( !traf
->trun_list
)
1539 traf
->trun_list
= lsmash_create_entry_list();
1540 if( !traf
->trun_list
)
1543 isom_trun_entry_t
*trun
= malloc( sizeof(isom_trun_entry_t
) );
1546 memset( trun
, 0, sizeof(isom_trun_entry_t
) );
1547 isom_init_box_common( trun
, traf
, ISOM_BOX_TYPE_TRUN
);
1548 if( lsmash_add_entry( traf
->trun_list
, trun
) )
1556 static isom_traf_entry_t
*isom_add_traf( lsmash_root_t
*root
, isom_moof_entry_t
*moof
)
1558 if( !root
|| !root
->moof_list
|| !moof
)
1560 if( !moof
->traf_list
)
1562 moof
->traf_list
= lsmash_create_entry_list();
1563 if( !moof
->traf_list
)
1566 isom_traf_entry_t
*traf
= malloc( sizeof(isom_traf_entry_t
) );
1569 memset( traf
, 0, sizeof(isom_traf_entry_t
) );
1570 isom_init_box_common( traf
, moof
, ISOM_BOX_TYPE_TRAF
);
1571 isom_cache_t
*cache
= malloc( sizeof(isom_cache_t
) );
1577 memset( cache
, 0, sizeof(isom_cache_t
) );
1578 if( lsmash_add_entry( moof
->traf_list
, traf
) )
1584 traf
->cache
= cache
;
1588 static isom_moof_entry_t
*isom_add_moof( lsmash_root_t
*root
)
1592 if( !root
->moof_list
)
1594 root
->moof_list
= lsmash_create_entry_list();
1595 if( !root
->moof_list
)
1598 isom_moof_entry_t
*moof
= malloc( sizeof(isom_moof_entry_t
) );
1601 memset( moof
, 0, sizeof(isom_moof_entry_t
) );
1602 isom_init_box_common( moof
, root
, ISOM_BOX_TYPE_MOOF
);
1603 if( lsmash_add_entry( root
->moof_list
, moof
) )
1611 static isom_tfra_entry_t
*isom_add_tfra( isom_mfra_t
*mfra
)
1615 if( !mfra
->tfra_list
)
1617 mfra
->tfra_list
= lsmash_create_entry_list();
1618 if( !mfra
->tfra_list
)
1621 isom_tfra_entry_t
*tfra
= malloc( sizeof(isom_tfra_entry_t
) );
1624 memset( tfra
, 0, sizeof(isom_tfra_entry_t
) );
1625 isom_init_box_common( tfra
, mfra
, ISOM_BOX_TYPE_TFRA
);
1626 if( lsmash_add_entry( mfra
->tfra_list
, tfra
) )
1634 static int isom_add_ftyp( lsmash_root_t
*root
)
1638 isom_create_box( ftyp
, root
, ISOM_BOX_TYPE_FTYP
);
1639 ftyp
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
+ 8;
1644 static int isom_add_moov( lsmash_root_t
*root
)
1648 isom_create_box( moov
, root
, ISOM_BOX_TYPE_MOOV
);
1653 static int isom_add_mvhd( isom_moov_t
*moov
)
1655 if( !moov
|| moov
->mvhd
)
1657 isom_create_box( mvhd
, moov
, ISOM_BOX_TYPE_MVHD
);
1658 mvhd
->rate
= 0x00010000;
1659 mvhd
->volume
= 0x0100;
1660 mvhd
->matrix
[0] = 0x00010000;
1661 mvhd
->matrix
[4] = 0x00010000;
1662 mvhd
->matrix
[8] = 0x40000000;
1663 mvhd
->next_track_ID
= 1;
1668 static int isom_scan_trak_profileLevelIndication( isom_trak_entry_t
* trak
, mp4a_audioProfileLevelIndication
* audio_pli
, mp4sys_visualProfileLevelIndication
* visual_pli
)
1670 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
)
1672 isom_stsd_t
* stsd
= trak
->mdia
->minf
->stbl
->stsd
;
1673 if( !stsd
|| !stsd
->list
|| !stsd
->list
->head
)
1675 for( lsmash_entry_t
*entry
= stsd
->list
->head
; entry
; entry
= entry
->next
)
1677 isom_sample_entry_t
* sample_entry
= (isom_sample_entry_t
*)entry
->data
;
1680 switch( sample_entry
->type
)
1682 case ISOM_CODEC_TYPE_AVC1_VIDEO
:
1684 case ISOM_CODEC_TYPE_AVC2_VIDEO
:
1685 case ISOM_CODEC_TYPE_AVCP_VIDEO
:
1686 case ISOM_CODEC_TYPE_SVC1_VIDEO
:
1687 case ISOM_CODEC_TYPE_MVC1_VIDEO
:
1688 case ISOM_CODEC_TYPE_MVC2_VIDEO
:
1690 /* FIXME: Do we have to arbitrate like audio? */
1691 if( *visual_pli
== MP4SYS_VISUAL_PLI_NONE_REQUIRED
)
1692 *visual_pli
= MP4SYS_VISUAL_PLI_H264_AVC
;
1694 case ISOM_CODEC_TYPE_MP4A_AUDIO
:
1695 *audio_pli
= mp4a_max_audioProfileLevelIndication( *audio_pli
, mp4a_get_audioProfileLevelIndication( &((isom_audio_entry_t
*)sample_entry
)->summary
) );
1698 case ISOM_CODEC_TYPE_DRAC_VIDEO
:
1699 case ISOM_CODEC_TYPE_ENCV_VIDEO
:
1700 case ISOM_CODEC_TYPE_MJP2_VIDEO
:
1701 case ISOM_CODEC_TYPE_S263_VIDEO
:
1702 case ISOM_CODEC_TYPE_VC_1_VIDEO
:
1703 /* FIXME: Do we have to arbitrate like audio? */
1704 if( *visual_pli
== MP4SYS_VISUAL_PLI_NONE_REQUIRED
)
1705 *visual_pli
= MP4SYS_VISUAL_PLI_NOT_SPECIFIED
;
1708 case ISOM_CODEC_TYPE_AC_3_AUDIO
:
1709 case ISOM_CODEC_TYPE_ALAC_AUDIO
:
1710 case ISOM_CODEC_TYPE_SAMR_AUDIO
:
1711 case ISOM_CODEC_TYPE_SAWB_AUDIO
:
1712 #ifdef LSMASH_DEMUXER_ENABLED
1713 case ISOM_CODEC_TYPE_EC_3_AUDIO
:
1716 case ISOM_CODEC_TYPE_DRA1_AUDIO
:
1717 case ISOM_CODEC_TYPE_DTSC_AUDIO
:
1718 case ISOM_CODEC_TYPE_DTSH_AUDIO
:
1719 case ISOM_CODEC_TYPE_DTSL_AUDIO
:
1720 case ISOM_CODEC_TYPE_ENCA_AUDIO
:
1721 case ISOM_CODEC_TYPE_G719_AUDIO
:
1722 case ISOM_CODEC_TYPE_G726_AUDIO
:
1723 case ISOM_CODEC_TYPE_M4AE_AUDIO
:
1724 case ISOM_CODEC_TYPE_MLPA_AUDIO
:
1725 case ISOM_CODEC_TYPE_RAW_AUDIO
:
1726 case ISOM_CODEC_TYPE_SAWP_AUDIO
:
1727 case ISOM_CODEC_TYPE_SEVC_AUDIO
:
1728 case ISOM_CODEC_TYPE_SQCP_AUDIO
:
1729 case ISOM_CODEC_TYPE_SSMV_AUDIO
:
1730 case ISOM_CODEC_TYPE_TWOS_AUDIO
:
1732 /* NOTE: These audio codecs other than mp4a does not have appropriate pli. */
1733 *audio_pli
= MP4A_AUDIO_PLI_NOT_SPECIFIED
;
1736 case ISOM_CODEC_TYPE_FDP_HINT
:
1737 case ISOM_CODEC_TYPE_M2TS_HINT
:
1738 case ISOM_CODEC_TYPE_PM2T_HINT
:
1739 case ISOM_CODEC_TYPE_PRTP_HINT
:
1740 case ISOM_CODEC_TYPE_RM2T_HINT
:
1741 case ISOM_CODEC_TYPE_RRTP_HINT
:
1742 case ISOM_CODEC_TYPE_RSRP_HINT
:
1743 case ISOM_CODEC_TYPE_RTP_HINT
:
1744 case ISOM_CODEC_TYPE_SM2T_HINT
:
1745 case ISOM_CODEC_TYPE_SRTP_HINT
:
1746 /* FIXME: Do we have to set OD_profileLevelIndication? */
1748 case ISOM_CODEC_TYPE_IXSE_META
:
1749 case ISOM_CODEC_TYPE_METT_META
:
1750 case ISOM_CODEC_TYPE_METX_META
:
1751 case ISOM_CODEC_TYPE_MLIX_META
:
1752 case ISOM_CODEC_TYPE_OKSD_META
:
1753 case ISOM_CODEC_TYPE_SVCM_META
:
1754 case ISOM_CODEC_TYPE_TEXT_META
:
1755 case ISOM_CODEC_TYPE_URIM_META
:
1756 case ISOM_CODEC_TYPE_XML_META
:
1757 /* FIXME: Do we have to set OD_profileLevelIndication? */
1765 static int isom_add_iods( isom_moov_t
*moov
)
1767 if( !moov
|| !moov
->trak_list
|| moov
->iods
)
1769 isom_create_box( iods
, moov
, ISOM_BOX_TYPE_IODS
);
1770 iods
->OD
= mp4sys_create_ObjectDescriptor( 1 ); /* NOTE: Use 1 for ObjectDescriptorID of IOD. */
1776 mp4a_audioProfileLevelIndication audio_pli
= MP4A_AUDIO_PLI_NONE_REQUIRED
;
1777 mp4sys_visualProfileLevelIndication visual_pli
= MP4SYS_VISUAL_PLI_NONE_REQUIRED
;
1778 for( lsmash_entry_t
*entry
= moov
->trak_list
->head
; entry
; entry
= entry
->next
)
1780 isom_trak_entry_t
* trak
= (isom_trak_entry_t
*)entry
->data
;
1781 if( !trak
|| !trak
->tkhd
)
1783 if( isom_scan_trak_profileLevelIndication( trak
, &audio_pli
, &visual_pli
) )
1785 if( mp4sys_add_ES_ID_Inc( iods
->OD
, trak
->tkhd
->track_ID
) )
1788 if( mp4sys_to_InitialObjectDescriptor( iods
->OD
,
1789 0, /* FIXME: I'm not quite sure what the spec says. */
1790 MP4SYS_OD_PLI_NONE_REQUIRED
, MP4SYS_SCENE_PLI_NONE_REQUIRED
,
1791 audio_pli
, visual_pli
,
1792 MP4SYS_GRAPHICS_PLI_NONE_REQUIRED
) )
1801 static int isom_add_tkhd( isom_trak_entry_t
*trak
, uint32_t handler_type
)
1803 if( !trak
|| !trak
->root
|| !trak
->root
->moov
|| !trak
->root
->moov
->mvhd
|| !trak
->root
->moov
->trak_list
)
1807 isom_create_box( tkhd
, trak
, ISOM_BOX_TYPE_TKHD
);
1808 switch( handler_type
)
1810 case ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK
:
1811 tkhd
->matrix
[0] = 0x00010000;
1812 tkhd
->matrix
[4] = 0x00010000;
1813 tkhd
->matrix
[8] = 0x40000000;
1815 case ISOM_MEDIA_HANDLER_TYPE_AUDIO_TRACK
:
1816 tkhd
->volume
= 0x0100;
1821 tkhd
->duration
= 0xffffffff;
1822 tkhd
->track_ID
= trak
->root
->moov
->mvhd
->next_track_ID
;
1823 ++ trak
->root
->moov
->mvhd
->next_track_ID
;
1829 static int isom_add_clef( isom_tapt_t
*tapt
)
1833 isom_create_box( clef
, tapt
, QT_BOX_TYPE_CLEF
);
1838 static int isom_add_prof( isom_tapt_t
*tapt
)
1842 isom_create_box( prof
, tapt
, QT_BOX_TYPE_PROF
);
1847 static int isom_add_enof( isom_tapt_t
*tapt
)
1851 isom_create_box( enof
, tapt
, QT_BOX_TYPE_ENOF
);
1856 static int isom_add_tapt( isom_trak_entry_t
*trak
)
1860 isom_create_box( tapt
, trak
, QT_BOX_TYPE_TAPT
);
1865 int isom_add_elst( isom_edts_t
*edts
)
1869 isom_create_list_box( elst
, edts
, ISOM_BOX_TYPE_ELST
);
1874 int isom_add_edts( isom_trak_entry_t
*trak
)
1878 isom_create_box( edts
, trak
, ISOM_BOX_TYPE_EDTS
);
1883 static int isom_add_tref( isom_trak_entry_t
*trak
)
1887 isom_create_box( tref
, trak
, ISOM_BOX_TYPE_TREF
);
1888 tref
->ref_list
= lsmash_create_entry_list();
1889 if( !tref
->ref_list
)
1898 static int isom_add_mdhd( isom_mdia_t
*mdia
, uint16_t default_language
)
1900 if( !mdia
|| mdia
->mdhd
)
1902 isom_create_box( mdhd
, mdia
, ISOM_BOX_TYPE_MDHD
);
1903 mdhd
->language
= default_language
;
1908 static int isom_add_mdia( isom_trak_entry_t
*trak
)
1910 if( !trak
|| trak
->mdia
)
1912 isom_create_box( mdia
, trak
, ISOM_BOX_TYPE_MDIA
);
1917 static int isom_add_hdlr( isom_mdia_t
*mdia
, isom_minf_t
*minf
, uint32_t media_type
)
1919 if( (!mdia
&& !minf
) || (mdia
&& minf
) )
1920 return -1; /* Either one must be given. */
1921 if( (mdia
&& mdia
->hdlr
) || (minf
&& minf
->hdlr
) )
1922 return -1; /* Selected one must not have hdlr yet. */
1923 isom_box_t
*parent
= mdia
? (isom_box_t
*)mdia
: (isom_box_t
*)minf
;
1924 isom_create_box( hdlr
, parent
, ISOM_BOX_TYPE_HDLR
);
1925 lsmash_root_t
*root
= hdlr
->root
;
1926 uint32_t type
= mdia
? (root
->qt_compatible
? QT_HANDLER_TYPE_MEDIA
: 0) : QT_HANDLER_TYPE_DATA
;
1927 uint32_t subtype
= media_type
;
1928 hdlr
->componentType
= type
;
1929 hdlr
->componentSubtype
= subtype
;
1930 char *type_name
= NULL
;
1931 char *subtype_name
= NULL
;
1932 uint8_t type_name_length
= 0;
1933 uint8_t subtype_name_length
= 0;
1936 case QT_HANDLER_TYPE_DATA
:
1937 type_name
= "Data ";
1938 type_name_length
= 5;
1941 type_name
= "Media ";
1942 type_name_length
= 6;
1947 case ISOM_MEDIA_HANDLER_TYPE_AUDIO_TRACK
:
1948 subtype_name
= "Sound ";
1949 subtype_name_length
= 6;
1951 case ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK
:
1952 subtype_name
= "Video ";
1953 subtype_name_length
= 6;
1955 case ISOM_MEDIA_HANDLER_TYPE_HINT_TRACK
:
1956 subtype_name
= "Hint ";
1957 subtype_name_length
= 5;
1959 case ISOM_MEDIA_HANDLER_TYPE_TIMED_METADATA_TRACK
:
1960 subtype_name
= "Meta ";
1961 subtype_name_length
= 5;
1963 case ISOM_MEDIA_HANDLER_TYPE_TEXT_TRACK
:
1964 subtype_name
= "Text ";
1965 subtype_name_length
= 5;
1967 case QT_REFERENCE_HANDLER_TYPE_ALIAS
:
1968 subtype_name
= "Alias ";
1969 subtype_name_length
= 6;
1971 case QT_REFERENCE_HANDLER_TYPE_RESOURCE
:
1972 subtype_name
= "Resource ";
1973 subtype_name_length
= 9;
1975 case QT_REFERENCE_HANDLER_TYPE_URL
:
1976 subtype_name
= "URL ";
1977 subtype_name_length
= 4;
1980 subtype_name
= "Unknown ";
1981 subtype_name_length
= 8;
1984 uint32_t name_length
= 15 + subtype_name_length
+ type_name_length
+ root
->isom_compatible
+ root
->qt_compatible
;
1985 uint8_t *name
= malloc( name_length
);
1988 if( root
->qt_compatible
)
1989 name
[0] = name_length
& 0xff;
1990 memcpy( name
+ root
->qt_compatible
, "L-SMASH ", 8 );
1991 memcpy( name
+ root
->qt_compatible
+ 8, subtype_name
, subtype_name_length
);
1992 memcpy( name
+ root
->qt_compatible
+ 8 + subtype_name_length
, type_name
, type_name_length
);
1993 memcpy( name
+ root
->qt_compatible
+ 8 + subtype_name_length
+ type_name_length
, "Handler", 7 );
1994 if( root
->isom_compatible
)
1995 name
[name_length
- 1] = 0;
1996 hdlr
->componentName
= name
;
1997 hdlr
->componentName_length
= name_length
;
2005 static int isom_add_minf( isom_mdia_t
*mdia
)
2007 if( !mdia
|| mdia
->minf
)
2009 isom_create_box( minf
, mdia
, ISOM_BOX_TYPE_MINF
);
2014 static int isom_add_vmhd( isom_minf_t
*minf
)
2016 if( !minf
|| minf
->vmhd
)
2018 isom_create_box( vmhd
, minf
, ISOM_BOX_TYPE_VMHD
);
2019 vmhd
->flags
= 0x000001;
2024 static int isom_add_smhd( isom_minf_t
*minf
)
2026 if( !minf
|| minf
->smhd
)
2028 isom_create_box( smhd
, minf
, ISOM_BOX_TYPE_SMHD
);
2033 static int isom_add_hmhd( isom_minf_t
*minf
)
2035 if( !minf
|| minf
->hmhd
)
2037 isom_create_box( hmhd
, minf
, ISOM_BOX_TYPE_HMHD
);
2042 static int isom_add_nmhd( isom_minf_t
*minf
)
2044 if( !minf
|| minf
->nmhd
)
2046 isom_create_box( nmhd
, minf
, ISOM_BOX_TYPE_NMHD
);
2051 static int isom_add_gmin( isom_gmhd_t
*gmhd
)
2053 if( !gmhd
|| gmhd
->gmin
)
2055 isom_create_box( gmin
, gmhd
, QT_BOX_TYPE_GMIN
);
2060 static int isom_add_text( isom_gmhd_t
*gmhd
)
2062 if( !gmhd
|| gmhd
->text
)
2064 isom_create_box( text
, gmhd
, QT_BOX_TYPE_TEXT
);
2065 text
->matrix
[0] = 0x00010000;
2066 text
->matrix
[4] = 0x00010000;
2067 text
->matrix
[8] = 0x40000000;
2072 static int isom_add_gmhd( isom_minf_t
*minf
)
2074 if( !minf
|| minf
->gmhd
)
2076 isom_create_box( gmhd
, minf
, QT_BOX_TYPE_GMHD
);
2081 static int isom_add_dinf( isom_minf_t
*minf
)
2083 if( !minf
|| minf
->dinf
)
2085 isom_create_box( dinf
, minf
, ISOM_BOX_TYPE_DINF
);
2090 static int isom_add_dref( isom_dinf_t
*dinf
)
2092 if( !dinf
|| dinf
->dref
)
2094 isom_create_list_box( dref
, dinf
, ISOM_BOX_TYPE_DREF
);
2096 if( isom_add_dref_entry( dref
, 0x000001, NULL
, NULL
) )
2101 static int isom_add_stsd( isom_stbl_t
*stbl
)
2103 if( !stbl
|| stbl
->stsd
)
2105 isom_create_list_box( stsd
, stbl
, ISOM_BOX_TYPE_STSD
);
2110 int isom_add_btrt( isom_visual_entry_t
*visual
)
2112 if( !visual
|| visual
->btrt
)
2114 isom_create_box( btrt
, visual
, ISOM_BOX_TYPE_BTRT
);
2115 visual
->btrt
= btrt
;
2119 int lsmash_add_btrt( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t entry_number
)
2121 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
2122 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
|| !trak
->mdia
->minf
->stbl
->stsd
|| !trak
->mdia
->minf
->stbl
->stsd
->list
)
2124 isom_visual_entry_t
*data
= (isom_visual_entry_t
*)lsmash_get_entry_data( trak
->mdia
->minf
->stbl
->stsd
->list
, entry_number
);
2125 return isom_add_btrt( data
);
2128 static int isom_add_stts( isom_stbl_t
*stbl
)
2130 if( !stbl
|| stbl
->stts
)
2132 isom_create_list_box( stts
, stbl
, ISOM_BOX_TYPE_STTS
);
2137 static int isom_add_ctts( isom_stbl_t
*stbl
)
2139 if( !stbl
|| stbl
->ctts
)
2141 isom_create_list_box( ctts
, stbl
, ISOM_BOX_TYPE_CTTS
);
2146 static int isom_add_cslg( isom_stbl_t
*stbl
)
2148 if( !stbl
|| stbl
->cslg
)
2150 isom_create_box( cslg
, stbl
, ISOM_BOX_TYPE_CSLG
);
2155 static int isom_add_stsc( isom_stbl_t
*stbl
)
2157 if( !stbl
|| stbl
->stsc
)
2159 isom_create_list_box( stsc
, stbl
, ISOM_BOX_TYPE_STSC
);
2164 static int isom_add_stsz( isom_stbl_t
*stbl
)
2166 if( !stbl
|| stbl
->stsz
)
2168 isom_create_box( stsz
, stbl
, ISOM_BOX_TYPE_STSZ
); /* We don't create a list here. */
2173 static int isom_add_stss( isom_stbl_t
*stbl
)
2175 if( !stbl
|| stbl
->stss
)
2177 isom_create_list_box( stss
, stbl
, ISOM_BOX_TYPE_STSS
);
2182 static int isom_add_stps( isom_stbl_t
*stbl
)
2184 if( !stbl
|| stbl
->stps
)
2186 isom_create_list_box( stps
, stbl
, QT_BOX_TYPE_STPS
);
2191 static int isom_add_sdtp( isom_stbl_t
*stbl
)
2193 if( !stbl
|| stbl
->sdtp
)
2195 isom_create_list_box( sdtp
, stbl
, ISOM_BOX_TYPE_SDTP
);
2200 static isom_sgpd_entry_t
*isom_add_sgpd( isom_stbl_t
*stbl
, uint32_t grouping_type
)
2204 if( !stbl
->sgpd_list
)
2206 stbl
->sgpd_list
= lsmash_create_entry_list();
2207 if( !stbl
->sgpd_list
)
2210 isom_sgpd_entry_t
*sgpd
= malloc( sizeof(isom_sgpd_entry_t
) );
2213 memset( sgpd
, 0, sizeof(isom_sgpd_entry_t
) );
2214 isom_init_box_common( sgpd
, stbl
, ISOM_BOX_TYPE_SGPD
);
2215 sgpd
->list
= lsmash_create_entry_list();
2216 if( !sgpd
->list
|| lsmash_add_entry( stbl
->sgpd_list
, sgpd
) )
2221 sgpd
->grouping_type
= grouping_type
;
2222 sgpd
->version
= 1; /* We use version 1 because it is recommended in the spec. */
2223 switch( grouping_type
)
2225 case ISOM_GROUP_TYPE_RAP
:
2226 sgpd
->default_length
= 1;
2228 case ISOM_GROUP_TYPE_ROLL
:
2229 sgpd
->default_length
= 2;
2232 /* We don't consider other grouping types currently. */
2238 static isom_sbgp_entry_t
*isom_add_sbgp( isom_stbl_t
*stbl
, uint32_t grouping_type
)
2242 if( !stbl
->sbgp_list
)
2244 stbl
->sbgp_list
= lsmash_create_entry_list();
2245 if( !stbl
->sbgp_list
)
2248 isom_sbgp_entry_t
*sbgp
= malloc( sizeof(isom_sbgp_entry_t
) );
2251 memset( sbgp
, 0, sizeof(isom_sbgp_entry_t
) );
2252 isom_init_box_common( sbgp
, stbl
, ISOM_BOX_TYPE_SBGP
);
2253 sbgp
->list
= lsmash_create_entry_list();
2254 if( !sbgp
->list
|| lsmash_add_entry( stbl
->sbgp_list
, sbgp
) )
2259 sbgp
->grouping_type
= grouping_type
;
2263 static int isom_add_stbl( isom_minf_t
*minf
)
2265 if( !minf
|| minf
->stbl
)
2267 isom_create_box( stbl
, minf
, ISOM_BOX_TYPE_STBL
);
2272 static int isom_add_chpl( isom_moov_t
*moov
)
2274 if( !moov
|| !moov
->udta
|| moov
->udta
->chpl
)
2276 isom_create_list_box( chpl
, moov
, ISOM_BOX_TYPE_CHPL
);
2277 chpl
->version
= 1; /* version = 1 is popular. */
2278 moov
->udta
->chpl
= chpl
;
2282 static int isom_add_udta( lsmash_root_t
*root
, uint32_t track_ID
)
2284 /* track_ID == 0 means the direct addition to moov box */
2287 if( !root
|| !root
->moov
)
2289 if( root
->moov
->udta
)
2291 isom_create_box( udta
, root
->moov
, ISOM_BOX_TYPE_UDTA
);
2292 root
->moov
->udta
= udta
;
2295 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
2300 isom_create_box( udta
, trak
, ISOM_BOX_TYPE_UDTA
);
2305 static isom_trak_entry_t
*isom_add_trak( lsmash_root_t
*root
)
2307 if( !root
|| !root
->moov
)
2309 isom_moov_t
*moov
= root
->moov
;
2310 if( !moov
->trak_list
)
2312 moov
->trak_list
= lsmash_create_entry_list();
2313 if( !moov
->trak_list
)
2316 isom_trak_entry_t
*trak
= malloc( sizeof(isom_trak_entry_t
) );
2319 memset( trak
, 0, sizeof(isom_trak_entry_t
) );
2320 isom_init_box_common( trak
, moov
, ISOM_BOX_TYPE_TRAK
);
2321 isom_cache_t
*cache
= malloc( sizeof(isom_cache_t
) );
2327 memset( cache
, 0, sizeof(isom_cache_t
) );
2328 isom_fragment_t
*fragment
= NULL
;
2329 if( root
->fragment
)
2331 fragment
= malloc( sizeof(isom_fragment_t
) );
2338 memset( fragment
, 0, sizeof(isom_fragment_t
) );
2339 cache
->fragment
= fragment
;
2341 if( lsmash_add_entry( moov
->trak_list
, trak
) )
2349 trak
->cache
= cache
;
2353 static int isom_add_mvex( isom_moov_t
*moov
)
2355 if( !moov
|| moov
->mvex
)
2357 isom_create_box( mvex
, moov
, ISOM_BOX_TYPE_MVEX
);
2362 static int isom_add_mehd( isom_mvex_t
*mvex
)
2364 if( !mvex
|| mvex
->mehd
)
2366 isom_create_box( mehd
, mvex
, ISOM_BOX_TYPE_MEHD
);
2371 static int isom_add_tfhd( isom_traf_entry_t
*traf
)
2373 if( !traf
|| traf
->tfhd
)
2375 isom_create_box( tfhd
, traf
, ISOM_BOX_TYPE_TFHD
);
2380 static int isom_add_mfhd( isom_moof_entry_t
*moof
)
2382 if( !moof
|| moof
->mfhd
)
2384 isom_create_box( mfhd
, moof
, ISOM_BOX_TYPE_MFHD
);
2389 static int isom_add_mfra( lsmash_root_t
*root
)
2391 if( !root
|| root
->mfra
)
2393 isom_create_box( mfra
, root
, ISOM_BOX_TYPE_MFRA
);
2398 static int isom_add_mfro( isom_mfra_t
*mfra
)
2400 if( !mfra
|| mfra
->mfro
)
2402 isom_create_box( mfro
, mfra
, ISOM_BOX_TYPE_MFRO
);
2407 #define isom_remove_box( box_name, parent_type ) \
2410 parent_type *parent = (parent_type *)box_name->parent; \
2413 parent->box_name = NULL; \
2416 static void isom_remove_ftyp( isom_ftyp_t
*ftyp
)
2420 if( ftyp
->compatible_brands
)
2421 free( ftyp
->compatible_brands
);
2422 isom_remove_box( ftyp
, lsmash_root_t
);
2425 static void isom_remove_tkhd( isom_tkhd_t
*tkhd
)
2429 isom_remove_box( tkhd
, isom_trak_entry_t
);
2432 static void isom_remove_clef( isom_clef_t
*clef
)
2436 isom_remove_box( clef
, isom_tapt_t
);
2439 static void isom_remove_prof( isom_prof_t
*prof
)
2443 isom_remove_box( prof
, isom_tapt_t
);
2446 static void isom_remove_enof( isom_enof_t
*enof
)
2450 isom_remove_box( enof
, isom_tapt_t
);
2453 void isom_remove_tapt( isom_tapt_t
*tapt
)
2457 isom_remove_clef( tapt
->clef
);
2458 isom_remove_prof( tapt
->prof
);
2459 isom_remove_enof( tapt
->enof
);
2460 isom_remove_box( tapt
, isom_trak_entry_t
);
2463 static void isom_remove_elst( isom_elst_t
*elst
)
2467 lsmash_remove_list( elst
->list
, NULL
);
2468 isom_remove_box( elst
, isom_edts_t
);
2471 static void isom_remove_edts( isom_edts_t
*edts
)
2475 isom_remove_elst( edts
->elst
);
2476 isom_remove_box( edts
, isom_trak_entry_t
);
2479 static void isom_remove_track_reference_type( isom_tref_type_t
*ref
)
2484 free( ref
->track_ID
);
2488 static void isom_remove_tref( isom_tref_t
*tref
)
2492 lsmash_remove_list( tref
->ref_list
, isom_remove_track_reference_type
);
2493 isom_remove_box( tref
, isom_trak_entry_t
);
2496 static void isom_remove_mdhd( isom_mdhd_t
*mdhd
)
2500 isom_remove_box( mdhd
, isom_mdia_t
);
2503 static void isom_remove_vmhd( isom_vmhd_t
*vmhd
)
2507 isom_remove_box( vmhd
, isom_minf_t
);
2510 static void isom_remove_smhd( isom_smhd_t
*smhd
)
2514 isom_remove_box( smhd
, isom_minf_t
);
2517 static void isom_remove_hmhd( isom_hmhd_t
*hmhd
)
2521 isom_remove_box( hmhd
, isom_minf_t
);
2524 static void isom_remove_nmhd( isom_nmhd_t
*nmhd
)
2528 isom_remove_box( nmhd
, isom_minf_t
);
2531 static void isom_remove_gmin( isom_gmin_t
*gmin
)
2535 isom_remove_box( gmin
, isom_gmhd_t
);
2538 static void isom_remove_text( isom_text_t
*text
)
2542 isom_remove_box( text
, isom_gmhd_t
);
2545 static void isom_remove_gmhd( isom_gmhd_t
*gmhd
)
2549 isom_remove_gmin( gmhd
->gmin
);
2550 isom_remove_text( gmhd
->text
);
2551 isom_remove_box( gmhd
, isom_minf_t
);
2554 static void isom_remove_hdlr( isom_hdlr_t
*hdlr
)
2558 if( hdlr
->componentName
)
2559 free( hdlr
->componentName
);
2562 if( hdlr
->parent
->type
== ISOM_BOX_TYPE_MDIA
)
2563 isom_remove_box( hdlr
, isom_mdia_t
);
2564 else if( hdlr
->parent
->type
== ISOM_BOX_TYPE_MINF
)
2565 isom_remove_box( hdlr
, isom_minf_t
);
2573 void isom_remove_clap( isom_clap_t
*clap
)
2577 isom_remove_box( clap
, isom_visual_entry_t
);
2580 void isom_remove_pasp( isom_pasp_t
*pasp
)
2584 isom_remove_box( pasp
, isom_visual_entry_t
);
2587 void isom_remove_colr( isom_colr_t
*colr
)
2591 isom_remove_box( colr
, isom_visual_entry_t
);
2594 void isom_remove_stsl( isom_stsl_t
*stsl
)
2598 isom_remove_box( stsl
, isom_visual_entry_t
);
2601 static void isom_remove_esds( isom_esds_t
*esds
)
2605 mp4sys_remove_ES_Descriptor( esds
->ES
);
2608 switch( esds
->parent
->type
)
2610 case ISOM_CODEC_TYPE_MP4V_VIDEO
:
2611 isom_remove_box( esds
, isom_visual_entry_t
);
2613 case ISOM_CODEC_TYPE_MP4A_AUDIO
:
2614 case ISOM_CODEC_TYPE_M4AE_AUDIO
:
2615 isom_remove_box( esds
, isom_audio_entry_t
);
2617 case QT_BOX_TYPE_WAVE
:
2618 isom_remove_box( esds
, isom_wave_t
);
2620 case ISOM_CODEC_TYPE_MP4S_SYSTEM
:
2621 isom_remove_box( esds
, isom_mp4s_entry_t
);
2631 void isom_remove_avcC( isom_avcC_t
*avcC
)
2635 lsmash_remove_list( avcC
->sequenceParameterSets
, isom_remove_avcC_ps
);
2636 lsmash_remove_list( avcC
->pictureParameterSets
, isom_remove_avcC_ps
);
2637 lsmash_remove_list( avcC
->sequenceParameterSetExt
, isom_remove_avcC_ps
);
2638 isom_remove_box( avcC
, isom_visual_entry_t
);
2641 void isom_remove_btrt( isom_btrt_t
*btrt
)
2645 isom_remove_box( btrt
, isom_visual_entry_t
);
2648 static void isom_remove_visual_extensions( isom_visual_entry_t
*visual
)
2652 isom_remove_clap( visual
->clap
);
2653 isom_remove_pasp( visual
->pasp
);
2654 isom_remove_colr( visual
->colr
);
2655 isom_remove_stsl( visual
->stsl
);
2656 isom_remove_esds( visual
->esds
);
2657 isom_remove_avcC( visual
->avcC
);
2658 isom_remove_btrt( visual
->btrt
);
2661 static void isom_remove_font_record( isom_font_record_t
*font_record
)
2665 if( font_record
->font_name
)
2666 free( font_record
->font_name
);
2667 free( font_record
);
2670 void isom_remove_ftab( isom_ftab_t
*ftab
)
2674 lsmash_remove_list( ftab
->list
, isom_remove_font_record
);
2675 isom_remove_box( ftab
, isom_tx3g_entry_t
);
2678 void isom_remove_frma( isom_frma_t
*frma
)
2682 isom_remove_box( frma
, isom_wave_t
);
2685 void isom_remove_enda( isom_enda_t
*enda
)
2689 isom_remove_box( enda
, isom_wave_t
);
2692 void isom_remove_mp4a( isom_mp4a_t
*mp4a
)
2696 isom_remove_box( mp4a
, isom_wave_t
);
2699 void isom_remove_terminator( isom_terminator_t
*terminator
)
2703 isom_remove_box( terminator
, isom_wave_t
);
2706 void isom_remove_wave( isom_wave_t
*wave
)
2710 isom_remove_frma( wave
->frma
);
2711 isom_remove_enda( wave
->enda
);
2712 isom_remove_mp4a( wave
->mp4a
);
2713 isom_remove_esds( wave
->esds
);
2714 isom_remove_terminator( wave
->terminator
);
2716 free( wave
->exdata
);
2717 isom_remove_box( wave
, isom_audio_entry_t
);
2720 void isom_remove_chan( isom_chan_t
*chan
)
2724 if( chan
->channelDescriptions
)
2725 free( chan
->channelDescriptions
);
2726 isom_remove_box( chan
, isom_audio_entry_t
);
2729 void isom_remove_sample_description( isom_sample_entry_t
*sample
)
2733 switch( sample
->type
)
2735 case ISOM_CODEC_TYPE_AVC1_VIDEO
:
2736 case ISOM_CODEC_TYPE_AVC2_VIDEO
:
2737 case ISOM_CODEC_TYPE_AVCP_VIDEO
:
2738 case ISOM_CODEC_TYPE_SVC1_VIDEO
:
2739 case ISOM_CODEC_TYPE_MVC1_VIDEO
:
2740 case ISOM_CODEC_TYPE_MVC2_VIDEO
:
2741 case ISOM_CODEC_TYPE_MP4V_VIDEO
:
2742 case ISOM_CODEC_TYPE_DRAC_VIDEO
:
2743 case ISOM_CODEC_TYPE_ENCV_VIDEO
:
2744 case ISOM_CODEC_TYPE_MJP2_VIDEO
:
2745 case ISOM_CODEC_TYPE_S263_VIDEO
:
2746 case ISOM_CODEC_TYPE_VC_1_VIDEO
:
2748 isom_visual_entry_t
*visual
= (isom_visual_entry_t
*)sample
;
2749 isom_remove_visual_extensions( (isom_visual_entry_t
*)visual
);
2753 case ISOM_CODEC_TYPE_MP4A_AUDIO
:
2754 case ISOM_CODEC_TYPE_AC_3_AUDIO
:
2755 case ISOM_CODEC_TYPE_ALAC_AUDIO
:
2756 case ISOM_CODEC_TYPE_SAMR_AUDIO
:
2757 case ISOM_CODEC_TYPE_SAWB_AUDIO
:
2758 case QT_CODEC_TYPE_23NI_AUDIO
:
2759 case QT_CODEC_TYPE_NONE_AUDIO
:
2760 case QT_CODEC_TYPE_LPCM_AUDIO
:
2761 case QT_CODEC_TYPE_RAW_AUDIO
:
2762 case QT_CODEC_TYPE_SOWT_AUDIO
:
2763 case QT_CODEC_TYPE_TWOS_AUDIO
:
2764 case QT_CODEC_TYPE_FL32_AUDIO
:
2765 case QT_CODEC_TYPE_FL64_AUDIO
:
2766 case QT_CODEC_TYPE_IN24_AUDIO
:
2767 case QT_CODEC_TYPE_IN32_AUDIO
:
2768 case QT_CODEC_TYPE_NOT_SPECIFIED
:
2769 case ISOM_CODEC_TYPE_DRA1_AUDIO
:
2770 case ISOM_CODEC_TYPE_DTSC_AUDIO
:
2771 case ISOM_CODEC_TYPE_DTSH_AUDIO
:
2772 case ISOM_CODEC_TYPE_DTSL_AUDIO
:
2773 case ISOM_CODEC_TYPE_EC_3_AUDIO
:
2774 case ISOM_CODEC_TYPE_ENCA_AUDIO
:
2775 case ISOM_CODEC_TYPE_G719_AUDIO
:
2776 case ISOM_CODEC_TYPE_G726_AUDIO
:
2777 case ISOM_CODEC_TYPE_M4AE_AUDIO
:
2778 case ISOM_CODEC_TYPE_MLPA_AUDIO
:
2779 //case ISOM_CODEC_TYPE_RAW_AUDIO :
2780 case ISOM_CODEC_TYPE_SAWP_AUDIO
:
2781 case ISOM_CODEC_TYPE_SEVC_AUDIO
:
2782 case ISOM_CODEC_TYPE_SQCP_AUDIO
:
2783 case ISOM_CODEC_TYPE_SSMV_AUDIO
:
2784 //case ISOM_CODEC_TYPE_TWOS_AUDIO :
2786 isom_audio_entry_t
*audio
= (isom_audio_entry_t
*)sample
;
2787 isom_remove_esds( audio
->esds
);
2788 isom_remove_wave( audio
->wave
);
2789 isom_remove_chan( audio
->chan
);
2791 free( audio
->exdata
);
2795 case ISOM_CODEC_TYPE_FDP_HINT
:
2796 case ISOM_CODEC_TYPE_M2TS_HINT
:
2797 case ISOM_CODEC_TYPE_PM2T_HINT
:
2798 case ISOM_CODEC_TYPE_PRTP_HINT
:
2799 case ISOM_CODEC_TYPE_RM2T_HINT
:
2800 case ISOM_CODEC_TYPE_RRTP_HINT
:
2801 case ISOM_CODEC_TYPE_RSRP_HINT
:
2802 case ISOM_CODEC_TYPE_RTP_HINT
:
2803 case ISOM_CODEC_TYPE_SM2T_HINT
:
2804 case ISOM_CODEC_TYPE_SRTP_HINT
:
2806 isom_hint_entry_t
*hint
= (isom_hint_entry_t
*)sample
;
2812 case ISOM_CODEC_TYPE_IXSE_META
:
2813 case ISOM_CODEC_TYPE_METT_META
:
2814 case ISOM_CODEC_TYPE_METX_META
:
2815 case ISOM_CODEC_TYPE_MLIX_META
:
2816 case ISOM_CODEC_TYPE_OKSD_META
:
2817 case ISOM_CODEC_TYPE_SVCM_META
:
2818 //case ISOM_CODEC_TYPE_TEXT_META :
2819 case ISOM_CODEC_TYPE_URIM_META
:
2820 case ISOM_CODEC_TYPE_XML_META
:
2822 isom_metadata_entry_t
*metadata
= (isom_metadata_entry_t
*)sample
;
2826 case ISOM_CODEC_TYPE_TX3G_TEXT
:
2828 isom_tx3g_entry_t
*tx3g
= (isom_tx3g_entry_t
*)sample
;
2830 isom_remove_ftab( tx3g
->ftab
);
2834 case QT_CODEC_TYPE_TEXT_TEXT
:
2836 isom_text_entry_t
*text
= (isom_text_entry_t
*)sample
;
2837 if( text
->font_name
)
2838 free( text
->font_name
);
2842 case ISOM_CODEC_TYPE_MP4S_SYSTEM
:
2844 isom_mp4s_entry_t
*mp4s
= (isom_mp4s_entry_t
*)sample
;
2845 isom_remove_esds( mp4s
->esds
);
2854 static void isom_remove_stsd( isom_stsd_t
*stsd
)
2858 lsmash_remove_list( stsd
->list
, isom_remove_sample_description
);
2859 isom_remove_box( stsd
, isom_stbl_t
);
2862 static void isom_remove_stts( isom_stts_t
*stts
)
2866 lsmash_remove_list( stts
->list
, NULL
);
2867 isom_remove_box( stts
, isom_stbl_t
);
2870 static void isom_remove_ctts( isom_ctts_t
*ctts
)
2874 lsmash_remove_list( ctts
->list
, NULL
);
2875 isom_remove_box( ctts
, isom_stbl_t
);
2878 static void isom_remove_cslg( isom_cslg_t
*cslg
)
2882 isom_remove_box( cslg
, isom_stbl_t
);
2885 static void isom_remove_stsc( isom_stsc_t
*stsc
)
2889 lsmash_remove_list( stsc
->list
, NULL
);
2890 isom_remove_box( stsc
, isom_stbl_t
);
2893 static void isom_remove_stsz( isom_stsz_t
*stsz
)
2897 lsmash_remove_list( stsz
->list
, NULL
);
2898 isom_remove_box( stsz
, isom_stbl_t
);
2901 static void isom_remove_stss( isom_stss_t
*stss
)
2905 lsmash_remove_list( stss
->list
, NULL
);
2906 isom_remove_box( stss
, isom_stbl_t
);
2909 static void isom_remove_stps( isom_stps_t
*stps
)
2913 lsmash_remove_list( stps
->list
, NULL
);
2914 isom_remove_box( stps
, isom_stbl_t
);
2917 static void isom_remove_sdtp( isom_sdtp_t
*sdtp
)
2921 lsmash_remove_list( sdtp
->list
, NULL
);
2922 isom_remove_box( sdtp
, isom_stbl_t
);
2925 static void isom_remove_stco( isom_stco_t
*stco
)
2929 lsmash_remove_list( stco
->list
, NULL
);
2930 isom_remove_box( stco
, isom_stbl_t
);
2933 static void isom_remove_sgpd( isom_sgpd_entry_t
*sgpd
)
2937 lsmash_remove_list( sgpd
->list
, NULL
);
2941 static void isom_remove_sbgp( isom_sbgp_entry_t
*sbgp
)
2945 lsmash_remove_list( sbgp
->list
, NULL
);
2949 static void isom_remove_stbl( isom_stbl_t
*stbl
)
2953 isom_remove_stsd( stbl
->stsd
);
2954 isom_remove_stts( stbl
->stts
);
2955 isom_remove_ctts( stbl
->ctts
);
2956 isom_remove_cslg( stbl
->cslg
);
2957 isom_remove_stsc( stbl
->stsc
);
2958 isom_remove_stsz( stbl
->stsz
);
2959 isom_remove_stss( stbl
->stss
);
2960 isom_remove_stps( stbl
->stps
);
2961 isom_remove_sdtp( stbl
->sdtp
);
2962 isom_remove_stco( stbl
->stco
);
2963 lsmash_remove_list( stbl
->sgpd_list
, isom_remove_sgpd
);
2964 lsmash_remove_list( stbl
->sbgp_list
, isom_remove_sbgp
);
2965 isom_remove_box( stbl
, isom_minf_t
);
2968 static void isom_remove_dref( isom_dref_t
*dref
)
2977 for( lsmash_entry_t
*entry
= dref
->list
->head
; entry
; )
2979 isom_dref_entry_t
*data
= (isom_dref_entry_t
*)entry
->data
;
2984 if( data
->location
)
2985 free( data
->location
);
2988 lsmash_entry_t
*next
= entry
->next
;
2993 isom_remove_box( dref
, isom_dinf_t
);
2996 static void isom_remove_dinf( isom_dinf_t
*dinf
)
3000 isom_remove_dref( dinf
->dref
);
3001 isom_remove_box( dinf
, isom_minf_t
);
3004 static void isom_remove_minf( isom_minf_t
*minf
)
3008 isom_remove_vmhd( minf
->vmhd
);
3009 isom_remove_smhd( minf
->smhd
);
3010 isom_remove_hmhd( minf
->hmhd
);
3011 isom_remove_nmhd( minf
->nmhd
);
3012 isom_remove_gmhd( minf
->gmhd
);
3013 isom_remove_hdlr( minf
->hdlr
);
3014 isom_remove_dinf( minf
->dinf
);
3015 isom_remove_stbl( minf
->stbl
);
3016 isom_remove_box( minf
, isom_mdia_t
);
3019 static void isom_remove_mdia( isom_mdia_t
*mdia
)
3023 isom_remove_mdhd( mdia
->mdhd
);
3024 isom_remove_minf( mdia
->minf
);
3025 isom_remove_hdlr( mdia
->hdlr
);
3026 isom_remove_box( mdia
, isom_trak_entry_t
);
3029 static void isom_remove_chpl( isom_chpl_t
*chpl
)
3038 for( lsmash_entry_t
*entry
= chpl
->list
->head
; entry
; )
3040 isom_chpl_entry_t
*data
= (isom_chpl_entry_t
*)entry
->data
;
3043 if( data
->chapter_name
)
3044 free( data
->chapter_name
);
3047 lsmash_entry_t
*next
= entry
->next
;
3052 isom_remove_box( chpl
, isom_udta_t
);
3055 static void isom_remove_udta( isom_udta_t
*udta
)
3059 isom_remove_chpl( udta
->chpl
);
3062 if( udta
->parent
->type
== ISOM_BOX_TYPE_MOOV
)
3063 isom_remove_box( udta
, isom_moov_t
);
3064 else if( udta
->parent
->type
== ISOM_BOX_TYPE_TRAK
)
3065 isom_remove_box( udta
, isom_trak_entry_t
);
3073 static void isom_remove_trak( isom_trak_entry_t
*trak
)
3077 isom_remove_tkhd( trak
->tkhd
);
3078 isom_remove_tapt( trak
->tapt
);
3079 isom_remove_edts( trak
->edts
);
3080 isom_remove_tref( trak
->tref
);
3081 isom_remove_mdia( trak
->mdia
);
3082 isom_remove_udta( trak
->udta
);
3085 lsmash_remove_list( trak
->cache
->chunk
.pool
, lsmash_delete_sample
);
3086 lsmash_remove_list( trak
->cache
->roll
.pool
, NULL
);
3087 if( trak
->cache
->rap
)
3088 free( trak
->cache
->rap
);
3089 free( trak
->cache
);
3091 free( trak
); /* Note: the list that contains this trak still has the address of the entry. */
3094 static void isom_remove_iods( isom_iods_t
*iods
)
3098 mp4sys_remove_ObjectDescriptor( iods
->OD
);
3099 isom_remove_box( iods
, isom_moov_t
);
3102 static void isom_remove_mehd( isom_mehd_t
*mehd
)
3106 isom_remove_box( mehd
, isom_mvex_t
);
3109 static void isom_remove_mvex( isom_mvex_t
*mvex
)
3113 isom_remove_mehd( mvex
->mehd
);
3114 lsmash_remove_list( mvex
->trex_list
, NULL
);
3115 isom_remove_box( mvex
, isom_moov_t
);
3118 static void isom_remove_moov( lsmash_root_t
*root
)
3120 if( !root
|| !root
->moov
)
3122 isom_moov_t
*moov
= root
->moov
;
3125 isom_remove_iods( moov
->iods
);
3126 isom_remove_udta( moov
->udta
);
3127 lsmash_remove_list( moov
->trak_list
, isom_remove_trak
);
3128 isom_remove_mvex( moov
->mvex
);
3133 static void isom_remove_mfhd( isom_mfhd_t
*mfhd
)
3137 isom_remove_box( mfhd
, isom_moof_entry_t
);
3140 static void isom_remove_tfhd( isom_tfhd_t
*tfhd
)
3144 isom_remove_box( tfhd
, isom_traf_entry_t
);
3147 static void isom_remove_trun( isom_trun_entry_t
*trun
)
3151 lsmash_remove_list( trun
->optional
, NULL
);
3152 free( trun
); /* Note: the list that contains this trun still has the address of the entry. */
3155 static void isom_remove_traf( isom_traf_entry_t
*traf
)
3159 isom_remove_tfhd( traf
->tfhd
);
3160 lsmash_remove_list( traf
->trun_list
, isom_remove_trun
);
3161 free( traf
); /* Note: the list that contains this traf still has the address of the entry. */
3164 static void isom_remove_moof( isom_moof_entry_t
*moof
)
3168 isom_remove_mfhd( moof
->mfhd
);
3169 lsmash_remove_list( moof
->traf_list
, isom_remove_traf
);
3173 static void isom_remove_mdat( isom_mdat_t
*mdat
)
3177 isom_remove_box( mdat
, lsmash_root_t
);
3180 static void isom_remove_free( isom_free_t
*skip
)
3186 lsmash_root_t
*root
= (lsmash_root_t
*)skip
->parent
;
3191 static void isom_remove_tfra( isom_tfra_entry_t
*tfra
)
3195 lsmash_remove_list( tfra
->list
, NULL
);
3199 static void isom_remove_mfro( isom_mfro_t
*mfro
)
3203 isom_remove_box( mfro
, isom_mfra_t
);
3206 static void isom_remove_mfra( isom_mfra_t
*mfra
)
3210 lsmash_remove_list( mfra
->tfra_list
, isom_remove_tfra
);
3211 isom_remove_mfro( mfra
->mfro
);
3212 isom_remove_box( mfra
, lsmash_root_t
);
3216 static int isom_write_tkhd( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3218 isom_tkhd_t
*tkhd
= trak
->tkhd
;
3221 isom_bs_put_box_common( bs
, tkhd
);
3224 lsmash_bs_put_be64( bs
, tkhd
->creation_time
);
3225 lsmash_bs_put_be64( bs
, tkhd
->modification_time
);
3226 lsmash_bs_put_be32( bs
, tkhd
->track_ID
);
3227 lsmash_bs_put_be32( bs
, tkhd
->reserved1
);
3228 lsmash_bs_put_be64( bs
, tkhd
->duration
);
3232 lsmash_bs_put_be32( bs
, (uint32_t)tkhd
->creation_time
);
3233 lsmash_bs_put_be32( bs
, (uint32_t)tkhd
->modification_time
);
3234 lsmash_bs_put_be32( bs
, tkhd
->track_ID
);
3235 lsmash_bs_put_be32( bs
, tkhd
->reserved1
);
3236 lsmash_bs_put_be32( bs
, (uint32_t)tkhd
->duration
);
3238 lsmash_bs_put_be32( bs
, tkhd
->reserved2
[0] );
3239 lsmash_bs_put_be32( bs
, tkhd
->reserved2
[1] );
3240 lsmash_bs_put_be16( bs
, tkhd
->layer
);
3241 lsmash_bs_put_be16( bs
, tkhd
->alternate_group
);
3242 lsmash_bs_put_be16( bs
, tkhd
->volume
);
3243 lsmash_bs_put_be16( bs
, tkhd
->reserved3
);
3244 for( uint32_t i
= 0; i
< 9; i
++ )
3245 lsmash_bs_put_be32( bs
, tkhd
->matrix
[i
] );
3246 lsmash_bs_put_be32( bs
, tkhd
->width
);
3247 lsmash_bs_put_be32( bs
, tkhd
->height
);
3248 return lsmash_bs_write_data( bs
);
3251 static int isom_write_clef( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3253 isom_clef_t
*clef
= trak
->tapt
->clef
;
3256 isom_bs_put_box_common( bs
, clef
);
3257 lsmash_bs_put_be32( bs
, clef
->width
);
3258 lsmash_bs_put_be32( bs
, clef
->height
);
3259 return lsmash_bs_write_data( bs
);
3262 static int isom_write_prof( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3264 isom_prof_t
*prof
= trak
->tapt
->prof
;
3267 isom_bs_put_box_common( bs
, prof
);
3268 lsmash_bs_put_be32( bs
, prof
->width
);
3269 lsmash_bs_put_be32( bs
, prof
->height
);
3270 return lsmash_bs_write_data( bs
);
3273 static int isom_write_enof( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3275 isom_enof_t
*enof
= trak
->tapt
->enof
;
3278 isom_bs_put_box_common( bs
, enof
);
3279 lsmash_bs_put_be32( bs
, enof
->width
);
3280 lsmash_bs_put_be32( bs
, enof
->height
);
3281 return lsmash_bs_write_data( bs
);
3284 static int isom_write_tapt( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3286 isom_tapt_t
*tapt
= trak
->tapt
;
3289 isom_bs_put_box_common( bs
, tapt
);
3290 if( lsmash_bs_write_data( bs
) )
3292 if( isom_write_clef( bs
, trak
)
3293 || isom_write_prof( bs
, trak
)
3294 || isom_write_enof( bs
, trak
) )
3299 static int isom_write_elst( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3301 isom_elst_t
*elst
= trak
->edts
->elst
;
3304 if( !elst
->list
->entry_count
)
3306 if( elst
->root
->fragment
&& elst
->root
->bs
->stream
!= stdout
)
3307 elst
->pos
= elst
->root
->bs
->written
; /* Remember to rewrite entries. */
3308 isom_bs_put_box_common( bs
, elst
);
3309 lsmash_bs_put_be32( bs
, elst
->list
->entry_count
);
3310 for( lsmash_entry_t
*entry
= elst
->list
->head
; entry
; entry
= entry
->next
)
3312 isom_elst_entry_t
*data
= (isom_elst_entry_t
*)entry
->data
;
3317 lsmash_bs_put_be64( bs
, data
->segment_duration
);
3318 lsmash_bs_put_be64( bs
, data
->media_time
);
3322 lsmash_bs_put_be32( bs
, (uint32_t)data
->segment_duration
);
3323 lsmash_bs_put_be32( bs
, (uint32_t)data
->media_time
);
3325 lsmash_bs_put_be32( bs
, data
->media_rate
);
3327 return lsmash_bs_write_data( bs
);
3330 static int isom_write_edts( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3332 isom_edts_t
*edts
= trak
->edts
;
3335 isom_bs_put_box_common( bs
, edts
);
3336 if( lsmash_bs_write_data( bs
) )
3338 return isom_write_elst( bs
, trak
);
3341 static int isom_write_tref( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3343 isom_tref_t
*tref
= trak
->tref
;
3346 isom_bs_put_box_common( bs
, tref
);
3347 if( tref
->ref_list
)
3348 for( lsmash_entry_t
*entry
= tref
->ref_list
->head
; entry
; entry
= entry
->next
)
3350 isom_tref_type_t
*ref
= (isom_tref_type_t
*)entry
->data
;
3353 isom_bs_put_box_common( bs
, ref
);
3354 for( uint32_t i
= 0; i
< ref
->ref_count
; i
++ )
3355 lsmash_bs_put_be32( bs
, ref
->track_ID
[i
] );
3357 return lsmash_bs_write_data( bs
);
3360 static int isom_write_mdhd( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3362 isom_mdhd_t
*mdhd
= trak
->mdia
->mdhd
;
3365 isom_bs_put_box_common( bs
, mdhd
);
3368 lsmash_bs_put_be64( bs
, mdhd
->creation_time
);
3369 lsmash_bs_put_be64( bs
, mdhd
->modification_time
);
3370 lsmash_bs_put_be32( bs
, mdhd
->timescale
);
3371 lsmash_bs_put_be64( bs
, mdhd
->duration
);
3375 lsmash_bs_put_be32( bs
, (uint32_t)mdhd
->creation_time
);
3376 lsmash_bs_put_be32( bs
, (uint32_t)mdhd
->modification_time
);
3377 lsmash_bs_put_be32( bs
, mdhd
->timescale
);
3378 lsmash_bs_put_be32( bs
, (uint32_t)mdhd
->duration
);
3380 lsmash_bs_put_be16( bs
, mdhd
->language
);
3381 lsmash_bs_put_be16( bs
, mdhd
->quality
);
3382 return lsmash_bs_write_data( bs
);
3385 static int isom_write_hdlr( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
, uint8_t is_media_handler
)
3387 isom_hdlr_t
*hdlr
= is_media_handler
? trak
->mdia
->hdlr
: trak
->mdia
->minf
->hdlr
;
3390 isom_bs_put_box_common( bs
, hdlr
);
3391 lsmash_bs_put_be32( bs
, hdlr
->componentType
);
3392 lsmash_bs_put_be32( bs
, hdlr
->componentSubtype
);
3393 lsmash_bs_put_be32( bs
, hdlr
->componentManufacturer
);
3394 lsmash_bs_put_be32( bs
, hdlr
->componentFlags
);
3395 lsmash_bs_put_be32( bs
, hdlr
->componentFlagsMask
);
3396 lsmash_bs_put_bytes( bs
, hdlr
->componentName
, hdlr
->componentName_length
);
3397 return lsmash_bs_write_data( bs
);
3400 static int isom_write_vmhd( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3402 isom_vmhd_t
*vmhd
= trak
->mdia
->minf
->vmhd
;
3405 isom_bs_put_box_common( bs
, vmhd
);
3406 lsmash_bs_put_be16( bs
, vmhd
->graphicsmode
);
3407 for( uint32_t i
= 0; i
< 3; i
++ )
3408 lsmash_bs_put_be16( bs
, vmhd
->opcolor
[i
] );
3409 return lsmash_bs_write_data( bs
);
3412 static int isom_write_smhd( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3414 isom_smhd_t
*smhd
= trak
->mdia
->minf
->smhd
;
3417 isom_bs_put_box_common( bs
, smhd
);
3418 lsmash_bs_put_be16( bs
, smhd
->balance
);
3419 lsmash_bs_put_be16( bs
, smhd
->reserved
);
3420 return lsmash_bs_write_data( bs
);
3423 static int isom_write_hmhd( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3425 isom_hmhd_t
*hmhd
= trak
->mdia
->minf
->hmhd
;
3428 isom_bs_put_box_common( bs
, hmhd
);
3429 lsmash_bs_put_be16( bs
, hmhd
->maxPDUsize
);
3430 lsmash_bs_put_be16( bs
, hmhd
->avgPDUsize
);
3431 lsmash_bs_put_be32( bs
, hmhd
->maxbitrate
);
3432 lsmash_bs_put_be32( bs
, hmhd
->avgbitrate
);
3433 lsmash_bs_put_be32( bs
, hmhd
->reserved
);
3434 return lsmash_bs_write_data( bs
);
3437 static int isom_write_nmhd( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3439 isom_nmhd_t
*nmhd
= trak
->mdia
->minf
->nmhd
;
3442 isom_bs_put_box_common( bs
, nmhd
);
3443 return lsmash_bs_write_data( bs
);
3446 static int isom_write_gmin( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3448 isom_gmin_t
*gmin
= trak
->mdia
->minf
->gmhd
->gmin
;
3451 isom_bs_put_box_common( bs
, gmin
);
3452 lsmash_bs_put_be16( bs
, gmin
->graphicsmode
);
3453 for( uint32_t i
= 0; i
< 3; i
++ )
3454 lsmash_bs_put_be16( bs
, gmin
->opcolor
[i
] );
3455 lsmash_bs_put_be16( bs
, gmin
->balance
);
3456 lsmash_bs_put_be16( bs
, gmin
->reserved
);
3457 return lsmash_bs_write_data( bs
);
3460 static int isom_write_text( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3462 isom_text_t
*text
= trak
->mdia
->minf
->gmhd
->text
;
3465 isom_bs_put_box_common( bs
, text
);
3466 for( uint32_t i
= 0; i
< 9; i
++ )
3467 lsmash_bs_put_be32( bs
, text
->matrix
[i
] );
3468 return lsmash_bs_write_data( bs
);
3471 static int isom_write_gmhd( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3473 isom_gmhd_t
*gmhd
= trak
->mdia
->minf
->gmhd
;
3476 isom_bs_put_box_common( bs
, gmhd
);
3477 if( isom_write_gmin( bs
, trak
) ||
3478 isom_write_text( bs
, trak
) )
3483 static int isom_write_dref( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3485 isom_dref_t
*dref
= trak
->mdia
->minf
->dinf
->dref
;
3486 if( !dref
|| !dref
->list
)
3488 isom_bs_put_box_common( bs
, dref
);
3489 lsmash_bs_put_be32( bs
, dref
->list
->entry_count
);
3490 for( lsmash_entry_t
*entry
= dref
->list
->head
; entry
; entry
= entry
->next
)
3492 isom_dref_entry_t
*data
= (isom_dref_entry_t
*)entry
->data
;
3495 isom_bs_put_box_common( bs
, data
);
3496 if( data
->type
== ISOM_BOX_TYPE_URN
)
3497 lsmash_bs_put_bytes( bs
, data
->name
, data
->name_length
);
3498 lsmash_bs_put_bytes( bs
, data
->location
, data
->location_length
);
3500 return lsmash_bs_write_data( bs
);
3503 static int isom_write_dinf( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3505 isom_dinf_t
*dinf
= trak
->mdia
->minf
->dinf
;
3508 isom_bs_put_box_common( bs
, dinf
);
3509 if( lsmash_bs_write_data( bs
) )
3511 return isom_write_dref( bs
, trak
);
3514 static int isom_write_pasp( lsmash_bs_t
*bs
, isom_pasp_t
*pasp
)
3518 isom_bs_put_box_common( bs
, pasp
);
3519 lsmash_bs_put_be32( bs
, pasp
->hSpacing
);
3520 lsmash_bs_put_be32( bs
, pasp
->vSpacing
);
3521 return lsmash_bs_write_data( bs
);
3524 static int isom_write_clap( lsmash_bs_t
*bs
, isom_clap_t
*clap
)
3528 isom_bs_put_box_common( bs
, clap
);
3529 lsmash_bs_put_be32( bs
, clap
->cleanApertureWidthN
);
3530 lsmash_bs_put_be32( bs
, clap
->cleanApertureWidthD
);
3531 lsmash_bs_put_be32( bs
, clap
->cleanApertureHeightN
);
3532 lsmash_bs_put_be32( bs
, clap
->cleanApertureHeightD
);
3533 lsmash_bs_put_be32( bs
, clap
->horizOffN
);
3534 lsmash_bs_put_be32( bs
, clap
->horizOffD
);
3535 lsmash_bs_put_be32( bs
, clap
->vertOffN
);
3536 lsmash_bs_put_be32( bs
, clap
->vertOffD
);
3537 return lsmash_bs_write_data( bs
);
3540 static int isom_write_colr( lsmash_bs_t
*bs
, isom_colr_t
*colr
)
3542 if( !colr
|| colr
->color_parameter_type
== QT_COLOR_PARAMETER_TYPE_PROF
)
3544 isom_bs_put_box_common( bs
, colr
);
3545 lsmash_bs_put_be32( bs
, colr
->color_parameter_type
);
3546 lsmash_bs_put_be16( bs
, colr
->primaries_index
);
3547 lsmash_bs_put_be16( bs
, colr
->transfer_function_index
);
3548 lsmash_bs_put_be16( bs
, colr
->matrix_index
);
3549 return lsmash_bs_write_data( bs
);
3552 static int isom_write_stsl( lsmash_bs_t
*bs
, isom_stsl_t
*stsl
)
3556 isom_bs_put_box_common( bs
, stsl
);
3557 lsmash_bs_put_byte( bs
, stsl
->constraint_flag
);
3558 lsmash_bs_put_byte( bs
, stsl
->scale_method
);
3559 lsmash_bs_put_be16( bs
, stsl
->display_center_x
);
3560 lsmash_bs_put_be16( bs
, stsl
->display_center_y
);
3561 return lsmash_bs_write_data( bs
);
3564 static int isom_write_esds( lsmash_bs_t
*bs
, isom_esds_t
*esds
)
3568 isom_bs_put_box_common( bs
, esds
);
3569 return mp4sys_write_ES_Descriptor( bs
, esds
->ES
);
3572 static int isom_put_ps_entries( lsmash_bs_t
*bs
, lsmash_entry_list_t
*list
)
3574 for( lsmash_entry_t
*entry
= list
->head
; entry
; entry
= entry
->next
)
3576 isom_avcC_ps_entry_t
*data
= (isom_avcC_ps_entry_t
*)entry
->data
;
3579 lsmash_bs_put_be16( bs
, data
->parameterSetLength
);
3580 lsmash_bs_put_bytes( bs
, data
->parameterSetNALUnit
, data
->parameterSetLength
);
3585 static int isom_write_avcC( lsmash_bs_t
*bs
, isom_avcC_t
*avcC
)
3587 if( !bs
|| !avcC
|| !avcC
->sequenceParameterSets
|| !avcC
->pictureParameterSets
)
3589 isom_bs_put_box_common( bs
, avcC
);
3590 lsmash_bs_put_byte( bs
, avcC
->configurationVersion
);
3591 lsmash_bs_put_byte( bs
, avcC
->AVCProfileIndication
);
3592 lsmash_bs_put_byte( bs
, avcC
->profile_compatibility
);
3593 lsmash_bs_put_byte( bs
, avcC
->AVCLevelIndication
);
3594 lsmash_bs_put_byte( bs
, avcC
->lengthSizeMinusOne
| 0xfc ); /* upper 6-bits are reserved as 111111b */
3595 lsmash_bs_put_byte( bs
, avcC
->numOfSequenceParameterSets
| 0xe0 ); /* upper 3-bits are reserved as 111b */
3596 if( isom_put_ps_entries( bs
, avcC
->sequenceParameterSets
) )
3598 lsmash_bs_put_byte( bs
, avcC
->numOfPictureParameterSets
);
3599 if( isom_put_ps_entries( bs
, avcC
->pictureParameterSets
) )
3601 if( ISOM_REQUIRES_AVCC_EXTENSION( avcC
->AVCProfileIndication
) )
3603 lsmash_bs_put_byte( bs
, avcC
->chroma_format
| 0xfc ); /* upper 6-bits are reserved as 111111b */
3604 lsmash_bs_put_byte( bs
, avcC
->bit_depth_luma_minus8
| 0xf8 ); /* upper 5-bits are reserved as 11111b */
3605 lsmash_bs_put_byte( bs
, avcC
->bit_depth_chroma_minus8
| 0xf8 ); /* upper 5-bits are reserved as 11111b */
3606 lsmash_bs_put_byte( bs
, avcC
->numOfSequenceParameterSetExt
);
3607 if( isom_put_ps_entries( bs
, avcC
->sequenceParameterSetExt
) )
3610 return lsmash_bs_write_data( bs
);
3613 static int isom_write_btrt( lsmash_bs_t
*bs
, isom_btrt_t
*btrt
)
3617 isom_bs_put_box_common( bs
, btrt
);
3618 lsmash_bs_put_be32( bs
, btrt
->bufferSizeDB
);
3619 lsmash_bs_put_be32( bs
, btrt
->maxBitrate
);
3620 lsmash_bs_put_be32( bs
, btrt
->avgBitrate
);
3621 return lsmash_bs_write_data( bs
);
3624 static int isom_write_visual_extensions( lsmash_bs_t
*bs
, isom_visual_entry_t
*visual
)
3628 if( isom_write_clap( bs
, visual
->clap
)
3629 || isom_write_pasp( bs
, visual
->pasp
)
3630 || isom_write_colr( bs
, visual
->colr
)
3631 || isom_write_stsl( bs
, visual
->stsl
)
3632 || isom_write_esds( bs
, visual
->esds
)
3633 || isom_write_avcC( bs
, visual
->avcC
)
3634 || isom_write_btrt( bs
, visual
->btrt
) )
3639 static int isom_write_frma( lsmash_bs_t
*bs
, isom_frma_t
*frma
)
3643 isom_bs_put_box_common( bs
, frma
);
3644 lsmash_bs_put_be32( bs
, frma
->data_format
);
3645 return lsmash_bs_write_data( bs
);
3648 static int isom_write_enda( lsmash_bs_t
*bs
, isom_enda_t
*enda
)
3652 isom_bs_put_box_common( bs
, enda
);
3653 lsmash_bs_put_be16( bs
, enda
->littleEndian
);
3654 return lsmash_bs_write_data( bs
);
3657 static int isom_write_mp4a( lsmash_bs_t
*bs
, isom_mp4a_t
*mp4a
)
3661 isom_bs_put_box_common( bs
, mp4a
);
3662 lsmash_bs_put_be32( bs
, mp4a
->unknown
);
3663 return lsmash_bs_write_data( bs
);
3666 static int isom_write_terminator( lsmash_bs_t
*bs
, isom_terminator_t
*terminator
)
3670 isom_bs_put_box_common( bs
, terminator
);
3671 return lsmash_bs_write_data( bs
);
3674 static int isom_write_wave( lsmash_bs_t
*bs
, isom_wave_t
*wave
)
3678 isom_bs_put_box_common( bs
, wave
);
3679 if( lsmash_bs_write_data( bs
) )
3681 if( isom_write_frma( bs
, wave
->frma
)
3682 || isom_write_enda( bs
, wave
->enda
)
3683 || isom_write_mp4a( bs
, wave
->mp4a
) )
3685 lsmash_bs_put_bytes( bs
, wave
->exdata
, wave
->exdata_length
);
3686 if( lsmash_bs_write_data( bs
) )
3688 if( isom_write_esds( bs
, wave
->esds
) )
3690 return isom_write_terminator( bs
, wave
->terminator
);
3693 static int isom_write_chan( lsmash_bs_t
*bs
, isom_chan_t
*chan
)
3697 isom_bs_put_box_common( bs
, chan
);
3698 lsmash_bs_put_be32( bs
, chan
->channelLayoutTag
);
3699 lsmash_bs_put_be32( bs
, chan
->channelBitmap
);
3700 lsmash_bs_put_be32( bs
, chan
->numberChannelDescriptions
);
3701 if( chan
->channelDescriptions
)
3702 for( uint32_t i
= 0; i
< chan
->numberChannelDescriptions
; i
++ )
3704 isom_channel_description_t
*channelDescriptions
= (isom_channel_description_t
*)(&chan
->channelDescriptions
[i
]);
3705 if( !channelDescriptions
)
3707 lsmash_bs_put_be32( bs
, channelDescriptions
->channelLabel
);
3708 lsmash_bs_put_be32( bs
, channelDescriptions
->channelFlags
);
3709 lsmash_bs_put_be32( bs
, channelDescriptions
->coordinates
[0] );
3710 lsmash_bs_put_be32( bs
, channelDescriptions
->coordinates
[1] );
3711 lsmash_bs_put_be32( bs
, channelDescriptions
->coordinates
[2] );
3713 return lsmash_bs_write_data( bs
);
3716 static int isom_write_audio_extensions( lsmash_bs_t
*bs
, isom_audio_entry_t
*audio
)
3720 if( isom_write_esds( bs
, audio
->esds
)
3721 || isom_write_wave( bs
, audio
->wave
)
3722 || isom_write_chan( bs
, audio
->chan
) )
3727 static int isom_write_visual_entry( lsmash_bs_t
*bs
, lsmash_entry_t
*entry
)
3729 isom_visual_entry_t
*data
= (isom_visual_entry_t
*)entry
->data
;
3732 isom_bs_put_box_common( bs
, data
);
3733 lsmash_bs_put_bytes( bs
, data
->reserved
, 6 );
3734 lsmash_bs_put_be16( bs
, data
->data_reference_index
);
3735 lsmash_bs_put_be16( bs
, data
->version
);
3736 lsmash_bs_put_be16( bs
, data
->revision_level
);
3737 lsmash_bs_put_be32( bs
, data
->vendor
);
3738 lsmash_bs_put_be32( bs
, data
->temporalQuality
);
3739 lsmash_bs_put_be32( bs
, data
->spatialQuality
);
3740 lsmash_bs_put_be16( bs
, data
->width
);
3741 lsmash_bs_put_be16( bs
, data
->height
);
3742 lsmash_bs_put_be32( bs
, data
->horizresolution
);
3743 lsmash_bs_put_be32( bs
, data
->vertresolution
);
3744 lsmash_bs_put_be32( bs
, data
->dataSize
);
3745 lsmash_bs_put_be16( bs
, data
->frame_count
);
3746 lsmash_bs_put_bytes( bs
, data
->compressorname
, 32 );
3747 lsmash_bs_put_be16( bs
, data
->depth
);
3748 lsmash_bs_put_be16( bs
, data
->color_table_ID
);
3749 if( lsmash_bs_write_data( bs
) )
3751 return isom_write_visual_extensions( bs
, data
);
3754 static int isom_write_audio_entry( lsmash_bs_t
*bs
, lsmash_entry_t
*entry
)
3756 isom_audio_entry_t
*data
= (isom_audio_entry_t
*)entry
->data
;
3759 isom_bs_put_box_common( bs
, data
);
3760 lsmash_bs_put_bytes( bs
, data
->reserved
, 6 );
3761 lsmash_bs_put_be16( bs
, data
->data_reference_index
);
3762 lsmash_bs_put_be16( bs
, data
->version
);
3763 lsmash_bs_put_be16( bs
, data
->revision_level
);
3764 lsmash_bs_put_be32( bs
, data
->vendor
);
3765 lsmash_bs_put_be16( bs
, data
->channelcount
);
3766 lsmash_bs_put_be16( bs
, data
->samplesize
);
3767 lsmash_bs_put_be16( bs
, data
->compression_ID
);
3768 lsmash_bs_put_be16( bs
, data
->packet_size
);
3769 lsmash_bs_put_be32( bs
, data
->samplerate
);
3770 if( data
->version
== 1 )
3772 lsmash_bs_put_be32( bs
, data
->samplesPerPacket
);
3773 lsmash_bs_put_be32( bs
, data
->bytesPerPacket
);
3774 lsmash_bs_put_be32( bs
, data
->bytesPerFrame
);
3775 lsmash_bs_put_be32( bs
, data
->bytesPerSample
);
3777 else if( data
->version
== 2 )
3779 lsmash_bs_put_be32( bs
, data
->sizeOfStructOnly
);
3780 lsmash_bs_put_be64( bs
, data
->audioSampleRate
);
3781 lsmash_bs_put_be32( bs
, data
->numAudioChannels
);
3782 lsmash_bs_put_be32( bs
, data
->always7F000000
);
3783 lsmash_bs_put_be32( bs
, data
->constBitsPerChannel
);
3784 lsmash_bs_put_be32( bs
, data
->formatSpecificFlags
);
3785 lsmash_bs_put_be32( bs
, data
->constBytesPerAudioPacket
);
3786 lsmash_bs_put_be32( bs
, data
->constLPCMFramesPerAudioPacket
);
3788 lsmash_bs_put_bytes( bs
, data
->exdata
, data
->exdata_length
);
3789 if( lsmash_bs_write_data( bs
) )
3791 return isom_write_audio_extensions( bs
, data
);
3795 static int isom_write_hint_entry( lsmash_bs_t
*bs
, lsmash_entry_t
*entry
)
3797 isom_hint_entry_t
*data
= (isom_hint_entry_t
*)entry
->data
;
3800 isom_bs_put_box_common( bs
, data
);
3801 lsmash_bs_put_bytes( bs
, data
->reserved
, 6 );
3802 lsmash_bs_put_be16( bs
, data
->data_reference_index
);
3803 if( data
->data
&& data
->data_length
)
3804 lsmash_bs_put_bytes( bs
, data
->data
, data
->data_length
);
3805 return lsmash_bs_write_data( bs
);
3808 static int isom_write_metadata_entry( lsmash_bs_t
*bs
, lsmash_entry_t
*entry
)
3810 isom_metadata_entry_t
*data
= (isom_metadata_entry_t
*)entry
->data
;
3813 isom_bs_put_box_common( bs
, data
);
3814 lsmash_bs_put_bytes( bs
, data
->reserved
, 6 );
3815 lsmash_bs_put_be16( bs
, data
->data_reference_index
);
3816 return lsmash_bs_write_data( bs
);
3820 static int isom_write_text_entry( lsmash_bs_t
*bs
, lsmash_entry_t
*entry
)
3822 isom_text_entry_t
*data
= (isom_text_entry_t
*)entry
->data
;
3825 isom_bs_put_box_common( bs
, data
);
3826 lsmash_bs_put_bytes( bs
, data
->reserved
, 6 );
3827 lsmash_bs_put_be16( bs
, data
->data_reference_index
);
3828 lsmash_bs_put_be32( bs
, data
->displayFlags
);
3829 lsmash_bs_put_be32( bs
, data
->textJustification
);
3830 for( uint32_t i
= 0; i
< 3; i
++ )
3831 lsmash_bs_put_be16( bs
, data
->bgColor
[i
] );
3832 lsmash_bs_put_be16( bs
, data
->top
);
3833 lsmash_bs_put_be16( bs
, data
->left
);
3834 lsmash_bs_put_be16( bs
, data
->bottom
);
3835 lsmash_bs_put_be16( bs
, data
->right
);
3836 lsmash_bs_put_be32( bs
, data
->scrpStartChar
);
3837 lsmash_bs_put_be16( bs
, data
->scrpHeight
);
3838 lsmash_bs_put_be16( bs
, data
->scrpAscent
);
3839 lsmash_bs_put_be16( bs
, data
->scrpFont
);
3840 lsmash_bs_put_be16( bs
, data
->scrpFace
);
3841 lsmash_bs_put_be16( bs
, data
->scrpSize
);
3842 for( uint32_t i
= 0; i
< 3; i
++ )
3843 lsmash_bs_put_be16( bs
, data
->scrpColor
[i
] );
3844 lsmash_bs_put_byte( bs
, data
->font_name_length
);
3845 if( data
->font_name
&& data
->font_name_length
)
3846 lsmash_bs_put_bytes( bs
, data
->font_name
, data
->font_name_length
);
3847 return lsmash_bs_write_data( bs
);
3850 static int isom_put_ftab( lsmash_bs_t
*bs
, isom_ftab_t
*ftab
)
3852 if( !ftab
|| !ftab
->list
)
3854 isom_bs_put_box_common( bs
, ftab
);
3855 lsmash_bs_put_be16( bs
, ftab
->list
->entry_count
);
3856 for( lsmash_entry_t
*entry
= ftab
->list
->head
; entry
; entry
= entry
->next
)
3858 isom_font_record_t
*data
= (isom_font_record_t
*)entry
->data
;
3861 lsmash_bs_put_be16( bs
, data
->font_ID
);
3862 lsmash_bs_put_byte( bs
, data
->font_name_length
);
3863 if( data
->font_name
&& data
->font_name_length
)
3864 lsmash_bs_put_bytes( bs
, data
->font_name
, data
->font_name_length
);
3869 static int isom_write_tx3g_entry( lsmash_bs_t
*bs
, lsmash_entry_t
*entry
)
3871 isom_tx3g_entry_t
*data
= (isom_tx3g_entry_t
*)entry
->data
;
3874 isom_bs_put_box_common( bs
, data
);
3875 lsmash_bs_put_bytes( bs
, data
->reserved
, 6 );
3876 lsmash_bs_put_be16( bs
, data
->data_reference_index
);
3877 lsmash_bs_put_be32( bs
, data
->displayFlags
);
3878 lsmash_bs_put_byte( bs
, data
->horizontal_justification
);
3879 lsmash_bs_put_byte( bs
, data
->vertical_justification
);
3880 for( uint32_t i
= 0; i
< 4; i
++ )
3881 lsmash_bs_put_byte( bs
, data
->background_color_rgba
[i
] );
3882 lsmash_bs_put_be16( bs
, data
->top
);
3883 lsmash_bs_put_be16( bs
, data
->left
);
3884 lsmash_bs_put_be16( bs
, data
->bottom
);
3885 lsmash_bs_put_be16( bs
, data
->right
);
3886 lsmash_bs_put_be16( bs
, data
->startChar
);
3887 lsmash_bs_put_be16( bs
, data
->endChar
);
3888 lsmash_bs_put_be16( bs
, data
->font_ID
);
3889 lsmash_bs_put_byte( bs
, data
->face_style_flags
);
3890 lsmash_bs_put_byte( bs
, data
->font_size
);
3891 for( uint32_t i
= 0; i
< 4; i
++ )
3892 lsmash_bs_put_byte( bs
, data
->text_color_rgba
[i
] );
3893 isom_put_ftab( bs
, data
->ftab
);
3894 return lsmash_bs_write_data( bs
);
3897 static int isom_write_stsd( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3899 isom_stsd_t
*stsd
= trak
->mdia
->minf
->stbl
->stsd
;
3900 if( !stsd
|| !stsd
->list
|| !stsd
->list
->head
)
3902 isom_bs_put_box_common( bs
, stsd
);
3903 lsmash_bs_put_be32( bs
, stsd
->list
->entry_count
);
3905 for( lsmash_entry_t
*entry
= stsd
->list
->head
; entry
; entry
= entry
->next
)
3907 isom_sample_entry_t
*sample
= (isom_sample_entry_t
*)entry
->data
;
3910 switch( sample
->type
)
3912 case ISOM_CODEC_TYPE_AVC1_VIDEO
:
3914 case ISOM_CODEC_TYPE_AVC2_VIDEO
:
3915 case ISOM_CODEC_TYPE_AVCP_VIDEO
:
3916 case ISOM_CODEC_TYPE_SVC1_VIDEO
:
3917 case ISOM_CODEC_TYPE_MVC1_VIDEO
:
3918 case ISOM_CODEC_TYPE_MVC2_VIDEO
:
3919 case ISOM_CODEC_TYPE_MP4V_VIDEO
:
3920 case ISOM_CODEC_TYPE_DRAC_VIDEO
:
3921 case ISOM_CODEC_TYPE_ENCV_VIDEO
:
3922 case ISOM_CODEC_TYPE_MJP2_VIDEO
:
3923 case ISOM_CODEC_TYPE_S263_VIDEO
:
3924 case ISOM_CODEC_TYPE_VC_1_VIDEO
:
3926 ret
= isom_write_visual_entry( bs
, entry
);
3928 case ISOM_CODEC_TYPE_MP4A_AUDIO
:
3929 case ISOM_CODEC_TYPE_AC_3_AUDIO
:
3930 case ISOM_CODEC_TYPE_ALAC_AUDIO
:
3931 case ISOM_CODEC_TYPE_SAMR_AUDIO
:
3932 case ISOM_CODEC_TYPE_SAWB_AUDIO
:
3933 case QT_CODEC_TYPE_23NI_AUDIO
:
3934 case QT_CODEC_TYPE_NONE_AUDIO
:
3935 case QT_CODEC_TYPE_LPCM_AUDIO
:
3936 case QT_CODEC_TYPE_RAW_AUDIO
:
3937 case QT_CODEC_TYPE_SOWT_AUDIO
:
3938 case QT_CODEC_TYPE_TWOS_AUDIO
:
3939 case QT_CODEC_TYPE_FL32_AUDIO
:
3940 case QT_CODEC_TYPE_FL64_AUDIO
:
3941 case QT_CODEC_TYPE_IN24_AUDIO
:
3942 case QT_CODEC_TYPE_IN32_AUDIO
:
3943 case QT_CODEC_TYPE_NOT_SPECIFIED
:
3944 #ifdef LSMASH_DEMUXER_ENABLED
3945 case ISOM_CODEC_TYPE_EC_3_AUDIO
:
3948 case ISOM_CODEC_TYPE_DRA1_AUDIO
:
3949 case ISOM_CODEC_TYPE_DTSC_AUDIO
:
3950 case ISOM_CODEC_TYPE_DTSH_AUDIO
:
3951 case ISOM_CODEC_TYPE_DTSL_AUDIO
:
3952 case ISOM_CODEC_TYPE_ENCA_AUDIO
:
3953 case ISOM_CODEC_TYPE_G719_AUDIO
:
3954 case ISOM_CODEC_TYPE_G726_AUDIO
:
3955 case ISOM_CODEC_TYPE_M4AE_AUDIO
:
3956 case ISOM_CODEC_TYPE_MLPA_AUDIO
:
3957 case ISOM_CODEC_TYPE_RAW_AUDIO
:
3958 case ISOM_CODEC_TYPE_SAWP_AUDIO
:
3959 case ISOM_CODEC_TYPE_SEVC_AUDIO
:
3960 case ISOM_CODEC_TYPE_SQCP_AUDIO
:
3961 case ISOM_CODEC_TYPE_SSMV_AUDIO
:
3962 case ISOM_CODEC_TYPE_TWOS_AUDIO
:
3964 ret
= isom_write_audio_entry( bs
, entry
);
3967 case ISOM_CODEC_TYPE_FDP_HINT
:
3968 case ISOM_CODEC_TYPE_M2TS_HINT
:
3969 case ISOM_CODEC_TYPE_PM2T_HINT
:
3970 case ISOM_CODEC_TYPE_PRTP_HINT
:
3971 case ISOM_CODEC_TYPE_RM2T_HINT
:
3972 case ISOM_CODEC_TYPE_RRTP_HINT
:
3973 case ISOM_CODEC_TYPE_RSRP_HINT
:
3974 case ISOM_CODEC_TYPE_RTP_HINT
:
3975 case ISOM_CODEC_TYPE_SM2T_HINT
:
3976 case ISOM_CODEC_TYPE_SRTP_HINT
:
3977 ret
= isom_write_hint_entry( bs
, entry
);
3979 case ISOM_CODEC_TYPE_IXSE_META
:
3980 case ISOM_CODEC_TYPE_METT_META
:
3981 case ISOM_CODEC_TYPE_METX_META
:
3982 case ISOM_CODEC_TYPE_MLIX_META
:
3983 case ISOM_CODEC_TYPE_OKSD_META
:
3984 case ISOM_CODEC_TYPE_SVCM_META
:
3985 case ISOM_CODEC_TYPE_TEXT_META
:
3986 case ISOM_CODEC_TYPE_URIM_META
:
3987 case ISOM_CODEC_TYPE_XML_META
:
3988 ret
= isom_write_metadata_entry( bs
, entry
);
3991 case ISOM_CODEC_TYPE_TX3G_TEXT
:
3992 ret
= isom_write_tx3g_entry( bs
, entry
);
3994 case QT_CODEC_TYPE_TEXT_TEXT
:
3995 ret
= isom_write_text_entry( bs
, entry
);
4006 static int isom_write_stts( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4008 isom_stts_t
*stts
= trak
->mdia
->minf
->stbl
->stts
;
4009 if( !stts
|| !stts
->list
)
4011 isom_bs_put_box_common( bs
, stts
);
4012 lsmash_bs_put_be32( bs
, stts
->list
->entry_count
);
4013 for( lsmash_entry_t
*entry
= stts
->list
->head
; entry
; entry
= entry
->next
)
4015 isom_stts_entry_t
*data
= (isom_stts_entry_t
*)entry
->data
;
4018 lsmash_bs_put_be32( bs
, data
->sample_count
);
4019 lsmash_bs_put_be32( bs
, data
->sample_delta
);
4021 return lsmash_bs_write_data( bs
);
4024 static int isom_write_ctts( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4026 isom_ctts_t
*ctts
= trak
->mdia
->minf
->stbl
->ctts
;
4031 isom_bs_put_box_common( bs
, ctts
);
4032 lsmash_bs_put_be32( bs
, ctts
->list
->entry_count
);
4033 for( lsmash_entry_t
*entry
= ctts
->list
->head
; entry
; entry
= entry
->next
)
4035 isom_ctts_entry_t
*data
= (isom_ctts_entry_t
*)entry
->data
;
4038 lsmash_bs_put_be32( bs
, data
->sample_count
);
4039 lsmash_bs_put_be32( bs
, data
->sample_offset
);
4041 return lsmash_bs_write_data( bs
);
4044 static int isom_write_cslg( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4046 isom_cslg_t
*cslg
= trak
->mdia
->minf
->stbl
->cslg
;
4049 isom_bs_put_box_common( bs
, cslg
);
4050 lsmash_bs_put_be32( bs
, cslg
->compositionToDTSShift
);
4051 lsmash_bs_put_be32( bs
, cslg
->leastDecodeToDisplayDelta
);
4052 lsmash_bs_put_be32( bs
, cslg
->greatestDecodeToDisplayDelta
);
4053 lsmash_bs_put_be32( bs
, cslg
->compositionStartTime
);
4054 lsmash_bs_put_be32( bs
, cslg
->compositionEndTime
);
4055 return lsmash_bs_write_data( bs
);
4058 static int isom_write_stsz( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4060 isom_stsz_t
*stsz
= trak
->mdia
->minf
->stbl
->stsz
;
4063 isom_bs_put_box_common( bs
, stsz
);
4064 lsmash_bs_put_be32( bs
, stsz
->sample_size
);
4065 lsmash_bs_put_be32( bs
, stsz
->sample_count
);
4066 if( stsz
->sample_size
== 0 && stsz
->list
)
4067 for( lsmash_entry_t
*entry
= stsz
->list
->head
; entry
; entry
= entry
->next
)
4069 isom_stsz_entry_t
*data
= (isom_stsz_entry_t
*)entry
->data
;
4072 lsmash_bs_put_be32( bs
, data
->entry_size
);
4074 return lsmash_bs_write_data( bs
);
4077 static int isom_write_stss( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4079 isom_stss_t
*stss
= trak
->mdia
->minf
->stbl
->stss
;
4081 return 0; /* If the sync sample box is not present, every sample is a random access point. */
4084 isom_bs_put_box_common( bs
, stss
);
4085 lsmash_bs_put_be32( bs
, stss
->list
->entry_count
);
4086 for( lsmash_entry_t
*entry
= stss
->list
->head
; entry
; entry
= entry
->next
)
4088 isom_stss_entry_t
*data
= (isom_stss_entry_t
*)entry
->data
;
4091 lsmash_bs_put_be32( bs
, data
->sample_number
);
4093 return lsmash_bs_write_data( bs
);
4096 static int isom_write_stps( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4098 isom_stps_t
*stps
= trak
->mdia
->minf
->stbl
->stps
;
4103 isom_bs_put_box_common( bs
, stps
);
4104 lsmash_bs_put_be32( bs
, stps
->list
->entry_count
);
4105 for( lsmash_entry_t
*entry
= stps
->list
->head
; entry
; entry
= entry
->next
)
4107 isom_stps_entry_t
*data
= (isom_stps_entry_t
*)entry
->data
;
4110 lsmash_bs_put_be32( bs
, data
->sample_number
);
4112 return lsmash_bs_write_data( bs
);
4115 static int isom_write_sdtp( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4117 isom_sdtp_t
*sdtp
= trak
->mdia
->minf
->stbl
->sdtp
;
4122 isom_bs_put_box_common( bs
, sdtp
);
4123 for( lsmash_entry_t
*entry
= sdtp
->list
->head
; entry
; entry
= entry
->next
)
4125 isom_sdtp_entry_t
*data
= (isom_sdtp_entry_t
*)entry
->data
;
4128 uint8_t temp
= (data
->is_leading
<< 6)
4129 | (data
->sample_depends_on
<< 4)
4130 | (data
->sample_is_depended_on
<< 2)
4131 | data
->sample_has_redundancy
;
4132 lsmash_bs_put_byte( bs
, temp
);
4134 return lsmash_bs_write_data( bs
);
4137 static int isom_write_stsc( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4139 isom_stsc_t
*stsc
= trak
->mdia
->minf
->stbl
->stsc
;
4140 if( !stsc
|| !stsc
->list
)
4142 isom_bs_put_box_common( bs
, stsc
);
4143 lsmash_bs_put_be32( bs
, stsc
->list
->entry_count
);
4144 for( lsmash_entry_t
*entry
= stsc
->list
->head
; entry
; entry
= entry
->next
)
4146 isom_stsc_entry_t
*data
= (isom_stsc_entry_t
*)entry
->data
;
4149 lsmash_bs_put_be32( bs
, data
->first_chunk
);
4150 lsmash_bs_put_be32( bs
, data
->samples_per_chunk
);
4151 lsmash_bs_put_be32( bs
, data
->sample_description_index
);
4153 return lsmash_bs_write_data( bs
);
4156 static int isom_write_co64( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4158 isom_stco_t
*co64
= trak
->mdia
->minf
->stbl
->stco
;
4159 if( !co64
|| !co64
->list
)
4161 isom_bs_put_box_common( bs
, co64
);
4162 lsmash_bs_put_be32( bs
, co64
->list
->entry_count
);
4163 for( lsmash_entry_t
*entry
= co64
->list
->head
; entry
; entry
= entry
->next
)
4165 isom_co64_entry_t
*data
= (isom_co64_entry_t
*)entry
->data
;
4168 lsmash_bs_put_be64( bs
, data
->chunk_offset
);
4170 return lsmash_bs_write_data( bs
);
4173 static int isom_write_stco( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4175 isom_stco_t
*stco
= trak
->mdia
->minf
->stbl
->stco
;
4176 if( !stco
|| !stco
->list
)
4178 if( stco
->large_presentation
)
4179 return isom_write_co64( bs
, trak
);
4180 isom_bs_put_box_common( bs
, stco
);
4181 lsmash_bs_put_be32( bs
, stco
->list
->entry_count
);
4182 for( lsmash_entry_t
*entry
= stco
->list
->head
; entry
; entry
= entry
->next
)
4184 isom_stco_entry_t
*data
= (isom_stco_entry_t
*)entry
->data
;
4187 lsmash_bs_put_be32( bs
, data
->chunk_offset
);
4189 return lsmash_bs_write_data( bs
);
4192 static int isom_write_sgpd( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
, uint32_t grouping_number
)
4194 isom_sgpd_entry_t
*sgpd
= (isom_sgpd_entry_t
*)lsmash_get_entry_data( trak
->mdia
->minf
->stbl
->sgpd_list
, grouping_number
);
4195 if( !sgpd
|| !sgpd
->list
)
4197 isom_bs_put_box_common( bs
, sgpd
);
4198 lsmash_bs_put_be32( bs
, sgpd
->grouping_type
);
4199 if( sgpd
->version
== 1 )
4200 lsmash_bs_put_be32( bs
, sgpd
->default_length
);
4201 lsmash_bs_put_be32( bs
, sgpd
->list
->entry_count
);
4202 for( lsmash_entry_t
*entry
= sgpd
->list
->head
; entry
; entry
= entry
->next
)
4206 switch( sgpd
->grouping_type
)
4208 case ISOM_GROUP_TYPE_RAP
:
4210 isom_rap_entry_t
*rap
= (isom_rap_entry_t
*)entry
->data
;
4211 uint8_t temp
= (rap
->num_leading_samples_known
<< 7)
4212 | rap
->num_leading_samples
;
4213 lsmash_bs_put_byte( bs
, temp
);
4216 case ISOM_GROUP_TYPE_ROLL
:
4217 lsmash_bs_put_be16( bs
, ((isom_roll_entry_t
*)entry
->data
)->roll_distance
);
4220 /* We don't consider other grouping types currently. */
4221 // if( sgpd->version == 1 && !sgpd->default_length )
4222 // lsmash_bs_put_be32( bs, ((isom_sgpd_entry_t *)entry->data)->description_length );
4226 return lsmash_bs_write_data( bs
);
4229 static int isom_write_sbgp( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
, uint32_t grouping_number
)
4231 isom_sbgp_entry_t
*sbgp
= (isom_sbgp_entry_t
*)lsmash_get_entry_data( trak
->mdia
->minf
->stbl
->sbgp_list
, grouping_number
);
4232 if( !sbgp
|| !sbgp
->list
)
4234 isom_bs_put_box_common( bs
, sbgp
);
4235 lsmash_bs_put_be32( bs
, sbgp
->grouping_type
);
4236 if( sbgp
->version
== 1 )
4237 lsmash_bs_put_be32( bs
, sbgp
->grouping_type_parameter
);
4238 lsmash_bs_put_be32( bs
, sbgp
->list
->entry_count
);
4239 for( lsmash_entry_t
*entry
= sbgp
->list
->head
; entry
; entry
= entry
->next
)
4241 isom_group_assignment_entry_t
*data
= (isom_group_assignment_entry_t
*)entry
->data
;
4244 lsmash_bs_put_be32( bs
, data
->sample_count
);
4245 lsmash_bs_put_be32( bs
, data
->group_description_index
);
4247 return lsmash_bs_write_data( bs
);
4250 static int isom_write_stbl( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4252 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
4255 isom_bs_put_box_common( bs
, stbl
);
4256 if( lsmash_bs_write_data( bs
) )
4258 if( isom_write_stsd( bs
, trak
)
4259 || isom_write_stts( bs
, trak
)
4260 || isom_write_ctts( bs
, trak
)
4261 || isom_write_cslg( bs
, trak
)
4262 || isom_write_stss( bs
, trak
)
4263 || isom_write_stps( bs
, trak
)
4264 || isom_write_sdtp( bs
, trak
)
4265 || isom_write_stsc( bs
, trak
)
4266 || isom_write_stsz( bs
, trak
)
4267 || isom_write_stco( bs
, trak
) )
4269 if( stbl
->sgpd_list
)
4270 for( uint32_t i
= 1; i
<= stbl
->sgpd_list
->entry_count
; i
++ )
4271 if( isom_write_sgpd( bs
, trak
, i
) )
4273 if( stbl
->sbgp_list
)
4274 for( uint32_t i
= 1; i
<= stbl
->sbgp_list
->entry_count
; i
++ )
4275 if( isom_write_sbgp( bs
, trak
, i
) )
4280 static int isom_write_minf( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4282 isom_minf_t
*minf
= trak
->mdia
->minf
;
4285 isom_bs_put_box_common( bs
, minf
);
4286 if( lsmash_bs_write_data( bs
) )
4288 if( (minf
->vmhd
&& isom_write_vmhd( bs
, trak
))
4289 || (minf
->smhd
&& isom_write_smhd( bs
, trak
))
4290 || (minf
->hmhd
&& isom_write_hmhd( bs
, trak
))
4291 || (minf
->nmhd
&& isom_write_nmhd( bs
, trak
))
4292 || (minf
->gmhd
&& isom_write_gmhd( bs
, trak
)) )
4294 if( isom_write_hdlr( bs
, trak
, 0 )
4295 || isom_write_dinf( bs
, trak
)
4296 || isom_write_stbl( bs
, trak
) )
4301 static int isom_write_mdia( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4303 isom_mdia_t
*mdia
= trak
->mdia
;
4306 isom_bs_put_box_common( bs
, mdia
);
4307 if( lsmash_bs_write_data( bs
) )
4309 if( isom_write_mdhd( bs
, trak
)
4310 || isom_write_hdlr( bs
, trak
, 1 )
4311 || isom_write_minf( bs
, trak
) )
4316 static int isom_write_chpl( lsmash_bs_t
*bs
, isom_chpl_t
*chpl
)
4320 if( !chpl
->list
|| chpl
->version
> 1 )
4322 isom_bs_put_box_common( bs
, chpl
);
4323 if( chpl
->version
== 1 )
4325 lsmash_bs_put_byte( bs
, chpl
->unknown
);
4326 lsmash_bs_put_be32( bs
, chpl
->list
->entry_count
);
4328 else /* chpl->version == 0 */
4329 lsmash_bs_put_byte( bs
, (uint8_t)chpl
->list
->entry_count
);
4330 for( lsmash_entry_t
*entry
= chpl
->list
->head
; entry
; entry
= entry
->next
)
4332 isom_chpl_entry_t
*data
= (isom_chpl_entry_t
*)entry
->data
;
4335 lsmash_bs_put_be64( bs
, data
->start_time
);
4336 lsmash_bs_put_byte( bs
, data
->chapter_name_length
);
4337 lsmash_bs_put_bytes( bs
, data
->chapter_name
, data
->chapter_name_length
);
4339 return lsmash_bs_write_data( bs
);
4342 static int isom_write_udta( lsmash_bs_t
*bs
, isom_moov_t
*moov
, isom_trak_entry_t
*trak
)
4344 /* Setting non-NULL pointer to trak means trak->udta data will be written in stream.
4345 * If trak is set by NULL while moov is set by non-NULL pointer, moov->udta data will be written in stream. */
4346 isom_udta_t
*udta
= trak
? trak
->udta
: moov
? moov
->udta
: NULL
;
4349 isom_bs_put_box_common( bs
, udta
);
4350 if( lsmash_bs_write_data( bs
) )
4352 if( moov
&& isom_write_chpl( bs
, udta
->chpl
) )
4357 static int isom_write_trak( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4361 isom_bs_put_box_common( bs
, trak
);
4362 if( lsmash_bs_write_data( bs
) )
4364 if( isom_write_tkhd( bs
, trak
)
4365 || isom_write_tapt( bs
, trak
)
4366 || isom_write_edts( bs
, trak
)
4367 || isom_write_tref( bs
, trak
)
4368 || isom_write_mdia( bs
, trak
)
4369 || isom_write_udta( bs
, NULL
, trak
) )
4374 static int isom_write_iods( lsmash_root_t
*root
)
4376 if( !root
|| !root
->moov
)
4378 if( !root
->moov
->iods
)
4380 isom_iods_t
*iods
= root
->moov
->iods
;
4381 lsmash_bs_t
*bs
= root
->bs
;
4382 isom_bs_put_box_common( bs
, iods
);
4383 return mp4sys_write_ObjectDescriptor( bs
, iods
->OD
);
4386 static int isom_write_mvhd( lsmash_root_t
*root
)
4388 if( !root
|| !root
->moov
|| !root
->moov
->mvhd
)
4390 isom_mvhd_t
*mvhd
= root
->moov
->mvhd
;
4391 lsmash_bs_t
*bs
= root
->bs
;
4392 isom_bs_put_box_common( bs
, mvhd
);
4395 lsmash_bs_put_be64( bs
, mvhd
->creation_time
);
4396 lsmash_bs_put_be64( bs
, mvhd
->modification_time
);
4397 lsmash_bs_put_be32( bs
, mvhd
->timescale
);
4398 lsmash_bs_put_be64( bs
, mvhd
->duration
);
4402 lsmash_bs_put_be32( bs
, (uint32_t)mvhd
->creation_time
);
4403 lsmash_bs_put_be32( bs
, (uint32_t)mvhd
->modification_time
);
4404 lsmash_bs_put_be32( bs
, mvhd
->timescale
);
4405 lsmash_bs_put_be32( bs
, (uint32_t)mvhd
->duration
);
4407 lsmash_bs_put_be32( bs
, mvhd
->rate
);
4408 lsmash_bs_put_be16( bs
, mvhd
->volume
);
4409 lsmash_bs_put_be16( bs
, mvhd
->reserved
);
4410 lsmash_bs_put_be32( bs
, mvhd
->preferredLong
[0] );
4411 lsmash_bs_put_be32( bs
, mvhd
->preferredLong
[1] );
4412 for( int i
= 0; i
< 9; i
++ )
4413 lsmash_bs_put_be32( bs
, mvhd
->matrix
[i
] );
4414 lsmash_bs_put_be32( bs
, mvhd
->previewTime
);
4415 lsmash_bs_put_be32( bs
, mvhd
->previewDuration
);
4416 lsmash_bs_put_be32( bs
, mvhd
->posterTime
);
4417 lsmash_bs_put_be32( bs
, mvhd
->selectionTime
);
4418 lsmash_bs_put_be32( bs
, mvhd
->selectionDuration
);
4419 lsmash_bs_put_be32( bs
, mvhd
->currentTime
);
4420 lsmash_bs_put_be32( bs
, mvhd
->next_track_ID
);
4421 return lsmash_bs_write_data( bs
);
4424 static void isom_bs_put_sample_flags( lsmash_bs_t
*bs
, isom_sample_flags_t
*flags
)
4426 uint32_t temp
= (flags
->reserved
<< 28)
4427 | (flags
->is_leading
<< 26)
4428 | (flags
->sample_depends_on
<< 24)
4429 | (flags
->sample_is_depended_on
<< 22)
4430 | (flags
->sample_has_redundancy
<< 20)
4431 | (flags
->sample_padding_value
<< 17)
4432 | (flags
->sample_is_non_sync_sample
<< 16)
4433 | flags
->sample_degradation_priority
;
4434 lsmash_bs_put_be32( bs
, temp
);
4437 static int isom_write_mehd( lsmash_bs_t
*bs
, isom_mehd_t
*mehd
)
4441 isom_bs_put_box_common( bs
, mehd
);
4442 if( mehd
->version
== 1 )
4443 lsmash_bs_put_be64( bs
, mehd
->fragment_duration
);
4445 lsmash_bs_put_be32( bs
, (uint32_t)mehd
->fragment_duration
);
4446 return lsmash_bs_write_data( bs
);
4449 static int isom_write_trex( lsmash_bs_t
*bs
, isom_trex_entry_t
*trex
)
4453 isom_bs_put_box_common( bs
, trex
);
4454 lsmash_bs_put_be32( bs
, trex
->track_ID
);
4455 lsmash_bs_put_be32( bs
, trex
->default_sample_description_index
);
4456 lsmash_bs_put_be32( bs
, trex
->default_sample_duration
);
4457 lsmash_bs_put_be32( bs
, trex
->default_sample_size
);
4458 isom_bs_put_sample_flags( bs
, &trex
->default_sample_flags
);
4459 return lsmash_bs_write_data( bs
);
4462 static int isom_bs_write_movie_extends_placeholder( lsmash_bs_t
*bs
)
4464 /* The following will be overwritten by Movie Extends Header Box.
4465 * We use version 1 Movie Extends Header Box since it causes extra 4 bytes region
4466 * we cannot replace with empty Free Space Box as we place version 0 one. */
4467 lsmash_bs_put_be32( bs
, ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ 8 );
4468 lsmash_bs_put_be32( bs
, ISOM_BOX_TYPE_FREE
);
4469 lsmash_bs_put_be32( bs
, 0 );
4470 lsmash_bs_put_be64( bs
, 0 );
4471 return lsmash_bs_write_data( bs
);
4474 static int isom_write_mvex( lsmash_bs_t
*bs
, isom_mvex_t
*mvex
)
4478 isom_bs_put_box_common( bs
, mvex
);
4479 if( lsmash_bs_write_data( bs
) )
4481 /* Movie Extends Header Box is not written immediately.
4482 * It's done after finishing all movie fragments. */
4485 if( isom_write_mehd( bs
, mvex
->mehd
) )
4488 else if( bs
->stream
!= stdout
)
4500 |--[mehd] <--- mehd->pos == mvex->placeholder_pos
4502 mvex
->placeholder_pos
= mvex
->root
->bs
->written
;
4503 if( isom_bs_write_movie_extends_placeholder( bs
) )
4506 if( mvex
->trex_list
)
4507 for( lsmash_entry_t
*entry
= mvex
->trex_list
->head
; entry
; entry
= entry
->next
)
4508 if( isom_write_trex( bs
, (isom_trex_entry_t
*)entry
->data
) )
4513 static int isom_write_mfhd( lsmash_bs_t
*bs
, isom_mfhd_t
*mfhd
)
4517 isom_bs_put_box_common( bs
, mfhd
);
4518 lsmash_bs_put_be32( bs
, mfhd
->sequence_number
);
4519 return lsmash_bs_write_data( bs
);
4522 static int isom_write_tfhd( lsmash_bs_t
*bs
, isom_tfhd_t
*tfhd
)
4526 isom_bs_put_box_common( bs
, tfhd
);
4527 lsmash_bs_put_be32( bs
, tfhd
->track_ID
);
4528 if( tfhd
->flags
& ISOM_TF_FLAGS_BASE_DATA_OFFSET_PRESENT
) lsmash_bs_put_be64( bs
, tfhd
->base_data_offset
);
4529 if( tfhd
->flags
& ISOM_TF_FLAGS_SAMPLE_DESCRIPTION_INDEX_PRESENT
) lsmash_bs_put_be32( bs
, tfhd
->sample_description_index
);
4530 if( tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT
) lsmash_bs_put_be32( bs
, tfhd
->default_sample_duration
);
4531 if( tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_SAMPLE_SIZE_PRESENT
) lsmash_bs_put_be32( bs
, tfhd
->default_sample_size
);
4532 if( tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_SAMPLE_FLAGS_PRESENT
) isom_bs_put_sample_flags( bs
, &tfhd
->default_sample_flags
);
4533 return lsmash_bs_write_data( bs
);
4536 static int isom_write_trun( lsmash_bs_t
*bs
, isom_trun_entry_t
*trun
)
4540 isom_bs_put_box_common( bs
, trun
);
4541 lsmash_bs_put_be32( bs
, trun
->sample_count
);
4542 if( trun
->flags
& ISOM_TR_FLAGS_DATA_OFFSET_PRESENT
) lsmash_bs_put_be32( bs
, trun
->data_offset
);
4543 if( trun
->flags
& ISOM_TR_FLAGS_FIRST_SAMPLE_FLAGS_PRESENT
) isom_bs_put_sample_flags( bs
, &trun
->first_sample_flags
);
4544 if( trun
->optional
)
4545 for( lsmash_entry_t
*entry
= trun
->optional
->head
; entry
; entry
= entry
->next
)
4547 isom_trun_optional_row_t
*data
= (isom_trun_optional_row_t
*)entry
->data
;
4550 if( trun
->flags
& ISOM_TR_FLAGS_SAMPLE_DURATION_PRESENT
) lsmash_bs_put_be32( bs
, data
->sample_duration
);
4551 if( trun
->flags
& ISOM_TR_FLAGS_SAMPLE_SIZE_PRESENT
) lsmash_bs_put_be32( bs
, data
->sample_size
);
4552 if( trun
->flags
& ISOM_TR_FLAGS_SAMPLE_FLAGS_PRESENT
) isom_bs_put_sample_flags( bs
, &data
->sample_flags
);
4553 if( trun
->flags
& ISOM_TR_FLAGS_SAMPLE_COMPOSITION_TIME_OFFSET_PRESENT
) lsmash_bs_put_be32( bs
, data
->sample_composition_time_offset
);
4555 return lsmash_bs_write_data( bs
);
4558 static int isom_write_traf( lsmash_bs_t
*bs
, isom_traf_entry_t
*traf
)
4562 isom_bs_put_box_common( bs
, traf
);
4563 if( lsmash_bs_write_data( bs
) )
4565 if( isom_write_tfhd( bs
, traf
->tfhd
) )
4567 if( traf
->trun_list
)
4568 for( lsmash_entry_t
*entry
= traf
->trun_list
->head
; entry
; entry
= entry
->next
)
4569 if( isom_write_trun( bs
, (isom_trun_entry_t
*)entry
->data
) )
4574 static int isom_write_moof( lsmash_bs_t
*bs
, isom_moof_entry_t
*moof
)
4578 isom_bs_put_box_common( bs
, moof
);
4579 if( lsmash_bs_write_data( bs
) )
4581 if( isom_write_mfhd( bs
, moof
->mfhd
) )
4583 if( moof
->traf_list
)
4584 for( lsmash_entry_t
*entry
= moof
->traf_list
->head
; entry
; entry
= entry
->next
)
4585 if( isom_write_traf( bs
, (isom_traf_entry_t
*)entry
->data
) )
4590 static int isom_write_tfra( lsmash_bs_t
*bs
, isom_tfra_entry_t
*tfra
)
4594 isom_bs_put_box_common( bs
, tfra
);
4595 uint32_t temp
= (tfra
->reserved
<< 6)
4596 | (tfra
->length_size_of_traf_num
<< 4)
4597 | (tfra
->length_size_of_trun_num
<< 2)
4598 | tfra
->length_size_of_sample_num
;
4599 lsmash_bs_put_be32( bs
, tfra
->track_ID
);
4600 lsmash_bs_put_be32( bs
, temp
);
4601 lsmash_bs_put_be32( bs
, tfra
->number_of_entry
);
4604 void (*bs_put_funcs
[5])( lsmash_bs_t
*, uint64_t ) =
4606 lsmash_bs_put_byte_from_64
,
4607 lsmash_bs_put_be16_from_64
,
4608 lsmash_bs_put_be24_from_64
,
4609 lsmash_bs_put_be32_from_64
,
4612 void (*bs_put_time
) ( lsmash_bs_t
*, uint64_t ) = bs_put_funcs
[ 3 + (tfra
->version
== 1) ];
4613 void (*bs_put_moof_offset
) ( lsmash_bs_t
*, uint64_t ) = bs_put_funcs
[ 3 + (tfra
->version
== 1) ];
4614 void (*bs_put_traf_number
) ( lsmash_bs_t
*, uint64_t ) = bs_put_funcs
[ tfra
->length_size_of_traf_num
];
4615 void (*bs_put_trun_number
) ( lsmash_bs_t
*, uint64_t ) = bs_put_funcs
[ tfra
->length_size_of_trun_num
];
4616 void (*bs_put_sample_number
)( lsmash_bs_t
*, uint64_t ) = bs_put_funcs
[ tfra
->length_size_of_sample_num
];
4617 for( lsmash_entry_t
*entry
= tfra
->list
->head
; entry
; entry
= entry
->next
)
4619 isom_tfra_location_time_entry_t
*data
= (isom_tfra_location_time_entry_t
*)entry
->data
;
4622 bs_put_time ( bs
, data
->time
);
4623 bs_put_moof_offset ( bs
, data
->moof_offset
);
4624 bs_put_traf_number ( bs
, data
->traf_number
);
4625 bs_put_trun_number ( bs
, data
->trun_number
);
4626 bs_put_sample_number( bs
, data
->sample_number
);
4629 return lsmash_bs_write_data( bs
);
4632 static int isom_write_mfro( lsmash_bs_t
*bs
, isom_mfro_t
*mfro
)
4636 isom_bs_put_box_common( bs
, mfro
);
4637 lsmash_bs_put_be32( bs
, mfro
->length
);
4638 return lsmash_bs_write_data( bs
);
4641 static int isom_write_mfra( lsmash_bs_t
*bs
, isom_mfra_t
*mfra
)
4645 isom_bs_put_box_common( bs
, mfra
);
4646 if( lsmash_bs_write_data( bs
) )
4648 if( mfra
->tfra_list
)
4649 for( lsmash_entry_t
*entry
= mfra
->tfra_list
->head
; entry
; entry
= entry
->next
)
4650 if( isom_write_tfra( bs
, (isom_tfra_entry_t
*)entry
->data
) )
4652 return isom_write_mfro( bs
, mfra
->mfro
);
4655 static int isom_bs_write_largesize_placeholder( lsmash_bs_t
*bs
)
4657 lsmash_bs_put_be32( bs
, ISOM_DEFAULT_BOX_HEADER_SIZE
);
4658 lsmash_bs_put_be32( bs
, ISOM_BOX_TYPE_FREE
);
4659 return lsmash_bs_write_data( bs
);
4662 static int isom_write_mdat_header( lsmash_root_t
*root
, uint64_t media_size
)
4664 if( !root
|| !root
->bs
|| !root
->mdat
)
4666 isom_mdat_t
*mdat
= root
->mdat
;
4667 lsmash_bs_t
*bs
= root
->bs
;
4670 mdat
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
+ media_size
;
4671 if( mdat
->size
> UINT32_MAX
)
4672 mdat
->size
+= 8; /* large_size */
4673 isom_bs_put_box_common( bs
, mdat
);
4676 mdat
->placeholder_pos
= lsmash_ftell( bs
->stream
);
4677 if( isom_bs_write_largesize_placeholder( bs
) )
4679 mdat
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
;
4680 isom_bs_put_box_common( bs
, mdat
);
4681 return lsmash_bs_write_data( bs
);
4684 static int isom_write_mdat_size( lsmash_root_t
*root
)
4686 if( !root
|| !root
->bs
|| !root
->bs
->stream
)
4690 isom_mdat_t
*mdat
= root
->mdat
;
4691 uint8_t large_flag
= mdat
->size
> UINT32_MAX
;
4692 lsmash_bs_t
*bs
= root
->bs
;
4693 FILE *stream
= bs
->stream
;
4694 uint64_t current_pos
= lsmash_ftell( stream
);
4697 lsmash_fseek( stream
, mdat
->placeholder_pos
, SEEK_SET
);
4698 lsmash_bs_put_be32( bs
, 1 );
4699 lsmash_bs_put_be32( bs
, ISOM_BOX_TYPE_MDAT
);
4700 lsmash_bs_put_be64( bs
, mdat
->size
+ ISOM_DEFAULT_BOX_HEADER_SIZE
);
4704 lsmash_fseek( stream
, mdat
->placeholder_pos
+ ISOM_DEFAULT_BOX_HEADER_SIZE
, SEEK_SET
);
4705 lsmash_bs_put_be32( bs
, mdat
->size
);
4706 lsmash_bs_put_be32( bs
, ISOM_BOX_TYPE_MDAT
);
4708 int ret
= lsmash_bs_write_data( bs
);
4709 lsmash_fseek( stream
, current_pos
, SEEK_SET
);
4713 /* We put a placeholder for 64-bit media data if the media_size of the argument is set to 0.
4714 * If a Media Data Box already exists and we don't pick movie fragments structure,
4715 * write the actual size of the current one and start a new one. */
4716 static int isom_new_mdat( lsmash_root_t
*root
, uint64_t media_size
)
4722 /* Write the actual size of the current Media Data Box. */
4723 if( !root
->fragment
&& isom_write_mdat_size( root
) )
4728 isom_create_box( mdat
, root
, ISOM_BOX_TYPE_MDAT
);
4731 /* Start a new Media Data Box. */
4732 return isom_write_mdat_header( root
, media_size
);
4735 int isom_check_compatibility( lsmash_root_t
*root
)
4739 root
->qt_compatible
= 0;
4740 /* Check brand to decide mandatory boxes. */
4741 if( !root
->ftyp
|| !root
->ftyp
->brand_count
)
4743 /* No brand declaration means this file is a MP4 version 1 or QuickTime file format. */
4744 if( root
->moov
&& root
->moov
->iods
)
4746 root
->mp4_version1
= 1;
4747 root
->isom_compatible
= 1;
4750 root
->qt_compatible
= 1;
4753 for( uint32_t i
= 0; i
< root
->ftyp
->brand_count
; i
++ )
4755 switch( root
->ftyp
->compatible_brands
[i
] )
4757 case ISOM_BRAND_TYPE_QT
:
4758 root
->qt_compatible
= 1;
4760 case ISOM_BRAND_TYPE_MP41
:
4761 root
->mp4_version1
= 1;
4763 case ISOM_BRAND_TYPE_MP42
:
4764 root
->mp4_version2
= 1;
4766 case ISOM_BRAND_TYPE_ISOM
:
4767 root
->max_isom_version
= LSMASH_MAX( root
->max_isom_version
, 1 );
4769 case ISOM_BRAND_TYPE_ISO2
:
4770 root
->max_isom_version
= LSMASH_MAX( root
->max_isom_version
, 2 );
4772 case ISOM_BRAND_TYPE_ISO3
:
4773 root
->max_isom_version
= LSMASH_MAX( root
->max_isom_version
, 3 );
4775 case ISOM_BRAND_TYPE_ISO4
:
4776 root
->max_isom_version
= LSMASH_MAX( root
->max_isom_version
, 4 );
4778 case ISOM_BRAND_TYPE_ISO5
:
4779 root
->max_isom_version
= LSMASH_MAX( root
->max_isom_version
, 5 );
4781 case ISOM_BRAND_TYPE_ISO6
:
4782 root
->max_isom_version
= LSMASH_MAX( root
->max_isom_version
, 6 );
4784 case ISOM_BRAND_TYPE_M4A
:
4785 case ISOM_BRAND_TYPE_M4B
:
4786 root
->itunes_audio
= 1;
4788 case ISOM_BRAND_TYPE_3GP4
:
4789 root
->max_3gpp_version
= LSMASH_MAX( root
->max_3gpp_version
, 4 );
4791 case ISOM_BRAND_TYPE_3GP5
:
4792 root
->max_3gpp_version
= LSMASH_MAX( root
->max_3gpp_version
, 5 );
4794 case ISOM_BRAND_TYPE_3GE6
:
4795 case ISOM_BRAND_TYPE_3GG6
:
4796 case ISOM_BRAND_TYPE_3GP6
:
4797 case ISOM_BRAND_TYPE_3GR6
:
4798 case ISOM_BRAND_TYPE_3GS6
:
4799 root
->max_3gpp_version
= LSMASH_MAX( root
->max_3gpp_version
, 6 );
4804 switch( root
->ftyp
->compatible_brands
[i
] )
4806 case ISOM_BRAND_TYPE_AVC1
:
4807 case ISOM_BRAND_TYPE_ISO2
:
4808 case ISOM_BRAND_TYPE_ISO3
:
4809 case ISOM_BRAND_TYPE_ISO4
:
4810 case ISOM_BRAND_TYPE_ISO5
:
4811 case ISOM_BRAND_TYPE_ISO6
:
4812 root
->avc_extensions
= 1;
4818 root
->isom_compatible
= !root
->qt_compatible
|| root
->mp4_version1
|| root
->mp4_version2
|| root
->itunes_audio
|| root
->max_3gpp_version
;
4822 static uint32_t isom_get_sample_count( isom_trak_entry_t
*trak
)
4824 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
|| !trak
->mdia
->minf
->stbl
->stsz
)
4826 return trak
->mdia
->minf
->stbl
->stsz
->sample_count
;
4829 static uint64_t isom_get_dts( isom_stts_t
*stts
, uint32_t sample_number
)
4831 if( !stts
|| !stts
->list
)
4835 lsmash_entry_t
*entry
;
4836 isom_stts_entry_t
*data
;
4837 for( entry
= stts
->list
->head
; entry
; entry
= entry
->next
)
4839 data
= (isom_stts_entry_t
*)entry
->data
;
4842 if( i
+ data
->sample_count
> sample_number
)
4844 dts
+= (uint64_t)data
->sample_delta
* data
->sample_count
;
4845 i
+= data
->sample_count
;
4849 dts
+= (uint64_t)data
->sample_delta
* (sample_number
- i
);
4854 static uint64_t isom_get_cts( isom_stts_t
*stts
, isom_ctts_t
*ctts
, uint32_t sample_number
)
4856 if( !stts
|| !stts
->list
)
4859 return isom_get_dts( stts
, sample_number
);
4860 uint32_t i
= 1; /* This can be 0 (and then condition below shall be changed) but I dare use same algorithm with isom_get_dts. */
4861 lsmash_entry_t
*entry
;
4862 isom_ctts_entry_t
*data
;
4863 if( sample_number
== 0 )
4865 for( entry
= ctts
->list
->head
; entry
; entry
= entry
->next
)
4867 data
= (isom_ctts_entry_t
*)entry
->data
;
4870 if( i
+ data
->sample_count
> sample_number
)
4872 i
+= data
->sample_count
;
4876 return isom_get_dts( stts
, sample_number
) + data
->sample_offset
;
4880 static int isom_replace_last_sample_delta( isom_stbl_t
*stbl
, uint32_t sample_delta
)
4882 if( !stbl
|| !stbl
->stts
|| !stbl
->stts
->list
|| !stbl
->stts
->list
->tail
|| !stbl
->stts
->list
->tail
->data
)
4884 isom_stts_entry_t
*last_stts_data
= (isom_stts_entry_t
*)stbl
->stts
->list
->tail
->data
;
4885 if( sample_delta
!= last_stts_data
->sample_delta
)
4887 if( last_stts_data
->sample_count
> 1 )
4889 last_stts_data
->sample_count
-= 1;
4890 if( isom_add_stts_entry( stbl
, sample_delta
) )
4894 last_stts_data
->sample_delta
= sample_delta
;
4899 static int isom_update_mdhd_duration( isom_trak_entry_t
*trak
, uint32_t last_sample_delta
)
4901 if( !trak
|| !trak
->root
|| !trak
->mdia
|| !trak
->mdia
->mdhd
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
4902 || !trak
->mdia
->minf
->stbl
->stts
|| !trak
->mdia
->minf
->stbl
->stts
->list
)
4904 lsmash_root_t
*root
= trak
->root
;
4905 isom_mdhd_t
*mdhd
= trak
->mdia
->mdhd
;
4906 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
4907 isom_stts_t
*stts
= stbl
->stts
;
4908 isom_ctts_t
*ctts
= stbl
->ctts
;
4909 isom_cslg_t
*cslg
= stbl
->cslg
;
4911 uint32_t sample_count
= isom_get_sample_count( trak
);
4914 /* Return error if non-fragmented movie has no samples. */
4915 if( !root
->fragment
&& !stts
->list
->entry_count
)
4919 /* Now we have at least 1 sample, so do stts_entry. */
4920 lsmash_entry_t
*last_stts
= stts
->list
->tail
;
4921 isom_stts_entry_t
*last_stts_data
= (isom_stts_entry_t
*)last_stts
->data
;
4922 if( sample_count
== 1 )
4923 mdhd
->duration
= last_stts_data
->sample_delta
;
4924 /* Now we have at least 2 samples,
4925 * but dunno whether 1 stts_entry which has 2 samples or 2 stts_entry which has 1 samle each. */
4928 /* use dts instead of cts */
4929 mdhd
->duration
= isom_get_dts( stts
, sample_count
);
4930 if( last_sample_delta
)
4932 mdhd
->duration
+= last_sample_delta
;
4933 if( isom_replace_last_sample_delta( stbl
, last_sample_delta
) )
4936 else if( last_stts_data
->sample_count
> 1 )
4937 mdhd
->duration
+= last_stts_data
->sample_delta
; /* no need to update last_stts_data->sample_delta */
4940 /* Remove the last entry. */
4941 if( lsmash_remove_entry( stts
->list
, stts
->list
->entry_count
, NULL
) )
4943 /* copy the previous sample_delta. */
4944 ++ ((isom_stts_entry_t
*)stts
->list
->tail
->data
)->sample_count
;
4945 mdhd
->duration
+= ((isom_stts_entry_t
*)stts
->list
->tail
->data
)->sample_delta
;
4950 if( !ctts
->list
|| ctts
->list
->entry_count
== 0 )
4953 uint64_t max_cts
= 0, max2_cts
= 0, min_cts
= UINT64_MAX
;
4954 uint32_t max_offset
= 0, min_offset
= UINT32_MAX
;
4956 lsmash_entry_t
*stts_entry
= stts
->list
->head
;
4957 lsmash_entry_t
*ctts_entry
= ctts
->list
->head
;
4959 for( uint32_t i
= 0; i
< sample_count
; i
++ )
4961 if( !ctts_entry
|| !stts_entry
)
4963 isom_stts_entry_t
*stts_data
= (isom_stts_entry_t
*)stts_entry
->data
;
4964 isom_ctts_entry_t
*ctts_data
= (isom_ctts_entry_t
*)ctts_entry
->data
;
4965 if( !stts_data
|| !ctts_data
)
4967 uint64_t cts
= dts
+ ctts_data
->sample_offset
;
4968 min_cts
= LSMASH_MIN( min_cts
, cts
);
4969 max_offset
= LSMASH_MAX( max_offset
, ctts_data
->sample_offset
);
4970 min_offset
= LSMASH_MIN( min_offset
, ctts_data
->sample_offset
);
4976 else if( max2_cts
< cts
)
4978 dts
+= stts_data
->sample_delta
;
4979 /* If finished sample_count of current entry, move to next. */
4980 if( ++j
== ctts_data
->sample_count
)
4982 ctts_entry
= ctts_entry
->next
;
4985 if( ++k
== stts_data
->sample_count
)
4987 stts_entry
= stts_entry
->next
;
4991 dts
-= last_stts_data
->sample_delta
;
4992 if( root
->fragment
)
4993 /* Overall presentation is extended exceeding this initial movie.
4994 * So, any players shall display the movie exceeding the durations
4995 * indicated in Movie Header Box, Track Header Boxes and Media Header Boxes.
4996 * Samples up to the duration indicated in Movie Extends Header Box shall be displayed.
4997 * In the absence of Movie Extends Header Box, all samples shall be displayed. */
4998 mdhd
->duration
+= dts
+ last_sample_delta
;
5001 if( !last_sample_delta
)
5003 /* The spec allows an arbitrary value for the duration of the last sample. So, we pick last-1 sample's. */
5004 last_sample_delta
= max_cts
- max2_cts
;
5006 mdhd
->duration
= max_cts
- min_cts
+ last_sample_delta
;
5007 /* To match dts and media duration, update stts and mdhd relatively. */
5008 if( mdhd
->duration
> dts
)
5009 last_sample_delta
= mdhd
->duration
- dts
;
5011 mdhd
->duration
= dts
+ last_sample_delta
; /* media duration must not less than last dts. */
5013 if( isom_replace_last_sample_delta( stbl
, last_sample_delta
) )
5015 /* Explicit composition information and DTS shifting */
5016 if( cslg
|| root
->qt_compatible
|| root
->max_isom_version
>= 4 )
5018 int64_t composition_end_time
= max_cts
+ (max_cts
- max2_cts
);
5020 && (min_offset
<= INT32_MAX
) && (max_offset
<= INT32_MAX
)
5021 && (min_cts
<= INT32_MAX
) && (composition_end_time
<= INT32_MAX
) )
5025 if( isom_add_cslg( trak
->mdia
->minf
->stbl
) )
5029 cslg
->compositionToDTSShift
= 0; /* We don't consider DTS shifting at present. */
5030 cslg
->leastDecodeToDisplayDelta
= min_offset
;
5031 cslg
->greatestDecodeToDisplayDelta
= max_offset
;
5032 cslg
->compositionStartTime
= min_cts
;
5033 cslg
->compositionEndTime
= composition_end_time
;
5043 if( mdhd
->duration
> UINT32_MAX
)
5048 static int isom_update_mvhd_duration( isom_moov_t
*moov
)
5050 if( !moov
|| !moov
->mvhd
)
5052 isom_mvhd_t
*mvhd
= moov
->mvhd
;
5054 for( lsmash_entry_t
*entry
= moov
->trak_list
->head
; entry
; entry
= entry
->next
)
5056 /* We pick maximum track duration as movie duration. */
5057 isom_trak_entry_t
*data
= (isom_trak_entry_t
*)entry
->data
;
5058 if( !data
|| !data
->tkhd
)
5060 mvhd
->duration
= entry
!= moov
->trak_list
->head
? LSMASH_MAX( mvhd
->duration
, data
->tkhd
->duration
) : data
->tkhd
->duration
;
5062 if( mvhd
->duration
> UINT32_MAX
)
5067 static int isom_update_tkhd_duration( isom_trak_entry_t
*trak
)
5069 if( !trak
|| !trak
->tkhd
|| !trak
->root
|| !trak
->root
->moov
)
5071 lsmash_root_t
*root
= trak
->root
;
5072 isom_tkhd_t
*tkhd
= trak
->tkhd
;
5074 if( root
->fragment
|| !trak
->edts
|| !trak
->edts
->elst
)
5076 /* If this presentation might be extended or this track doesn't have edit list, calculate track duration from media duration. */
5077 if( !trak
->mdia
|| !trak
->mdia
->mdhd
|| !root
->moov
->mvhd
|| !trak
->mdia
->mdhd
->timescale
)
5079 if( !trak
->mdia
->mdhd
->duration
&& isom_update_mdhd_duration( trak
, 0 ) )
5081 tkhd
->duration
= trak
->mdia
->mdhd
->duration
* ((double)root
->moov
->mvhd
->timescale
/ trak
->mdia
->mdhd
->timescale
);
5085 /* If the presentation won't be extended and this track has any edit, then track duration is just the sum of the segment_duartions. */
5086 for( lsmash_entry_t
*entry
= trak
->edts
->elst
->list
->head
; entry
; entry
= entry
->next
)
5088 isom_elst_entry_t
*data
= (isom_elst_entry_t
*)entry
->data
;
5091 tkhd
->duration
+= data
->segment_duration
;
5094 if( tkhd
->duration
> UINT32_MAX
)
5096 if( !root
->fragment
&& !tkhd
->duration
)
5097 tkhd
->duration
= tkhd
->version
== 1 ? 0xffffffffffffffff : 0xffffffff;
5098 return isom_update_mvhd_duration( root
->moov
);
5101 int lsmash_update_track_duration( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t last_sample_delta
)
5103 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
5106 if( isom_update_mdhd_duration( trak
, last_sample_delta
) )
5108 /* If the presentation won't be extended and this track has any edit, we don't change or update duration in tkhd. */
5109 return (!root
->fragment
&& trak
->edts
&& trak
->edts
->elst
)
5110 ? isom_update_mvhd_duration( root
->moov
) /* Only update movie duration. */
5111 : isom_update_tkhd_duration( trak
); /* Also update movie duration internally. */
5114 int lsmash_set_avc_config( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t entry_number
,
5115 uint8_t configurationVersion
, uint8_t AVCProfileIndication
, uint8_t profile_compatibility
, uint8_t AVCLevelIndication
, uint8_t lengthSizeMinusOne
,
5116 uint8_t chroma_format
, uint8_t bit_depth_luma_minus8
, uint8_t bit_depth_chroma_minus8
)
5118 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
5119 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
|| !trak
->mdia
->minf
->stbl
->stsd
|| !trak
->mdia
->minf
->stbl
->stsd
->list
)
5121 isom_visual_entry_t
*data
= (isom_visual_entry_t
*)lsmash_get_entry_data( trak
->mdia
->minf
->stbl
->stsd
->list
, entry_number
);
5124 isom_avcC_t
*avcC
= (isom_avcC_t
*)data
->avcC
;
5127 avcC
->configurationVersion
= configurationVersion
;
5128 avcC
->AVCProfileIndication
= AVCProfileIndication
;
5129 avcC
->profile_compatibility
= profile_compatibility
;
5130 avcC
->AVCLevelIndication
= AVCLevelIndication
;
5131 avcC
->lengthSizeMinusOne
= lengthSizeMinusOne
;
5132 if( ISOM_REQUIRES_AVCC_EXTENSION( AVCProfileIndication
) )
5134 avcC
->chroma_format
= chroma_format
;
5135 avcC
->bit_depth_luma_minus8
= bit_depth_luma_minus8
;
5136 avcC
->bit_depth_chroma_minus8
= bit_depth_chroma_minus8
;
5141 static int isom_update_bitrate_info( isom_mdia_t
*mdia
)
5143 if( !mdia
|| !mdia
->mdhd
|| !mdia
->minf
|| !mdia
->minf
->stbl
5144 || !mdia
->minf
->stbl
->stsd
|| !mdia
->minf
->stbl
->stsd
->list
5145 || !mdia
->minf
->stbl
->stsz
|| !mdia
->minf
->stbl
->stts
|| !mdia
->minf
->stbl
->stts
->list
)
5147 /* Not supporting multi sample entries yet. */
5148 isom_sample_entry_t
*sample_entry
= (isom_sample_entry_t
*)lsmash_get_entry_data( mdia
->minf
->stbl
->stsd
->list
, 1 );
5151 struct bitrate_info_t
5153 uint32_t bufferSizeDB
;
5154 uint32_t maxBitrate
;
5155 uint32_t avgBitrate
;
5156 } info
= { 0, 0, 0 };
5159 uint32_t time_wnd
= 0;
5160 uint32_t timescale
= mdia
->mdhd
->timescale
;
5162 isom_stsz_t
*stsz
= mdia
->minf
->stbl
->stsz
;
5163 lsmash_entry_t
*stsz_entry
= stsz
->list
? stsz
->list
->head
: NULL
;
5164 lsmash_entry_t
*stts_entry
= mdia
->minf
->stbl
->stts
->list
->head
;
5165 isom_stts_entry_t
*stts_data
= NULL
;
5173 isom_stsz_entry_t
*stsz_data
= (isom_stsz_entry_t
*)stsz_entry
->data
;
5176 size
= stsz_data
->entry_size
;
5177 stsz_entry
= stsz_entry
->next
;
5180 size
= stsz
->sample_size
;
5182 dts
+= stts_data
->sample_delta
;
5183 stts_data
= (isom_stts_entry_t
*)stts_entry
->data
;
5184 if( ++i
== stts_data
->sample_count
)
5186 stts_entry
= stts_entry
->next
;
5189 if( info
.bufferSizeDB
< size
)
5190 info
.bufferSizeDB
= size
;
5191 info
.avgBitrate
+= size
;
5193 if( dts
> time_wnd
+ timescale
)
5195 if( rate
> info
.maxBitrate
)
5196 info
.maxBitrate
= rate
;
5201 double duration
= (double)mdia
->mdhd
->duration
/ timescale
;
5202 info
.avgBitrate
= (uint32_t)(info
.avgBitrate
/ duration
);
5203 if( !info
.maxBitrate
)
5204 info
.maxBitrate
= info
.avgBitrate
;
5206 info
.maxBitrate
*= 8;
5207 info
.avgBitrate
*= 8;
5208 /* set bitrate info */
5209 switch( sample_entry
->type
)
5211 case ISOM_CODEC_TYPE_AVC1_VIDEO
:
5212 case ISOM_CODEC_TYPE_AVC2_VIDEO
:
5213 case ISOM_CODEC_TYPE_AVCP_VIDEO
:
5215 isom_visual_entry_t
*stsd_data
= (isom_visual_entry_t
*)sample_entry
;
5218 //isom_btrt_t *btrt = (isom_btrt_t *)stsd_data->btrt;
5219 isom_btrt_t
*btrt
= stsd_data
->btrt
;
5222 btrt
->bufferSizeDB
= info
.bufferSizeDB
;
5223 btrt
->maxBitrate
= info
.maxBitrate
;
5224 btrt
->avgBitrate
= info
.avgBitrate
;
5228 case ISOM_CODEC_TYPE_MP4A_AUDIO
:
5230 isom_esds_t
*esds
= NULL
;
5231 if( ((isom_audio_entry_t
*)sample_entry
)->version
)
5233 /* MPEG-4 Audio in QTFF */
5234 isom_audio_entry_t
*stsd_data
= (isom_audio_entry_t
*)sample_entry
;
5235 if( !stsd_data
|| !stsd_data
->wave
|| !stsd_data
->wave
->esds
|| !stsd_data
->wave
->esds
->ES
)
5237 esds
= stsd_data
->wave
->esds
;
5241 isom_audio_entry_t
*stsd_data
= (isom_audio_entry_t
*)sample_entry
;
5242 if( !stsd_data
|| !stsd_data
->esds
|| !stsd_data
->esds
->ES
)
5244 esds
= stsd_data
->esds
;
5246 /* FIXME: avgBitrate is 0 only if VBR in proper. */
5247 if( mp4sys_update_DecoderConfigDescriptor( esds
->ES
, info
.bufferSizeDB
, info
.maxBitrate
, 0 ) )
5251 case ISOM_CODEC_TYPE_ALAC_AUDIO
:
5253 isom_audio_entry_t
*alac
= (isom_audio_entry_t
*)sample_entry
;
5256 if( alac
->exdata_length
< 36 || !alac
->exdata
)
5258 isom_wave_t
*wave
= alac
->wave
;
5259 if( !wave
|| wave
->exdata_length
< 36 || !wave
->exdata
)
5261 break; /* Apparently, average bitrate field is 0. */
5263 uint8_t *exdata
= (uint8_t *)alac
->exdata
+ 28;
5264 exdata
[0] = (info
.avgBitrate
>> 24) & 0xff;
5265 exdata
[1] = (info
.avgBitrate
>> 16) & 0xff;
5266 exdata
[2] = (info
.avgBitrate
>> 8) & 0xff;
5267 exdata
[3] = info
.avgBitrate
& 0xff;
5276 static int isom_check_mandatory_boxes( lsmash_root_t
*root
)
5280 if( !root
->moov
|| !root
->moov
->mvhd
)
5282 if( !root
->moov
->trak_list
)
5284 /* A movie requires at least one track. */
5285 if( !root
->moov
->trak_list
->head
)
5287 for( lsmash_entry_t
*entry
= root
->moov
->trak_list
->head
; entry
; entry
= entry
->next
)
5289 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)entry
->data
;
5293 || !trak
->mdia
->mdhd
5294 || !trak
->mdia
->hdlr
5295 || !trak
->mdia
->minf
5296 || !trak
->mdia
->minf
->dinf
5297 || !trak
->mdia
->minf
->dinf
->dref
5298 || !trak
->mdia
->minf
->stbl
5299 || !trak
->mdia
->minf
->stbl
->stsd
5300 || !trak
->mdia
->minf
->stbl
->stsz
5301 || !trak
->mdia
->minf
->stbl
->stts
5302 || !trak
->mdia
->minf
->stbl
->stsc
5303 || !trak
->mdia
->minf
->stbl
->stco
)
5305 if( root
->qt_compatible
&& !trak
->mdia
->minf
->hdlr
)
5307 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
5308 if( !stbl
->stsd
->list
|| !stbl
->stsd
->list
->head
)
5311 && (!stbl
->stsd
->list
|| !stbl
->stsd
->list
->head
5312 || !stbl
->stts
->list
|| !stbl
->stts
->list
->head
5313 || !stbl
->stsc
->list
|| !stbl
->stsc
->list
->head
5314 || !stbl
->stco
->list
|| !stbl
->stco
->list
->head
) )
5317 if( !root
->fragment
)
5319 if( !root
->moov
->mvex
|| !root
->moov
->mvex
->trex_list
)
5321 for( lsmash_entry_t
*entry
= root
->moov
->mvex
->trex_list
->head
; entry
; entry
= entry
->next
)
5322 if( !entry
->data
) /* trex */
5327 static inline uint64_t isom_get_current_mp4time( void )
5329 return (uint64_t)time( NULL
) + ISOM_MAC_EPOCH_OFFSET
;
5332 static int isom_set_media_creation_time( isom_trak_entry_t
*trak
, uint64_t current_mp4time
)
5334 if( !trak
->mdia
|| !trak
->mdia
->mdhd
)
5336 isom_mdhd_t
*mdhd
= trak
->mdia
->mdhd
;
5337 if( !mdhd
->creation_time
)
5338 mdhd
->creation_time
= mdhd
->modification_time
= current_mp4time
;
5342 static int isom_set_track_creation_time( isom_trak_entry_t
*trak
, uint64_t current_mp4time
)
5344 if( !trak
|| !trak
->tkhd
)
5346 isom_tkhd_t
*tkhd
= trak
->tkhd
;
5347 if( !tkhd
->creation_time
)
5348 tkhd
->creation_time
= tkhd
->modification_time
= current_mp4time
;
5349 if( isom_set_media_creation_time( trak
, current_mp4time
) )
5354 static int isom_set_movie_creation_time( lsmash_root_t
*root
)
5356 if( !root
|| !root
->moov
|| !root
->moov
->mvhd
|| !root
->moov
->trak_list
)
5358 uint64_t current_mp4time
= isom_get_current_mp4time();
5359 for( uint32_t i
= 1; i
<= root
->moov
->trak_list
->entry_count
; i
++ )
5360 if( isom_set_track_creation_time( isom_get_trak( root
, i
), current_mp4time
) )
5362 isom_mvhd_t
*mvhd
= root
->moov
->mvhd
;
5363 if( !mvhd
->creation_time
)
5364 mvhd
->creation_time
= mvhd
->modification_time
= current_mp4time
;
5368 #define CHECK_LARGESIZE( size ) if( (size) > UINT32_MAX ) (size) += 8
5370 static uint64_t isom_update_mvhd_size( isom_mvhd_t
*mvhd
)
5375 if( mvhd
->creation_time
> UINT32_MAX
|| mvhd
->modification_time
> UINT32_MAX
|| mvhd
->duration
> UINT32_MAX
)
5377 mvhd
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ 96 + (uint64_t)mvhd
->version
* 12;
5378 CHECK_LARGESIZE( mvhd
->size
);
5382 static uint64_t isom_update_iods_size( isom_iods_t
*iods
)
5384 if( !iods
|| !iods
->OD
)
5386 iods
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ mp4sys_update_ObjectDescriptor_size( iods
->OD
);
5387 CHECK_LARGESIZE( iods
->size
);
5391 static uint64_t isom_update_tkhd_size( isom_tkhd_t
*tkhd
)
5396 if( tkhd
->creation_time
> UINT32_MAX
|| tkhd
->modification_time
> UINT32_MAX
|| tkhd
->duration
> UINT32_MAX
)
5398 tkhd
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ 80 + (uint64_t)tkhd
->version
* 12;
5399 CHECK_LARGESIZE( tkhd
->size
);
5403 static uint64_t isom_update_clef_size( isom_clef_t
*clef
)
5407 clef
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ 8;
5408 CHECK_LARGESIZE( clef
->size
);
5412 static uint64_t isom_update_prof_size( isom_prof_t
*prof
)
5416 prof
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ 8;
5417 CHECK_LARGESIZE( prof
->size
);
5421 static uint64_t isom_update_enof_size( isom_enof_t
*enof
)
5425 enof
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ 8;
5426 CHECK_LARGESIZE( enof
->size
);
5430 static uint64_t isom_update_tapt_size( isom_tapt_t
*tapt
)
5434 tapt
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
5435 + isom_update_clef_size( tapt
->clef
)
5436 + isom_update_prof_size( tapt
->prof
)
5437 + isom_update_enof_size( tapt
->enof
);
5438 CHECK_LARGESIZE( tapt
->size
);
5442 static uint64_t isom_update_elst_size( isom_elst_t
*elst
)
5444 if( !elst
|| !elst
->list
)
5448 for( lsmash_entry_t
*entry
= elst
->list
->head
; entry
; entry
= entry
->next
, i
++ )
5450 isom_elst_entry_t
*data
= (isom_elst_entry_t
*)entry
->data
;
5451 if( data
->segment_duration
> UINT32_MAX
|| data
->media_time
> INT32_MAX
|| data
->media_time
< INT32_MIN
)
5454 elst
->size
= ISOM_DEFAULT_LIST_FULLBOX_HEADER_SIZE
+ (uint64_t)i
* ( elst
->version
? 20 : 12 );
5455 CHECK_LARGESIZE( elst
->size
);
5459 static uint64_t isom_update_edts_size( isom_edts_t
*edts
)
5463 edts
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
+ isom_update_elst_size( edts
->elst
);
5464 CHECK_LARGESIZE( edts
->size
);
5468 static uint64_t isom_update_tref_size( isom_tref_t
*tref
)
5472 tref
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
;
5473 if( tref
->ref_list
)
5474 for( lsmash_entry_t
*entry
= tref
->ref_list
->head
; entry
; entry
= entry
->next
)
5476 isom_tref_type_t
*ref
= (isom_tref_type_t
*)entry
->data
;
5477 ref
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
+ (uint64_t)ref
->ref_count
* 4;
5478 CHECK_LARGESIZE( ref
->size
);
5479 tref
->size
+= ref
->size
;
5481 CHECK_LARGESIZE( tref
->size
);
5485 static uint64_t isom_update_mdhd_size( isom_mdhd_t
*mdhd
)
5490 if( mdhd
->creation_time
> UINT32_MAX
|| mdhd
->modification_time
> UINT32_MAX
|| mdhd
->duration
> UINT32_MAX
)
5492 mdhd
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ 20 + (uint64_t)mdhd
->version
* 12;
5493 CHECK_LARGESIZE( mdhd
->size
);
5497 static uint64_t isom_update_hdlr_size( isom_hdlr_t
*hdlr
)
5501 hdlr
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ 20 + (uint64_t)hdlr
->componentName_length
;
5502 CHECK_LARGESIZE( hdlr
->size
);
5506 static uint64_t isom_update_dref_entry_size( isom_dref_entry_t
*urln
)
5510 urln
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ (uint64_t)urln
->name_length
+ urln
->location_length
;
5511 CHECK_LARGESIZE( urln
->size
);
5515 static uint64_t isom_update_dref_size( isom_dref_t
*dref
)
5517 if( !dref
|| !dref
->list
)
5519 dref
->size
= ISOM_DEFAULT_LIST_FULLBOX_HEADER_SIZE
;
5521 for( lsmash_entry_t
*entry
= dref
->list
->head
; entry
; entry
= entry
->next
)
5523 isom_dref_entry_t
*data
= (isom_dref_entry_t
*)entry
->data
;
5524 dref
->size
+= isom_update_dref_entry_size( data
);
5526 CHECK_LARGESIZE( dref
->size
);
5530 static uint64_t isom_update_dinf_size( isom_dinf_t
*dinf
)
5534 dinf
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
+ isom_update_dref_size( dinf
->dref
);
5535 CHECK_LARGESIZE( dinf
->size
);
5539 static uint64_t isom_update_vmhd_size( isom_vmhd_t
*vmhd
)
5543 vmhd
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ 8;
5544 CHECK_LARGESIZE( vmhd
->size
);
5548 static uint64_t isom_update_smhd_size( isom_smhd_t
*smhd
)
5552 smhd
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ 4;
5553 CHECK_LARGESIZE( smhd
->size
);
5557 static uint64_t isom_update_hmhd_size( isom_hmhd_t
*hmhd
)
5561 hmhd
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ 16;
5562 CHECK_LARGESIZE( hmhd
->size
);
5566 static uint64_t isom_update_nmhd_size( isom_nmhd_t
*nmhd
)
5570 nmhd
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
;
5571 CHECK_LARGESIZE( nmhd
->size
);
5575 static uint64_t isom_update_gmin_size( isom_gmin_t
*gmin
)
5579 gmin
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ 12;
5580 CHECK_LARGESIZE( gmin
->size
);
5584 static uint64_t isom_update_text_size( isom_text_t
*text
)
5588 text
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
+ 36;
5589 CHECK_LARGESIZE( text
->size
);
5593 static uint64_t isom_update_gmhd_size( isom_gmhd_t
*gmhd
)
5597 gmhd
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
5598 + isom_update_gmin_size( gmhd
->gmin
)
5599 + isom_update_text_size( gmhd
->text
);
5600 CHECK_LARGESIZE( gmhd
->size
);
5604 static uint64_t isom_update_pasp_size( isom_pasp_t
*pasp
)
5608 pasp
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
+ 8;
5609 CHECK_LARGESIZE( pasp
->size
);
5613 static uint64_t isom_update_clap_size( isom_clap_t
*clap
)
5617 clap
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
+ 32;
5618 CHECK_LARGESIZE( clap
->size
);
5622 static uint64_t isom_update_colr_size( isom_colr_t
*colr
)
5624 if( !colr
|| colr
->color_parameter_type
== QT_COLOR_PARAMETER_TYPE_PROF
)
5626 colr
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
+ 10;
5627 CHECK_LARGESIZE( colr
->size
);
5631 static uint64_t isom_update_stsl_size( isom_stsl_t
*stsl
)
5635 stsl
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ 6;
5636 CHECK_LARGESIZE( stsl
->size
);
5640 static uint64_t isom_update_esds_size( isom_esds_t
*esds
)
5644 esds
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ mp4sys_update_ES_Descriptor_size( esds
->ES
);
5645 CHECK_LARGESIZE( esds
->size
);
5649 static uint64_t isom_update_avcC_size( isom_avcC_t
*avcC
)
5651 if( !avcC
|| !avcC
->sequenceParameterSets
|| !avcC
->pictureParameterSets
)
5653 uint64_t size
= ISOM_DEFAULT_BOX_HEADER_SIZE
+ 7;
5654 for( lsmash_entry_t
*entry
= avcC
->sequenceParameterSets
->head
; entry
; entry
= entry
->next
)
5656 isom_avcC_ps_entry_t
*data
= (isom_avcC_ps_entry_t
*)entry
->data
;
5657 size
+= 2 + data
->parameterSetLength
;
5659 for( lsmash_entry_t
*entry
= avcC
->pictureParameterSets
->head
; entry
; entry
= entry
->next
)
5661 isom_avcC_ps_entry_t
*data
= (isom_avcC_ps_entry_t
*)entry
->data
;
5662 size
+= 2 + data
->parameterSetLength
;
5664 if( ISOM_REQUIRES_AVCC_EXTENSION( avcC
->AVCProfileIndication
) )
5667 for( lsmash_entry_t
*entry
= avcC
->sequenceParameterSetExt
->head
; entry
; entry
= entry
->next
)
5669 isom_avcC_ps_entry_t
*data
= (isom_avcC_ps_entry_t
*)entry
->data
;
5670 size
+= 2 + data
->parameterSetLength
;
5674 CHECK_LARGESIZE( avcC
->size
);
5678 static uint64_t isom_update_btrt_size( isom_btrt_t
*btrt
)
5682 btrt
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
+ 12;
5683 CHECK_LARGESIZE( btrt
->size
);
5687 static uint64_t isom_update_visual_entry_size( isom_visual_entry_t
*visual
)
5691 visual
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
+ 78
5692 + isom_update_clap_size( visual
->clap
)
5693 + isom_update_pasp_size( visual
->pasp
)
5694 + isom_update_colr_size( visual
->colr
)
5695 + isom_update_stsl_size( visual
->stsl
)
5696 + isom_update_esds_size( visual
->esds
)
5697 + isom_update_avcC_size( visual
->avcC
)
5698 + isom_update_btrt_size( visual
->btrt
);
5699 CHECK_LARGESIZE( visual
->size
);
5700 return visual
->size
;
5704 static uint64_t isom_update_mp4s_entry_size( isom_mp4s_entry_t
*mp4s
)
5706 if( !mp4s
|| mp4s
->type
!= ISOM_CODEC_TYPE_MP4S_SYSTEM
)
5708 mp4s
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
+ 8 + isom_update_esds_size( mp4s
->esds
);
5709 CHECK_LARGESIZE( mp4s
->size
);
5714 static uint64_t isom_update_frma_size( isom_frma_t
*frma
)
5718 frma
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
+ 4;
5719 CHECK_LARGESIZE( frma
->size
);
5723 static uint64_t isom_update_enda_size( isom_enda_t
*enda
)
5727 enda
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
+ 2;
5728 CHECK_LARGESIZE( enda
->size
);
5732 static uint64_t isom_update_mp4a_size( isom_mp4a_t
*mp4a
)
5736 mp4a
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
+ 4;
5737 CHECK_LARGESIZE( mp4a
->size
);
5741 static uint64_t isom_update_terminator_size( isom_terminator_t
*terminator
)
5745 terminator
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
;
5746 CHECK_LARGESIZE( terminator
->size
);
5747 return terminator
->size
;
5750 static uint64_t isom_update_wave_size( isom_wave_t
*wave
)
5754 wave
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
5755 + isom_update_frma_size( wave
->frma
)
5756 + isom_update_enda_size( wave
->enda
)
5757 + isom_update_mp4a_size( wave
->mp4a
)
5758 + isom_update_esds_size( wave
->esds
)
5759 + isom_update_terminator_size( wave
->terminator
)
5760 + (uint64_t)wave
->exdata_length
;
5761 CHECK_LARGESIZE( wave
->size
);
5765 static uint64_t isom_update_chan_size( isom_chan_t
*chan
)
5769 chan
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ 12 + 20 * (uint64_t)chan
->numberChannelDescriptions
;
5770 CHECK_LARGESIZE( chan
->size
);
5774 static uint64_t isom_update_audio_entry_size( isom_audio_entry_t
*audio
)
5778 audio
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
+ 28
5779 + isom_update_esds_size( audio
->esds
)
5780 + isom_update_wave_size( audio
->wave
)
5781 + isom_update_chan_size( audio
->chan
)
5782 + (uint64_t)audio
->exdata_length
;
5783 if( audio
->version
== 1 )
5785 else if( audio
->version
== 2 )
5787 CHECK_LARGESIZE( audio
->size
);
5791 static uint64_t isom_update_text_entry_size( isom_text_entry_t
*text
)
5795 text
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
+ 51 + (uint64_t)text
->font_name_length
;
5796 CHECK_LARGESIZE( text
->size
);
5800 static uint64_t isom_update_ftab_size( isom_ftab_t
*ftab
)
5802 if( !ftab
|| !ftab
->list
)
5804 ftab
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
+ 2;
5805 for( lsmash_entry_t
*entry
= ftab
->list
->head
; entry
; entry
= entry
->next
)
5807 isom_font_record_t
*data
= (isom_font_record_t
*)entry
->data
;
5808 ftab
->size
+= 3 + data
->font_name_length
;
5810 CHECK_LARGESIZE( ftab
->size
);
5814 static uint64_t isom_update_tx3g_entry_size( isom_tx3g_entry_t
*tx3g
)
5818 tx3g
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
+ 38 + isom_update_ftab_size( tx3g
->ftab
);
5819 CHECK_LARGESIZE( tx3g
->size
);
5823 static uint64_t isom_update_stsd_size( isom_stsd_t
*stsd
)
5825 if( !stsd
|| !stsd
->list
)
5827 uint64_t size
= ISOM_DEFAULT_LIST_FULLBOX_HEADER_SIZE
;
5828 for( lsmash_entry_t
*entry
= stsd
->list
->head
; entry
; entry
= entry
->next
)
5830 isom_sample_entry_t
*data
= (isom_sample_entry_t
*)entry
->data
;
5831 switch( data
->type
)
5833 case ISOM_CODEC_TYPE_AVC1_VIDEO
:
5835 case ISOM_CODEC_TYPE_AVC2_VIDEO
:
5836 case ISOM_CODEC_TYPE_AVCP_VIDEO
:
5837 case ISOM_CODEC_TYPE_SVC1_VIDEO
:
5838 case ISOM_CODEC_TYPE_MVC1_VIDEO
:
5839 case ISOM_CODEC_TYPE_MVC2_VIDEO
:
5840 case ISOM_CODEC_TYPE_MP4V_VIDEO
:
5841 case ISOM_CODEC_TYPE_DRAC_VIDEO
:
5842 case ISOM_CODEC_TYPE_ENCV_VIDEO
:
5843 case ISOM_CODEC_TYPE_MJP2_VIDEO
:
5844 case ISOM_CODEC_TYPE_S263_VIDEO
:
5845 case ISOM_CODEC_TYPE_VC_1_VIDEO
:
5847 size
+= isom_update_visual_entry_size( (isom_visual_entry_t
*)data
);
5850 case ISOM_CODEC_TYPE_MP4S_SYSTEM
:
5851 size
+= isom_update_mp4s_entry_size( (isom_mp4s_entry_t
*)data
);
5854 case ISOM_CODEC_TYPE_MP4A_AUDIO
:
5855 case ISOM_CODEC_TYPE_AC_3_AUDIO
:
5856 case ISOM_CODEC_TYPE_ALAC_AUDIO
:
5857 case ISOM_CODEC_TYPE_SAMR_AUDIO
:
5858 case ISOM_CODEC_TYPE_SAWB_AUDIO
:
5859 case QT_CODEC_TYPE_23NI_AUDIO
:
5860 case QT_CODEC_TYPE_NONE_AUDIO
:
5861 case QT_CODEC_TYPE_LPCM_AUDIO
:
5862 case QT_CODEC_TYPE_RAW_AUDIO
:
5863 case QT_CODEC_TYPE_SOWT_AUDIO
:
5864 case QT_CODEC_TYPE_TWOS_AUDIO
:
5865 case QT_CODEC_TYPE_FL32_AUDIO
:
5866 case QT_CODEC_TYPE_FL64_AUDIO
:
5867 case QT_CODEC_TYPE_IN24_AUDIO
:
5868 case QT_CODEC_TYPE_IN32_AUDIO
:
5869 case QT_CODEC_TYPE_NOT_SPECIFIED
:
5870 #ifdef LSMASH_DEMUXER_ENABLED
5871 case ISOM_CODEC_TYPE_EC_3_AUDIO
:
5874 case ISOM_CODEC_TYPE_DRA1_AUDIO
:
5875 case ISOM_CODEC_TYPE_DTSC_AUDIO
:
5876 case ISOM_CODEC_TYPE_DTSH_AUDIO
:
5877 case ISOM_CODEC_TYPE_DTSL_AUDIO
:
5878 case ISOM_CODEC_TYPE_ENCA_AUDIO
:
5879 case ISOM_CODEC_TYPE_G719_AUDIO
:
5880 case ISOM_CODEC_TYPE_G726_AUDIO
:
5881 case ISOM_CODEC_TYPE_M4AE_AUDIO
:
5882 case ISOM_CODEC_TYPE_MLPA_AUDIO
:
5883 case ISOM_CODEC_TYPE_RAW_AUDIO
:
5884 case ISOM_CODEC_TYPE_SAWP_AUDIO
:
5885 case ISOM_CODEC_TYPE_SEVC_AUDIO
:
5886 case ISOM_CODEC_TYPE_SQCP_AUDIO
:
5887 case ISOM_CODEC_TYPE_SSMV_AUDIO
:
5888 case ISOM_CODEC_TYPE_TWOS_AUDIO
:
5890 size
+= isom_update_audio_entry_size( (isom_audio_entry_t
*)data
);
5892 case ISOM_CODEC_TYPE_TX3G_TEXT
:
5893 size
+= isom_update_tx3g_entry_size( (isom_tx3g_entry_t
*)data
);
5895 case QT_CODEC_TYPE_TEXT_TEXT
:
5896 size
+= isom_update_text_entry_size( (isom_text_entry_t
*)data
);
5903 CHECK_LARGESIZE( stsd
->size
);
5907 static uint64_t isom_update_stts_size( isom_stts_t
*stts
)
5909 if( !stts
|| !stts
->list
)
5911 stts
->size
= ISOM_DEFAULT_LIST_FULLBOX_HEADER_SIZE
+ (uint64_t)stts
->list
->entry_count
* 8;
5912 CHECK_LARGESIZE( stts
->size
);
5916 static uint64_t isom_update_ctts_size( isom_ctts_t
*ctts
)
5918 if( !ctts
|| !ctts
->list
)
5920 ctts
->size
= ISOM_DEFAULT_LIST_FULLBOX_HEADER_SIZE
+ (uint64_t)ctts
->list
->entry_count
* 8;
5921 CHECK_LARGESIZE( ctts
->size
);
5925 static uint64_t isom_update_cslg_size( isom_cslg_t
*cslg
)
5929 cslg
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ 20;
5930 CHECK_LARGESIZE( cslg
->size
);
5934 static uint64_t isom_update_stsz_size( isom_stsz_t
*stsz
)
5938 stsz
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ 8 + ( stsz
->list
? (uint64_t)stsz
->list
->entry_count
* 4 : 0 );
5939 CHECK_LARGESIZE( stsz
->size
);
5943 static uint64_t isom_update_stss_size( isom_stss_t
*stss
)
5945 if( !stss
|| !stss
->list
)
5947 stss
->size
= ISOM_DEFAULT_LIST_FULLBOX_HEADER_SIZE
+ (uint64_t)stss
->list
->entry_count
* 4;
5948 CHECK_LARGESIZE( stss
->size
);
5952 static uint64_t isom_update_stps_size( isom_stps_t
*stps
)
5954 if( !stps
|| !stps
->list
)
5956 stps
->size
= ISOM_DEFAULT_LIST_FULLBOX_HEADER_SIZE
+ (uint64_t)stps
->list
->entry_count
* 4;
5957 CHECK_LARGESIZE( stps
->size
);
5961 static uint64_t isom_update_sdtp_size( isom_sdtp_t
*sdtp
)
5963 if( !sdtp
|| !sdtp
->list
)
5965 sdtp
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ (uint64_t)sdtp
->list
->entry_count
;
5966 CHECK_LARGESIZE( sdtp
->size
);
5970 static uint64_t isom_update_stsc_size( isom_stsc_t
*stsc
)
5972 if( !stsc
|| !stsc
->list
)
5974 stsc
->size
= ISOM_DEFAULT_LIST_FULLBOX_HEADER_SIZE
+ (uint64_t)stsc
->list
->entry_count
* 12;
5975 CHECK_LARGESIZE( stsc
->size
);
5979 static uint64_t isom_update_stco_size( isom_stco_t
*stco
)
5981 if( !stco
|| !stco
->list
)
5983 stco
->size
= ISOM_DEFAULT_LIST_FULLBOX_HEADER_SIZE
+ (uint64_t)stco
->list
->entry_count
* (stco
->large_presentation
? 8 : 4);
5984 CHECK_LARGESIZE( stco
->size
);
5988 static uint64_t isom_update_sbgp_size( isom_sbgp_entry_t
*sbgp
)
5990 if( !sbgp
|| !sbgp
->list
)
5992 sbgp
->size
= ISOM_DEFAULT_LIST_FULLBOX_HEADER_SIZE
+ 4 + (uint64_t)sbgp
->list
->entry_count
* 8;
5993 CHECK_LARGESIZE( sbgp
->size
);
5997 static uint64_t isom_update_sgpd_size( isom_sgpd_entry_t
*sgpd
)
5999 if( !sgpd
|| !sgpd
->list
)
6001 uint64_t size
= ISOM_DEFAULT_LIST_FULLBOX_HEADER_SIZE
+ (1 + (sgpd
->version
== 1)) * 4;
6002 size
+= (uint64_t)sgpd
->list
->entry_count
* ((sgpd
->version
== 1) && !sgpd
->default_length
) * 4;
6003 switch( sgpd
->grouping_type
)
6005 case ISOM_GROUP_TYPE_RAP
:
6006 size
+= sgpd
->list
->entry_count
;
6008 case ISOM_GROUP_TYPE_ROLL
:
6009 size
+= (uint64_t)sgpd
->list
->entry_count
* 2;
6012 /* We don't consider other grouping types currently. */
6016 CHECK_LARGESIZE( sgpd
->size
);
6020 static uint64_t isom_update_stbl_size( isom_stbl_t
*stbl
)
6024 stbl
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
6025 + isom_update_stsd_size( stbl
->stsd
)
6026 + isom_update_stts_size( stbl
->stts
)
6027 + isom_update_ctts_size( stbl
->ctts
)
6028 + isom_update_cslg_size( stbl
->cslg
)
6029 + isom_update_stsz_size( stbl
->stsz
)
6030 + isom_update_stss_size( stbl
->stss
)
6031 + isom_update_stps_size( stbl
->stps
)
6032 + isom_update_sdtp_size( stbl
->sdtp
)
6033 + isom_update_stsc_size( stbl
->stsc
)
6034 + isom_update_stco_size( stbl
->stco
);
6035 if( stbl
->sgpd_list
)
6036 for( lsmash_entry_t
*entry
= stbl
->sgpd_list
->head
; entry
; entry
= entry
->next
)
6037 stbl
->size
+= isom_update_sgpd_size( (isom_sgpd_entry_t
*)entry
->data
);
6038 if( stbl
->sbgp_list
)
6039 for( lsmash_entry_t
*entry
= stbl
->sbgp_list
->head
; entry
; entry
= entry
->next
)
6040 stbl
->size
+= isom_update_sbgp_size( (isom_sbgp_entry_t
*)entry
->data
);
6041 CHECK_LARGESIZE( stbl
->size
);
6045 static uint64_t isom_update_minf_size( isom_minf_t
*minf
)
6049 minf
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
6050 + isom_update_vmhd_size( minf
->vmhd
)
6051 + isom_update_smhd_size( minf
->smhd
)
6052 + isom_update_hmhd_size( minf
->hmhd
)
6053 + isom_update_nmhd_size( minf
->nmhd
)
6054 + isom_update_gmhd_size( minf
->gmhd
)
6055 + isom_update_hdlr_size( minf
->hdlr
)
6056 + isom_update_dinf_size( minf
->dinf
)
6057 + isom_update_stbl_size( minf
->stbl
);
6058 CHECK_LARGESIZE( minf
->size
);
6062 static uint64_t isom_update_mdia_size( isom_mdia_t
*mdia
)
6066 mdia
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
6067 + isom_update_mdhd_size( mdia
->mdhd
)
6068 + isom_update_hdlr_size( mdia
->hdlr
)
6069 + isom_update_minf_size( mdia
->minf
);
6070 CHECK_LARGESIZE( mdia
->size
);
6074 static uint64_t isom_update_chpl_size( isom_chpl_t
*chpl
)
6078 chpl
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ 4 * (chpl
->version
== 1) + 1;
6079 for( lsmash_entry_t
*entry
= chpl
->list
->head
; entry
; entry
= entry
->next
)
6081 isom_chpl_entry_t
*data
= (isom_chpl_entry_t
*)entry
->data
;
6082 chpl
->size
+= 9 + data
->chapter_name_length
;
6084 CHECK_LARGESIZE( chpl
->size
);
6088 static uint64_t isom_update_udta_size( isom_udta_t
*udta_moov
, isom_udta_t
*udta_trak
)
6090 isom_udta_t
*udta
= udta_trak
? udta_trak
: udta_moov
? udta_moov
: NULL
;
6093 udta
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
+ ( udta_moov
? isom_update_chpl_size( udta
->chpl
) : 0 );
6094 CHECK_LARGESIZE( udta
->size
);
6098 static uint64_t isom_update_trak_entry_size( isom_trak_entry_t
*trak
)
6102 trak
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
6103 + isom_update_tkhd_size( trak
->tkhd
)
6104 + isom_update_tapt_size( trak
->tapt
)
6105 + isom_update_edts_size( trak
->edts
)
6106 + isom_update_tref_size( trak
->tref
)
6107 + isom_update_mdia_size( trak
->mdia
)
6108 + isom_update_udta_size( NULL
, trak
->udta
);
6109 CHECK_LARGESIZE( trak
->size
);
6113 static uint64_t isom_update_mehd_size( isom_mehd_t
*mehd
)
6117 if( mehd
->fragment_duration
> UINT32_MAX
)
6119 mehd
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ 4 * (1 + (mehd
->version
== 1));
6120 CHECK_LARGESIZE( mehd
->size
);
6124 static uint64_t isom_update_trex_entry_size( isom_trex_entry_t
*trex
)
6128 trex
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ 20;
6129 CHECK_LARGESIZE( trex
->size
);
6133 static uint64_t isom_update_mvex_size( isom_mvex_t
*mvex
)
6137 mvex
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
;
6138 if( mvex
->trex_list
)
6139 for( lsmash_entry_t
*entry
= mvex
->trex_list
->head
; entry
; entry
= entry
->next
)
6141 isom_trex_entry_t
*trex
= (isom_trex_entry_t
*)entry
->data
;
6142 mvex
->size
+= isom_update_trex_entry_size( trex
);
6144 if( mvex
->root
->bs
->stream
!= stdout
)
6145 mvex
->size
+= mvex
->mehd
? isom_update_mehd_size( mvex
->mehd
) : 20; /* 20 bytes is of placeholder. */
6146 CHECK_LARGESIZE( mvex
->size
);
6150 static int isom_update_moov_size( isom_moov_t
*moov
)
6154 moov
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
6155 + isom_update_mvhd_size( moov
->mvhd
)
6156 + isom_update_iods_size( moov
->iods
)
6157 + isom_update_udta_size( moov
->udta
, NULL
)
6158 + isom_update_mvex_size( moov
->mvex
);
6159 if( moov
->trak_list
)
6160 for( lsmash_entry_t
*entry
= moov
->trak_list
->head
; entry
; entry
= entry
->next
)
6162 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)entry
->data
;
6163 moov
->size
+= isom_update_trak_entry_size( trak
);
6165 CHECK_LARGESIZE( moov
->size
);
6169 static uint64_t isom_update_mfhd_size( isom_mfhd_t
*mfhd
)
6173 mfhd
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ 4;
6174 CHECK_LARGESIZE( mfhd
->size
);
6178 static uint64_t isom_update_tfhd_size( isom_tfhd_t
*tfhd
)
6182 tfhd
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
6184 + 8 * !!( tfhd
->flags
& ISOM_TF_FLAGS_BASE_DATA_OFFSET_PRESENT
)
6185 + 4 * !!( tfhd
->flags
& ISOM_TF_FLAGS_SAMPLE_DESCRIPTION_INDEX_PRESENT
)
6186 + 4 * !!( tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT
)
6187 + 4 * !!( tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_SAMPLE_SIZE_PRESENT
)
6188 + 4 * !!( tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_SAMPLE_FLAGS_PRESENT
);
6189 CHECK_LARGESIZE( tfhd
->size
);
6193 static uint64_t isom_update_trun_entry_size( isom_trun_entry_t
*trun
)
6197 trun
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
6199 + 4 * !!( trun
->flags
& ISOM_TR_FLAGS_DATA_OFFSET_PRESENT
)
6200 + 4 * !!( trun
->flags
& ISOM_TR_FLAGS_FIRST_SAMPLE_FLAGS_PRESENT
);
6201 uint64_t row_size
= 4 * !!( trun
->flags
& ISOM_TR_FLAGS_SAMPLE_DURATION_PRESENT
)
6202 + 4 * !!( trun
->flags
& ISOM_TR_FLAGS_SAMPLE_SIZE_PRESENT
)
6203 + 4 * !!( trun
->flags
& ISOM_TR_FLAGS_SAMPLE_FLAGS_PRESENT
)
6204 + 4 * !!( trun
->flags
& ISOM_TR_FLAGS_SAMPLE_COMPOSITION_TIME_OFFSET_PRESENT
);
6205 trun
->size
+= row_size
* trun
->sample_count
;
6206 CHECK_LARGESIZE( trun
->size
);
6210 static uint64_t isom_update_traf_entry_size( isom_traf_entry_t
*traf
)
6214 traf
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
+ isom_update_tfhd_size( traf
->tfhd
);
6215 if( traf
->trun_list
)
6216 for( lsmash_entry_t
*entry
= traf
->trun_list
->head
; entry
; entry
= entry
->next
)
6218 isom_trun_entry_t
*trun
= (isom_trun_entry_t
*)entry
->data
;
6219 traf
->size
+= isom_update_trun_entry_size( trun
);
6221 CHECK_LARGESIZE( traf
->size
);
6225 static int isom_update_moof_entry_size( isom_moof_entry_t
*moof
)
6229 moof
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
+ isom_update_mfhd_size( moof
->mfhd
);
6230 if( moof
->traf_list
)
6231 for( lsmash_entry_t
*entry
= moof
->traf_list
->head
; entry
; entry
= entry
->next
)
6233 isom_traf_entry_t
*traf
= (isom_traf_entry_t
*)entry
->data
;
6234 moof
->size
+= isom_update_traf_entry_size( traf
);
6236 CHECK_LARGESIZE( moof
->size
);
6240 static uint64_t isom_update_tfra_entry_size( isom_tfra_entry_t
*tfra
)
6244 tfra
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ 12;
6245 uint32_t entry_size
= 8 * (1 + (tfra
->version
== 1))
6246 + tfra
->length_size_of_traf_num
+ 1
6247 + tfra
->length_size_of_trun_num
+ 1
6248 + tfra
->length_size_of_sample_num
+ 1;
6249 tfra
->size
+= entry_size
* tfra
->number_of_entry
;
6250 CHECK_LARGESIZE( tfra
->size
);
6254 static uint64_t isom_update_mfro_size( isom_mfro_t
*mfro
)
6258 mfro
->size
= ISOM_DEFAULT_FULLBOX_HEADER_SIZE
+ 4;
6259 CHECK_LARGESIZE( mfro
->size
);
6263 static int isom_update_mfra_size( isom_mfra_t
*mfra
)
6267 mfra
->size
= ISOM_DEFAULT_BOX_HEADER_SIZE
;
6268 if( mfra
->tfra_list
)
6269 for( lsmash_entry_t
*entry
= mfra
->tfra_list
->head
; entry
; entry
= entry
->next
)
6271 isom_tfra_entry_t
*tfra
= (isom_tfra_entry_t
*)entry
->data
;
6272 mfra
->size
+= isom_update_tfra_entry_size( tfra
);
6274 CHECK_LARGESIZE( mfra
->size
);
6277 mfra
->size
+= isom_update_mfro_size( mfra
->mfro
);
6278 mfra
->mfro
->length
= mfra
->size
;
6283 /*******************************
6285 *******************************/
6287 /*---- track manipulators ----*/
6289 void lsmash_delete_track( lsmash_root_t
*root
, uint32_t track_ID
)
6291 if( !root
|| !root
->moov
|| !root
->moov
->trak_list
)
6293 for( lsmash_entry_t
*entry
= root
->moov
->trak_list
->head
; entry
; entry
= entry
->next
)
6295 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)entry
->data
;
6296 if( !trak
|| !trak
->tkhd
)
6298 if( trak
->tkhd
->track_ID
== track_ID
)
6300 lsmash_entry_t
*next
= entry
->next
;
6301 lsmash_entry_t
*prev
= entry
->prev
;
6302 isom_remove_trak( trak
);
6316 uint32_t lsmash_create_track( lsmash_root_t
*root
, uint32_t media_type
)
6318 isom_trak_entry_t
*trak
= isom_add_trak( root
);
6321 if( isom_add_tkhd( trak
, media_type
)
6322 || isom_add_mdia( trak
)
6323 || isom_add_mdhd( trak
->mdia
, root
->qt_compatible
? 0 : ISOM_LANGUAGE_CODE_UNDEFINED
)
6324 || isom_add_minf( trak
->mdia
)
6325 || isom_add_stbl( trak
->mdia
->minf
)
6326 || isom_add_dinf( trak
->mdia
->minf
)
6327 || isom_add_dref( trak
->mdia
->minf
->dinf
)
6328 || isom_add_stsd( trak
->mdia
->minf
->stbl
)
6329 || isom_add_stts( trak
->mdia
->minf
->stbl
)
6330 || isom_add_stsc( trak
->mdia
->minf
->stbl
)
6331 || isom_add_stco( trak
->mdia
->minf
->stbl
)
6332 || isom_add_stsz( trak
->mdia
->minf
->stbl
) )
6334 if( isom_add_hdlr( trak
->mdia
, NULL
, media_type
) )
6336 if( root
->qt_compatible
&& isom_add_hdlr( NULL
, trak
->mdia
->minf
, QT_REFERENCE_HANDLER_TYPE_URL
) )
6338 switch( media_type
)
6340 case ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK
:
6341 if( isom_add_vmhd( trak
->mdia
->minf
) )
6344 case ISOM_MEDIA_HANDLER_TYPE_AUDIO_TRACK
:
6345 if( isom_add_smhd( trak
->mdia
->minf
) )
6348 case ISOM_MEDIA_HANDLER_TYPE_HINT_TRACK
:
6349 if( isom_add_hmhd( trak
->mdia
->minf
) )
6352 case ISOM_MEDIA_HANDLER_TYPE_TEXT_TRACK
:
6353 if( root
->qt_compatible
|| root
->itunes_audio
)
6355 if( isom_add_gmhd( trak
->mdia
->minf
)
6356 || isom_add_gmin( trak
->mdia
->minf
->gmhd
)
6357 || isom_add_text( trak
->mdia
->minf
->gmhd
) )
6361 return 0; /* We support only reference text media track for chapter yet. */
6364 if( isom_add_nmhd( trak
->mdia
->minf
) )
6368 return trak
->tkhd
->track_ID
;
6371 uint32_t lsmash_get_track_ID( lsmash_root_t
*root
, uint32_t track_number
)
6373 if( !root
|| !root
->moov
)
6375 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)lsmash_get_entry_data( root
->moov
->trak_list
, track_number
);
6376 if( !trak
|| !trak
->tkhd
)
6378 return trak
->tkhd
->track_ID
;
6381 void lsmash_initialize_track_parameters( lsmash_track_parameters_t
*param
)
6383 memset( param
, 0, sizeof(lsmash_track_parameters_t
) );
6384 param
->audio_volume
= 0x0100;
6385 param
->matrix
[0] = 0x00010000;
6386 param
->matrix
[4] = 0x00010000;
6387 param
->matrix
[8] = 0x40000000;
6390 int lsmash_set_track_parameters( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_track_parameters_t
*param
)
6392 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6393 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->hdlr
|| !root
->moov
->mvhd
)
6395 /* Prepare Track Aperture Modes if required. */
6396 if( root
->qt_compatible
&& param
->aperture_modes
)
6398 if( !trak
->tapt
&& isom_add_tapt( trak
) )
6400 isom_tapt_t
*tapt
= trak
->tapt
;
6401 if( (!tapt
->clef
&& isom_add_clef( tapt
))
6402 || (!tapt
->prof
&& isom_add_prof( tapt
))
6403 || (!tapt
->enof
&& isom_add_enof( tapt
)) )
6407 isom_remove_tapt( trak
->tapt
);
6408 /* Set up Track Header. */
6409 uint32_t media_type
= trak
->mdia
->hdlr
->componentSubtype
;
6410 isom_tkhd_t
*tkhd
= trak
->tkhd
;
6411 tkhd
->flags
= param
->mode
;
6412 tkhd
->track_ID
= param
->track_ID
? param
->track_ID
: tkhd
->track_ID
;
6413 tkhd
->duration
= !trak
->edts
|| !trak
->edts
->elst
? param
->duration
: tkhd
->duration
;
6414 tkhd
->alternate_group
= root
->qt_compatible
|| root
->itunes_audio
|| root
->max_3gpp_version
>= 4 ? param
->alternate_group
: 0;
6415 if( root
->qt_compatible
|| root
->itunes_audio
)
6417 tkhd
->layer
= media_type
== ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK
? param
->video_layer
: 0;
6418 tkhd
->volume
= media_type
== ISOM_MEDIA_HANDLER_TYPE_AUDIO_TRACK
? param
->audio_volume
: 0;
6423 tkhd
->volume
= media_type
== ISOM_MEDIA_HANDLER_TYPE_AUDIO_TRACK
? 0x0100 : 0;
6425 for( int i
= 0; i
< 9; i
++ )
6426 tkhd
->matrix
[i
] = media_type
== ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK
? param
->matrix
[i
] : 0;
6427 tkhd
->width
= media_type
== ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK
? param
->display_width
: 0;
6428 tkhd
->height
= media_type
== ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK
? param
->display_height
: 0;
6429 /* Update next_track_ID if needed. */
6430 if( root
->moov
->mvhd
->next_track_ID
<= tkhd
->track_ID
)
6431 root
->moov
->mvhd
->next_track_ID
= tkhd
->track_ID
+ 1;
6435 int lsmash_get_track_parameters( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_track_parameters_t
*param
)
6437 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6440 isom_tkhd_t
*tkhd
= trak
->tkhd
;
6441 param
->mode
= tkhd
->flags
;
6442 param
->track_ID
= tkhd
->track_ID
;
6443 param
->duration
= tkhd
->duration
;
6444 param
->video_layer
= tkhd
->layer
;
6445 param
->alternate_group
= tkhd
->alternate_group
;
6446 param
->audio_volume
= tkhd
->volume
;
6447 for( int i
= 0; i
< 9; i
++ )
6448 param
->matrix
[i
] = tkhd
->matrix
[i
];
6449 param
->display_width
= tkhd
->width
;
6450 param
->display_height
= tkhd
->height
;
6451 param
->aperture_modes
= !!trak
->tapt
;
6455 static int isom_set_media_handler_name( lsmash_root_t
*root
, uint32_t track_ID
, char *handler_name
)
6457 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6458 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->hdlr
)
6460 isom_hdlr_t
*hdlr
= trak
->mdia
->hdlr
;
6461 uint8_t *name
= NULL
;
6462 uint32_t name_length
= strlen( handler_name
) + root
->isom_compatible
+ root
->qt_compatible
;
6463 if( root
->qt_compatible
)
6464 name_length
= LSMASH_MIN( name_length
, 255 );
6465 if( name_length
> hdlr
->componentName_length
&& hdlr
->componentName
)
6466 name
= realloc( hdlr
->componentName
, name_length
);
6467 else if( !hdlr
->componentName
)
6468 name
= malloc( name_length
);
6470 name
= hdlr
->componentName
;
6473 if( root
->qt_compatible
)
6474 name
[0] = name_length
& 0xff;
6475 memcpy( name
+ root
->qt_compatible
, handler_name
, strlen( handler_name
) );
6476 if( root
->isom_compatible
)
6477 name
[name_length
- 1] = 0;
6478 hdlr
->componentName
= name
;
6479 hdlr
->componentName_length
= name_length
;
6483 static int isom_set_data_handler_name( lsmash_root_t
*root
, uint32_t track_ID
, char *handler_name
)
6485 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6486 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->hdlr
)
6488 isom_hdlr_t
*hdlr
= trak
->mdia
->minf
->hdlr
;
6489 uint8_t *name
= NULL
;
6490 uint32_t name_length
= strlen( handler_name
) + root
->isom_compatible
+ root
->qt_compatible
;
6491 if( root
->qt_compatible
)
6492 name_length
= LSMASH_MIN( name_length
, 255 );
6493 if( name_length
> hdlr
->componentName_length
&& hdlr
->componentName
)
6494 name
= realloc( hdlr
->componentName
, name_length
);
6495 else if( !hdlr
->componentName
)
6496 name
= malloc( name_length
);
6498 name
= hdlr
->componentName
;
6501 if( root
->qt_compatible
)
6502 name
[0] = name_length
& 0xff;
6503 memcpy( name
+ root
->qt_compatible
, handler_name
, strlen( handler_name
) );
6504 if( root
->isom_compatible
)
6505 name
[name_length
- 1] = 0;
6506 hdlr
->componentName
= name
;
6507 hdlr
->componentName_length
= name_length
;
6511 uint32_t lsmash_get_media_timescale( lsmash_root_t
*root
, uint32_t track_ID
)
6513 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6514 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->mdhd
)
6516 return trak
->mdia
->mdhd
->timescale
;
6519 uint64_t lsmash_get_media_duration( lsmash_root_t
*root
, uint32_t track_ID
)
6521 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6522 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->mdhd
)
6524 return trak
->mdia
->mdhd
->duration
;
6527 uint64_t lsmash_get_track_duration( lsmash_root_t
*root
, uint32_t track_ID
)
6529 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6530 if( !trak
|| !trak
->tkhd
)
6532 return trak
->tkhd
->duration
;
6535 uint32_t lsmash_get_last_sample_delta( lsmash_root_t
*root
, uint32_t track_ID
)
6537 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6538 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
6539 || !trak
->mdia
->minf
->stbl
->stts
|| !trak
->mdia
->minf
->stbl
->stts
->list
6540 || !trak
->mdia
->minf
->stbl
->stts
->list
->head
|| !trak
->mdia
->minf
->stbl
->stts
->list
->head
->data
)
6542 return ((isom_stts_entry_t
*)trak
->mdia
->minf
->stbl
->stts
->list
->head
->data
)->sample_delta
;
6545 uint32_t lsmash_get_start_time_offset( lsmash_root_t
*root
, uint32_t track_ID
)
6547 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6548 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
6549 || !trak
->mdia
->minf
->stbl
->ctts
|| !trak
->mdia
->minf
->stbl
->ctts
->list
6550 || !trak
->mdia
->minf
->stbl
->ctts
->list
->head
|| !trak
->mdia
->minf
->stbl
->ctts
->list
->head
->data
)
6552 return ((isom_ctts_entry_t
*)trak
->mdia
->minf
->stbl
->ctts
->list
->head
->data
)->sample_offset
;
6555 char *isom_unpack_iso_language( uint16_t language
)
6557 static char unpacked
[4];
6558 unpacked
[0] = ((language
>> 10) & 0x1f) + 0x60;
6559 unpacked
[1] = ((language
>> 5) & 0x1f) + 0x60;
6560 unpacked
[2] = ( language
& 0x1f) + 0x60;
6565 static int isom_iso2mac_language( uint16_t ISO_language
, uint16_t *MAC_language
)
6570 for( ; isom_languages
[i
].iso_name
; i
++ )
6571 if( ISO_language
== isom_languages
[i
].iso_name
)
6573 if( !isom_languages
[i
].iso_name
)
6575 *MAC_language
= isom_languages
[i
].mac_value
;
6579 static int isom_mac2iso_language( uint16_t MAC_language
, uint16_t *ISO_language
)
6584 for( ; isom_languages
[i
].iso_name
; i
++ )
6585 if( MAC_language
== isom_languages
[i
].mac_value
)
6587 *ISO_language
= isom_languages
[i
].iso_name
? isom_languages
[i
].iso_name
: ISOM_LANGUAGE_CODE_UNDEFINED
;
6591 static int isom_set_media_language( lsmash_root_t
*root
, uint32_t track_ID
, char *ISO_language
, uint16_t MAC_language
)
6593 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6594 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->mdhd
)
6596 uint16_t language
= 0;
6597 if( root
->isom_compatible
)
6599 if( ISO_language
&& (strlen( ISO_language
) == 3) )
6600 language
= ISOM_LANG( ISO_language
);
6601 else if( MAC_language
)
6603 if( isom_mac2iso_language( MAC_language
, &language
) )
6607 language
= ISOM_LANGUAGE_CODE_UNDEFINED
;
6609 else if( root
->qt_compatible
)
6611 if( ISO_language
&& (strlen( ISO_language
) == 3) )
6613 if( isom_iso2mac_language( ISOM_LANG( ISO_language
), &language
) )
6617 language
= MAC_language
;
6621 trak
->mdia
->mdhd
->language
= language
;
6625 static int isom_create_grouping( isom_trak_entry_t
*trak
, lsmash_grouping_type_code grouping_type
)
6627 lsmash_root_t
*root
= trak
->root
;
6628 switch( grouping_type
)
6630 case ISOM_GROUP_TYPE_RAP
:
6631 assert( root
->max_isom_version
>= 6 );
6633 case ISOM_GROUP_TYPE_ROLL
:
6634 assert( root
->avc_extensions
);
6640 if( !isom_add_sgpd( trak
->mdia
->minf
->stbl
, grouping_type
)
6641 || !isom_add_sbgp( trak
->mdia
->minf
->stbl
, grouping_type
) )
6646 void lsmash_initialize_media_parameters( lsmash_media_parameters_t
*param
)
6648 memset( param
, 0, sizeof(lsmash_media_parameters_t
) );
6649 param
->timescale
= 1;
6652 int lsmash_set_media_parameters( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_media_parameters_t
*param
)
6654 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6655 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->mdhd
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
)
6657 trak
->mdia
->mdhd
->timescale
= param
->timescale
;
6658 if( isom_set_media_language( root
, track_ID
, param
->ISO_language
, param
->MAC_language
) )
6660 if( param
->media_handler_name
6661 && isom_set_media_handler_name( root
, track_ID
, param
->media_handler_name
) )
6663 if( root
->qt_compatible
&& param
->data_handler_name
6664 && isom_set_data_handler_name( root
, track_ID
, param
->data_handler_name
) )
6666 if( root
->avc_extensions
&& param
->roll_grouping
6667 && isom_create_grouping( trak
, ISOM_GROUP_TYPE_ROLL
) )
6669 if( (root
->max_isom_version
>= 6) && param
->rap_grouping
6670 && isom_create_grouping( trak
, ISOM_GROUP_TYPE_RAP
) )
6675 int lsmash_get_media_parameters( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_media_parameters_t
*param
)
6677 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6678 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->mdhd
|| !trak
->mdia
->hdlr
6679 || !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
)
6681 isom_mdhd_t
*mdhd
= trak
->mdia
->mdhd
;
6682 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
6683 isom_sbgp_entry_t
*sbgp
;
6684 isom_sgpd_entry_t
*sgpd
;
6685 param
->timescale
= mdhd
->timescale
;
6686 param
->handler_type
= trak
->mdia
->hdlr
->componentSubtype
;
6687 param
->duration
= mdhd
->duration
;
6688 /* Whether sample grouping present. */
6689 sbgp
= isom_get_sample_to_group( stbl
, ISOM_GROUP_TYPE_ROLL
);
6690 sgpd
= isom_get_sample_group_description( stbl
, ISOM_GROUP_TYPE_ROLL
);
6691 param
->roll_grouping
= sbgp
&& sgpd
;
6692 sbgp
= isom_get_sample_to_group( stbl
, ISOM_GROUP_TYPE_RAP
);
6693 sgpd
= isom_get_sample_group_description( stbl
, ISOM_GROUP_TYPE_RAP
);
6694 param
->rap_grouping
= sbgp
&& sgpd
;
6695 /* Get media language. */
6696 if( mdhd
->language
>= 0x800 )
6698 param
->MAC_language
= 0;
6699 param
->ISO_language
= isom_unpack_iso_language( mdhd
->language
);
6700 memcpy( param
->language_shadow
, param
->ISO_language
, sizeof(param
->language_shadow
) );
6701 param
->ISO_language
= param
->language_shadow
;
6705 param
->MAC_language
= mdhd
->language
;
6706 param
->ISO_language
= NULL
;
6707 memset( param
->language_shadow
, 0, sizeof(param
->language_shadow
) );
6709 /* Get handler name(s). */
6710 isom_hdlr_t
*hdlr
= trak
->mdia
->hdlr
;
6711 int length
= LSMASH_MIN( 255, hdlr
->componentName_length
);
6714 memcpy( param
->media_handler_name_shadow
, hdlr
->componentName
+ root
->qt_compatible
, length
);
6715 param
->media_handler_name_shadow
[length
- 2 + root
->isom_compatible
+ root
->qt_compatible
] = '\0';
6716 param
->media_handler_name
= param
->media_handler_name_shadow
;
6720 param
->media_handler_name
= NULL
;
6721 memset( param
->media_handler_name_shadow
, 0, sizeof(param
->media_handler_name_shadow
) );
6723 if( trak
->mdia
->minf
->hdlr
)
6725 hdlr
= trak
->mdia
->minf
->hdlr
;
6726 length
= LSMASH_MIN( 255, hdlr
->componentName_length
);
6729 memcpy( param
->data_handler_name_shadow
, hdlr
->componentName
+ root
->qt_compatible
, length
);
6730 param
->data_handler_name_shadow
[length
- 2 + root
->isom_compatible
+ root
->qt_compatible
] = '\0';
6731 param
->data_handler_name
= param
->data_handler_name_shadow
;
6735 param
->data_handler_name
= NULL
;
6736 memset( param
->data_handler_name_shadow
, 0, sizeof(param
->data_handler_name_shadow
) );
6741 param
->data_handler_name
= NULL
;
6742 memset( param
->data_handler_name_shadow
, 0, sizeof(param
->data_handler_name_shadow
) );
6747 /*---- movie manipulators ----*/
6749 lsmash_root_t
*lsmash_open_movie( const char *filename
, lsmash_file_mode_code mode
)
6751 char open_mode
[4] = { 0 };
6752 if( mode
& LSMASH_FILE_MODE_WRITE
)
6753 memcpy( open_mode
, "w+b", 4 );
6754 #ifdef LSMASH_DEMUXER_ENABLED
6755 else if( mode
& LSMASH_FILE_MODE_READ
)
6756 memcpy( open_mode
, "rb", 3 );
6760 lsmash_root_t
*root
= malloc( sizeof(lsmash_root_t
) );
6763 memset( root
, 0, sizeof(lsmash_root_t
) );
6765 root
->bs
= malloc( sizeof(lsmash_bs_t
) );
6768 memset( root
->bs
, 0, sizeof(lsmash_bs_t
) );
6769 if( !strcmp( filename
, "-" ) )
6771 if( mode
& LSMASH_FILE_MODE_READ
)
6772 root
->bs
->stream
= stdin
;
6773 else if( (mode
& LSMASH_FILE_MODE_WRITE
) && (mode
& LSMASH_FILE_MODE_FRAGMENTED
) )
6774 root
->bs
->stream
= stdout
;
6777 root
->bs
->stream
= fopen( filename
, open_mode
);
6778 if( !root
->bs
->stream
)
6781 if( mode
& LSMASH_FILE_MODE_WRITE
)
6783 if( isom_add_moov( root
) || isom_add_mvhd( root
->moov
) )
6785 root
->qt_compatible
= 1; /* QTFF is default file format. */
6787 #ifdef LSMASH_DEMUXER_ENABLED
6788 if( (mode
& (LSMASH_FILE_MODE_READ
| LSMASH_FILE_MODE_DUMP
)) )
6790 if( isom_read_root( root
) )
6792 root
->max_read_size
= 4 * 1024 * 1024;
6795 if( mode
& LSMASH_FILE_MODE_FRAGMENTED
)
6797 root
->fragment
= malloc( sizeof(isom_fragment_manager_t
) );
6798 if( !root
->fragment
)
6800 memset( root
->fragment
, 0, sizeof(isom_fragment_manager_t
) );
6801 root
->fragment
->pool
= lsmash_create_entry_list();
6802 if( !root
->fragment
->pool
)
6807 lsmash_destroy_root( root
);
6811 static int isom_finish_fragment_movie( lsmash_root_t
*root
);
6813 /* A movie fragment cannot switch a sample description to another.
6814 * So you must call this function before switching sample descriptions. */
6815 int lsmash_create_fragment_movie( lsmash_root_t
*root
)
6817 if( !root
|| !root
->bs
|| !root
->fragment
|| !root
->moov
|| !root
->moov
->trak_list
)
6819 /* Finish the previous movie fragment before starting a new one. */
6820 if( isom_finish_fragment_movie( root
) )
6822 /* We always hold only one movie fragment except for the initial movie (a pair of moov and mdat). */
6823 if( root
->fragment
->movie
&& root
->moof_list
->entry_count
!= 1 )
6825 isom_moof_entry_t
*moof
= isom_add_moof( root
);
6826 if( isom_add_mfhd( moof
) )
6828 root
->fragment
->movie
= moof
;
6829 moof
->mfhd
->sequence_number
= ++ root
->fragment
->fragment_count
;
6830 if( root
->moof_list
->entry_count
== 1 )
6832 /* Remove the previous movie fragment. */
6833 return lsmash_remove_entry( root
->moof_list
, 1, isom_remove_moof
);
6836 static int isom_set_brands( lsmash_root_t
*root
, lsmash_brand_type_code major_brand
, uint32_t minor_version
, lsmash_brand_type_code
*brands
, uint32_t brand_count
)
6838 if( brand_count
> 50 )
6839 return -1; /* We support setting brands up to 50. */
6842 /* Absence of File Type Box means this file is a QuickTime or MP4 version 1 format file. */
6845 if( root
->ftyp
->compatible_brands
)
6846 free( root
->ftyp
->compatible_brands
);
6852 if( !root
->ftyp
&& isom_add_ftyp( root
) )
6854 isom_ftyp_t
*ftyp
= root
->ftyp
;
6855 ftyp
->major_brand
= major_brand
;
6856 ftyp
->minor_version
= minor_version
;
6857 lsmash_brand_type_code
*compatible_brands
;
6858 if( !ftyp
->compatible_brands
)
6859 compatible_brands
= malloc( brand_count
* sizeof(uint32_t) );
6861 compatible_brands
= realloc( ftyp
->compatible_brands
, brand_count
* sizeof(uint32_t) );
6862 if( !compatible_brands
)
6864 ftyp
->compatible_brands
= compatible_brands
;
6865 for( uint32_t i
= 0; i
< brand_count
; i
++ )
6867 ftyp
->compatible_brands
[i
] = brands
[i
];
6870 ftyp
->brand_count
= brand_count
;
6871 return isom_check_compatibility( root
);
6874 void lsmash_initialize_movie_parameters( lsmash_movie_parameters_t
*param
)
6876 memset( param
, 0, sizeof(lsmash_movie_parameters_t
) );
6877 param
->max_chunk_duration
= 0.5;
6878 param
->max_async_tolerance
= 2.0;
6879 param
->max_chunk_size
= 4 * 1024 * 1024;
6880 param
->max_read_size
= 4 * 1024 * 1024;
6881 param
->timescale
= 600;
6882 param
->playback_rate
= 0x00010000;
6883 param
->playback_volume
= 0x0100;
6886 int lsmash_set_movie_parameters( lsmash_root_t
*root
, lsmash_movie_parameters_t
*param
)
6888 if( !root
|| !root
->moov
|| !root
->moov
->mvhd
6889 || isom_set_brands( root
, param
->major_brand
, param
->minor_version
, param
->brands
, param
->number_of_brands
) )
6891 isom_mvhd_t
*mvhd
= root
->moov
->mvhd
;
6892 root
->max_chunk_duration
= param
->max_chunk_duration
;
6893 root
->max_async_tolerance
= LSMASH_MAX( param
->max_async_tolerance
, 2 * param
->max_chunk_duration
);
6894 root
->max_chunk_size
= param
->max_chunk_size
;
6895 root
->max_read_size
= param
->max_read_size
;
6896 mvhd
->timescale
= param
->timescale
;
6897 if( root
->qt_compatible
|| root
->itunes_audio
)
6899 mvhd
->rate
= param
->playback_rate
;
6900 mvhd
->volume
= param
->playback_volume
;
6901 mvhd
->previewTime
= param
->preview_time
;
6902 mvhd
->previewDuration
= param
->preview_duration
;
6903 mvhd
->posterTime
= param
->poster_time
;
6907 mvhd
->rate
= 0x00010000;
6908 mvhd
->volume
= 0x0100;
6909 mvhd
->previewTime
= 0;
6910 mvhd
->previewDuration
= 0;
6911 mvhd
->posterTime
= 0;
6916 int lsmash_get_movie_parameters( lsmash_root_t
*root
, lsmash_movie_parameters_t
*param
)
6918 if( !root
|| !root
->moov
|| !root
->moov
->mvhd
)
6920 isom_mvhd_t
*mvhd
= root
->moov
->mvhd
;
6923 isom_ftyp_t
*ftyp
= root
->ftyp
;
6924 uint32_t brand_count
= LSMASH_MIN( ftyp
->brand_count
, 50 ); /* brands up to 50 */
6925 for( uint32_t i
= 0; i
< brand_count
; i
++ )
6926 param
->brands_shadow
[i
] = ftyp
->compatible_brands
[i
];
6927 param
->major_brand
= ftyp
->major_brand
;
6928 param
->brands
= param
->brands_shadow
;
6929 param
->number_of_brands
= brand_count
;
6930 param
->minor_version
= ftyp
->minor_version
;
6932 param
->max_chunk_duration
= root
->max_chunk_duration
;
6933 param
->max_async_tolerance
= root
->max_async_tolerance
;
6934 param
->max_chunk_size
= root
->max_chunk_size
;
6935 param
->max_read_size
= root
->max_read_size
;
6936 param
->timescale
= mvhd
->timescale
;
6937 param
->duration
= mvhd
->duration
;
6938 param
->playback_rate
= mvhd
->rate
;
6939 param
->playback_volume
= mvhd
->volume
;
6940 param
->preview_time
= mvhd
->previewTime
;
6941 param
->preview_duration
= mvhd
->previewDuration
;
6942 param
->poster_time
= mvhd
->posterTime
;
6943 param
->number_of_tracks
= root
->moov
->trak_list
? root
->moov
->trak_list
->entry_count
: 0;
6947 uint32_t lsmash_get_movie_timescale( lsmash_root_t
*root
)
6949 if( !root
|| !root
->moov
|| !root
->moov
->mvhd
)
6951 return root
->moov
->mvhd
->timescale
;
6954 static int isom_write_ftyp( lsmash_root_t
*root
)
6956 isom_ftyp_t
*ftyp
= root
->ftyp
;
6957 if( !ftyp
|| !ftyp
->brand_count
)
6959 lsmash_bs_t
*bs
= root
->bs
;
6960 isom_bs_put_box_common( bs
, ftyp
);
6961 lsmash_bs_put_be32( bs
, ftyp
->major_brand
);
6962 lsmash_bs_put_be32( bs
, ftyp
->minor_version
);
6963 for( uint32_t i
= 0; i
< ftyp
->brand_count
; i
++ )
6964 lsmash_bs_put_be32( bs
, ftyp
->compatible_brands
[i
] );
6965 if( lsmash_bs_write_data( bs
) )
6967 root
->size
+= ftyp
->size
;
6968 root
->file_type_written
= 1;
6972 static int isom_write_moov( lsmash_root_t
*root
)
6974 if( !root
|| !root
->moov
)
6976 lsmash_bs_t
*bs
= root
->bs
;
6977 isom_bs_put_box_common( bs
, root
->moov
);
6978 if( lsmash_bs_write_data( bs
) )
6980 if( isom_write_mvhd( root
)
6981 || isom_write_iods( root
) )
6983 if( root
->moov
->trak_list
)
6984 for( lsmash_entry_t
*entry
= root
->moov
->trak_list
->head
; entry
; entry
= entry
->next
)
6985 if( isom_write_trak( bs
, (isom_trak_entry_t
*)entry
->data
) )
6987 if( isom_write_udta( bs
, root
->moov
, NULL
) )
6989 return isom_write_mvex( bs
, root
->moov
->mvex
);
6992 int lsmash_set_free( lsmash_root_t
*root
, uint8_t *data
, uint64_t data_length
)
6994 if( !root
|| !root
->free
|| !data
|| !data_length
)
6996 isom_free_t
*skip
= root
->free
;
6997 uint8_t *tmp
= NULL
;
6999 tmp
= malloc( data_length
);
7000 else if( skip
->length
< data_length
)
7001 tmp
= realloc( skip
->data
, data_length
);
7004 memcpy( tmp
, data
, data_length
);
7006 skip
->length
= data_length
;
7010 int lsmash_add_free( lsmash_root_t
*root
, uint8_t *data
, uint64_t data_length
)
7016 isom_create_box( skip
, root
, ISOM_BOX_TYPE_FREE
);
7019 if( data
&& data_length
)
7020 return lsmash_set_free( root
, data
, data_length
);
7024 int lsmash_write_free( lsmash_root_t
*root
)
7026 if( !root
|| !root
->bs
|| !root
->free
)
7028 isom_free_t
*skip
= root
->free
;
7029 lsmash_bs_t
*bs
= root
->bs
;
7030 skip
->size
= 8 + skip
->length
;
7031 isom_bs_put_box_common( bs
, skip
);
7032 if( skip
->data
&& skip
->length
)
7033 lsmash_bs_put_bytes( bs
, skip
->data
, skip
->length
);
7034 return lsmash_bs_write_data( bs
);
7037 int lsmash_create_object_descriptor( lsmash_root_t
*root
)
7041 /* Return error if this file is not compatible with MP4 file format. */
7042 if( !root
->mp4_version1
&& !root
->mp4_version2
)
7044 return isom_add_iods( root
->moov
);
7047 /*---- finishing functions ----*/
7049 static int isom_set_fragment_overall_duration( lsmash_root_t
*root
)
7051 if( root
->bs
->stream
== stdout
)
7053 isom_mvex_t
*mvex
= root
->moov
->mvex
;
7054 if( isom_add_mehd( mvex
) )
7056 /* Get the longest duration of the tracks. */
7057 uint64_t longest_duration
= 0;
7058 for( lsmash_entry_t
*entry
= root
->moov
->trak_list
->head
; entry
; entry
= entry
->next
)
7060 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)entry
->data
;
7061 if( !trak
|| !trak
->cache
|| !trak
->cache
->fragment
|| !trak
->mdia
|| !trak
->mdia
->mdhd
|| !trak
->mdia
->mdhd
->timescale
)
7064 if( !trak
->edts
|| !trak
->edts
->elst
|| !trak
->edts
->elst
->list
)
7066 duration
= trak
->cache
->fragment
->largest_cts
+ trak
->cache
->fragment
->last_duration
;
7067 duration
= (uint64_t)(((double)duration
/ trak
->mdia
->mdhd
->timescale
) * root
->moov
->mvhd
->timescale
);
7072 for( lsmash_entry_t
*elst_entry
= trak
->edts
->elst
->list
->head
; elst_entry
; elst_entry
= elst_entry
->next
)
7074 isom_elst_entry_t
*data
= (isom_elst_entry_t
*)elst_entry
->data
;
7077 duration
+= data
->segment_duration
;
7080 longest_duration
= LSMASH_MAX( duration
, longest_duration
);
7082 mvex
->mehd
->fragment_duration
= longest_duration
;
7083 mvex
->mehd
->version
= 1;
7084 isom_update_mehd_size( mvex
->mehd
);
7085 /* Write Movie Extends Header Box here. */
7086 lsmash_bs_t
*bs
= root
->bs
;
7087 FILE *stream
= bs
->stream
;
7088 uint64_t current_pos
= lsmash_ftell( stream
);
7089 lsmash_fseek( stream
, mvex
->placeholder_pos
, SEEK_SET
);
7090 int ret
= isom_write_mehd( bs
, mvex
->mehd
);
7092 ret
= lsmash_bs_write_data( bs
);
7093 lsmash_fseek( stream
, current_pos
, SEEK_SET
);
7097 static int isom_write_fragment_random_access_info( lsmash_root_t
*root
)
7099 if( root
->bs
->stream
== stdout
)
7101 if( isom_update_mfra_size( root
->mfra
) )
7103 return isom_write_mfra( root
->bs
, root
->mfra
);
7106 int lsmash_finish_movie( lsmash_root_t
*root
, lsmash_adhoc_remux_t
* remux
)
7108 if( !root
|| !root
->bs
|| !root
->moov
|| !root
->moov
->trak_list
)
7110 if( root
->fragment
)
7112 /* Output the final movie fragment. */
7113 if( isom_finish_fragment_movie( root
) )
7115 /* Write the overall random access information at the tail of the movie. */
7116 if( isom_write_fragment_random_access_info( root
) )
7118 /* Set overall duration of the movie. */
7119 return isom_set_fragment_overall_duration( root
);
7121 isom_moov_t
*moov
= root
->moov
;
7122 for( lsmash_entry_t
*entry
= moov
->trak_list
->head
; entry
; entry
= entry
->next
)
7124 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)entry
->data
;
7125 if( !trak
|| !trak
->cache
|| !trak
->tkhd
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
)
7127 uint32_t track_ID
= trak
->tkhd
->track_ID
;
7128 uint32_t related_track_ID
= trak
->related_track_ID
;
7129 /* Disable the track if the track is a track reference chapter. */
7130 if( trak
->is_chapter
)
7131 trak
->tkhd
->flags
&= ~ISOM_TRACK_ENABLED
;
7132 if( trak
->is_chapter
&& related_track_ID
)
7134 /* In order that the track duration of the chapter track doesn't exceed that of the related track. */
7135 uint64_t track_duration
= LSMASH_MIN( trak
->tkhd
->duration
, lsmash_get_track_duration( root
, related_track_ID
) );
7136 if( lsmash_create_explicit_timeline_map( root
, track_ID
, track_duration
, 0, ISOM_EDIT_MODE_NORMAL
) )
7139 /* Add stss box if any samples aren't sync sample. */
7140 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
7141 if( !trak
->cache
->all_sync
&& !stbl
->stss
&& isom_add_stss( stbl
) )
7143 if( isom_update_bitrate_info( trak
->mdia
) )
7146 if( root
->mp4_version1
== 1 && isom_add_iods( moov
) )
7148 if( isom_check_mandatory_boxes( root
)
7149 || isom_set_movie_creation_time( root
)
7150 || isom_update_moov_size( moov
)
7151 || isom_write_mdat_size( root
) )
7156 if( isom_write_moov( root
) )
7158 root
->size
+= moov
->size
;
7162 /* stco->co64 conversion, depending on last chunk's offset */
7163 for( lsmash_entry_t
* entry
= moov
->trak_list
->head
; entry
; )
7165 isom_trak_entry_t
* trak
= (isom_trak_entry_t
*)entry
->data
;
7166 isom_stco_t
* stco
= trak
->mdia
->minf
->stbl
->stco
;
7167 if( !stco
->list
->tail
)
7169 if( stco
->large_presentation
7170 || ((isom_stco_entry_t
*)stco
->list
->tail
->data
)->chunk_offset
+ moov
->size
<= UINT32_MAX
)
7172 entry
= entry
->next
;
7173 continue; /* no need to convert stco into co64 */
7175 /* stco->co64 conversion */
7176 if( isom_convert_stco_to_co64( trak
->mdia
->minf
->stbl
)
7177 || isom_update_moov_size( moov
) )
7179 entry
= moov
->trak_list
->head
; /* whenever any conversion, re-check all traks */
7182 /* now the amount of offset is fixed. */
7184 /* buffer size must be at least sizeof(moov)*2 */
7185 remux
->buffer_size
= LSMASH_MAX( remux
->buffer_size
, moov
->size
* 2 );
7188 if( (buf
[0] = (uint8_t*)malloc( remux
->buffer_size
)) == NULL
)
7189 return -1; /* NOTE: i think we still can fallback to "return isom_write_moov( root );" here. */
7190 uint64_t size
= remux
->buffer_size
/ 2;
7191 buf
[1] = buf
[0] + size
; /* split to 2 buffers */
7193 /* now the amount of offset is fixed. apply that to stco/co64 */
7194 for( lsmash_entry_t
* entry
= moov
->trak_list
->head
; entry
; entry
= entry
->next
)
7196 isom_stco_t
* stco
= ((isom_trak_entry_t
*)entry
->data
)->mdia
->minf
->stbl
->stco
;
7197 if( stco
->large_presentation
)
7198 for( lsmash_entry_t
* co64_entry
= stco
->list
->head
; co64_entry
; co64_entry
= co64_entry
->next
)
7199 ((isom_co64_entry_t
*)co64_entry
->data
)->chunk_offset
+= moov
->size
;
7201 for( lsmash_entry_t
* stco_entry
= stco
->list
->head
; stco_entry
; stco_entry
= stco_entry
->next
)
7202 ((isom_stco_entry_t
*)stco_entry
->data
)->chunk_offset
+= moov
->size
;
7205 FILE *stream
= root
->bs
->stream
;
7206 isom_mdat_t
*mdat
= root
->mdat
;
7207 uint64_t total
= lsmash_ftell( stream
) + moov
->size
; // FIXME:
7209 /* backup starting area of mdat and write moov there instead */
7210 if( lsmash_fseek( stream
, mdat
->placeholder_pos
, SEEK_SET
) )
7212 readnum
= fread( buf
[0], 1, size
, stream
);
7213 uint64_t read_pos
= lsmash_ftell( stream
);
7215 /* write moov there instead */
7216 if( lsmash_fseek( stream
, mdat
->placeholder_pos
, SEEK_SET
)
7217 || isom_write_moov( root
) )
7219 uint64_t write_pos
= lsmash_ftell( stream
);
7221 mdat
->placeholder_pos
+= moov
->size
; /* update placeholder */
7225 while( readnum
== size
)
7227 if( lsmash_fseek( stream
, read_pos
, SEEK_SET
) )
7229 readnum
= fread( buf
[buf_switch
], 1, size
, stream
);
7230 read_pos
= lsmash_ftell( stream
);
7234 if( lsmash_fseek( stream
, write_pos
, SEEK_SET
)
7235 || fwrite( buf
[buf_switch
], 1, size
, stream
) != size
)
7237 write_pos
= lsmash_ftell( stream
);
7238 if( remux
->func
) remux
->func( remux
->param
, write_pos
, total
); // FIXME:
7240 if( fwrite( buf
[buf_switch
^0x1], 1, readnum
, stream
) != readnum
)
7242 if( remux
->func
) remux
->func( remux
->param
, total
, total
); // FIXME:
7244 root
->size
+= moov
->size
;
7253 #define GET_MOST_USED( box_name, index, flag_name ) \
7254 if( most_used[index] < stats.flag_name[i] ) \
7256 most_used[index] = stats.flag_name[i]; \
7257 box_name->default_sample_flags.flag_name = i; \
7260 static int isom_create_fragment_overall_default_settings( lsmash_root_t
*root
)
7262 if( isom_add_mvex( root
->moov
) )
7264 for( lsmash_entry_t
*trak_entry
= root
->moov
->trak_list
->head
; trak_entry
; trak_entry
= trak_entry
->next
)
7266 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)trak_entry
->data
;
7267 if( !trak
|| !trak
->cache
|| !trak
->tkhd
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
)
7269 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
7270 if( !stbl
->stts
|| !stbl
->stts
->list
|| !stbl
->stsz
7271 || (stbl
->stts
->list
->tail
&& !stbl
->stts
->list
->tail
->data
)
7272 || (stbl
->stsz
->list
&& stbl
->stsz
->list
->head
&& !stbl
->stsz
->list
->head
->data
) )
7274 isom_trex_entry_t
*trex
= isom_add_trex( root
->moov
->mvex
);
7277 trex
->track_ID
= trak
->tkhd
->track_ID
;
7278 /* Set up defaults. */
7279 trex
->default_sample_description_index
= trak
->cache
->chunk
.sample_description_index
? trak
->cache
->chunk
.sample_description_index
: 1;
7280 trex
->default_sample_duration
= stbl
->stts
->list
->tail
? ((isom_stts_entry_t
*)stbl
->stts
->list
->tail
->data
)->sample_delta
: 1;
7281 trex
->default_sample_size
= !stbl
->stsz
->list
7282 ? stbl
->stsz
->sample_size
: stbl
->stsz
->list
->head
7283 ? ((isom_stsz_entry_t
*)stbl
->stsz
->list
->head
->data
)->entry_size
: 0;
7284 if( stbl
->sdtp
&& stbl
->sdtp
->list
)
7286 struct sample_flags_stats_t
7288 uint32_t is_leading
[4];
7289 uint32_t sample_depends_on
[4];
7290 uint32_t sample_is_depended_on
[4];
7291 uint32_t sample_has_redundancy
[4];
7292 } stats
= { { 0 }, { 0 }, { 0 }, { 0 } };
7293 for( lsmash_entry_t
*sdtp_entry
= stbl
->sdtp
->list
->head
; sdtp_entry
; sdtp_entry
= sdtp_entry
->next
)
7295 isom_sdtp_entry_t
*data
= (isom_sdtp_entry_t
*)sdtp_entry
->data
;
7298 ++ stats
.is_leading
[ data
->is_leading
];
7299 ++ stats
.sample_depends_on
[ data
->sample_depends_on
];
7300 ++ stats
.sample_is_depended_on
[ data
->sample_is_depended_on
];
7301 ++ stats
.sample_has_redundancy
[ data
->sample_has_redundancy
];
7303 uint32_t most_used
[4] = { 0, 0, 0, 0 };
7304 for( int i
= 0; i
< 4; i
++ )
7306 GET_MOST_USED( trex
, 0, is_leading
);
7307 GET_MOST_USED( trex
, 1, sample_depends_on
);
7308 GET_MOST_USED( trex
, 2, sample_is_depended_on
);
7309 GET_MOST_USED( trex
, 3, sample_has_redundancy
);
7312 trex
->default_sample_flags
.sample_is_non_sync_sample
= !trak
->cache
->all_sync
;
7317 static int isom_prepare_random_access_info( lsmash_root_t
*root
)
7319 if( root
->bs
->stream
== stdout
)
7321 if( isom_add_mfra( root
)
7322 || isom_add_mfro( root
->mfra
) )
7327 static int isom_output_fragment_media_data( lsmash_root_t
*root
)
7329 isom_fragment_manager_t
*fragment
= root
->fragment
;
7330 if( !fragment
->pool
->entry_count
)
7332 /* no need to write media data */
7333 lsmash_remove_entries( fragment
->pool
, lsmash_delete_sample
);
7334 fragment
->pool_size
= 0;
7337 /* If there is no available Media Data Box to write samples, add and write a new one. */
7338 if( isom_new_mdat( root
, fragment
->pool_size
) )
7340 /* Write samples in the current movie fragment. */
7341 for( lsmash_entry_t
* entry
= fragment
->pool
->head
; entry
; entry
= entry
->next
)
7343 lsmash_sample_t
*sample
= (lsmash_sample_t
*)entry
->data
;
7344 if( !sample
|| !sample
->data
)
7346 lsmash_bs_put_bytes( root
->bs
, sample
->data
, sample
->length
);
7348 if( lsmash_bs_write_data( root
->bs
) )
7350 root
->size
+= root
->mdat
->size
;
7351 lsmash_remove_entries( fragment
->pool
, lsmash_delete_sample
);
7352 fragment
->pool_size
= 0;
7356 static int isom_finish_fragment_initial_movie( lsmash_root_t
*root
)
7358 if( !root
->moov
|| !root
->moov
->trak_list
)
7360 isom_moov_t
*moov
= root
->moov
;
7361 for( lsmash_entry_t
*entry
= moov
->trak_list
->head
; entry
; entry
= entry
->next
)
7363 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)entry
->data
;
7364 if( !trak
|| !trak
->cache
|| !trak
->tkhd
|| !trak
->mdia
|| !trak
->mdia
->mdhd
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
)
7366 if( isom_get_sample_count( trak
) )
7368 /* Add stss box if any samples aren't sync sample. */
7369 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
7370 if( !trak
->cache
->all_sync
&& !stbl
->stss
&& isom_add_stss( stbl
) )
7374 trak
->tkhd
->duration
= 0;
7375 if( isom_update_bitrate_info( trak
->mdia
) )
7378 if( root
->mp4_version1
== 1 && isom_add_iods( moov
) )
7380 if( isom_create_fragment_overall_default_settings( root
)
7381 || isom_prepare_random_access_info( root
)
7382 || isom_check_mandatory_boxes( root
)
7383 || isom_set_movie_creation_time( root
)
7384 || isom_update_moov_size( moov
) )
7386 /* stco->co64 conversion, depending on last chunk's offset */
7387 for( lsmash_entry_t
* entry
= moov
->trak_list
->head
; entry
; )
7389 isom_trak_entry_t
* trak
= (isom_trak_entry_t
*)entry
->data
;
7390 isom_stco_t
* stco
= trak
->mdia
->minf
->stbl
->stco
;
7391 if( !stco
->list
->tail
/* no samples */
7392 || stco
->large_presentation
7393 || ((isom_stco_entry_t
*)stco
->list
->tail
->data
)->chunk_offset
+ moov
->size
<= UINT32_MAX
)
7395 entry
= entry
->next
;
7396 continue; /* no need to convert stco into co64 */
7398 /* stco->co64 conversion */
7399 if( isom_convert_stco_to_co64( trak
->mdia
->minf
->stbl
)
7400 || isom_update_moov_size( moov
) )
7402 entry
= moov
->trak_list
->head
; /* whenever any conversion, re-check all traks */
7404 /* Now, the amount of offset is fixed. Apply that to stco/co64. */
7405 for( lsmash_entry_t
* entry
= moov
->trak_list
->head
; entry
; entry
= entry
->next
)
7407 isom_stco_t
* stco
= ((isom_trak_entry_t
*)entry
->data
)->mdia
->minf
->stbl
->stco
;
7408 if( stco
->large_presentation
)
7409 for( lsmash_entry_t
* co64_entry
= stco
->list
->head
; co64_entry
; co64_entry
= co64_entry
->next
)
7410 ((isom_co64_entry_t
*)co64_entry
->data
)->chunk_offset
+= moov
->size
;
7412 for( lsmash_entry_t
* stco_entry
= stco
->list
->head
; stco_entry
; stco_entry
= stco_entry
->next
)
7413 ((isom_stco_entry_t
*)stco_entry
->data
)->chunk_offset
+= moov
->size
;
7415 /* Write File Type Box here if it was not written yet. */
7416 if( !root
->file_type_written
&& isom_write_ftyp( root
) )
7418 /* Write Movie Box. */
7419 if( isom_write_moov( root
) )
7421 root
->size
+= moov
->size
;
7422 /* Output samples. */
7423 return isom_output_fragment_media_data( root
);
7426 static int isom_finish_fragment_movie( lsmash_root_t
*root
)
7428 if( !root
->moov
|| !root
->moov
->trak_list
|| !root
->fragment
|| !root
->fragment
->pool
)
7430 isom_moof_entry_t
*moof
= root
->fragment
->movie
;
7432 return isom_finish_fragment_initial_movie( root
);
7433 /* Calculate appropriate default_sample_flags of each Track Fragment Header Box.
7434 * And check whether that default_sample_flags is useful or not. */
7435 for( lsmash_entry_t
*entry
= moof
->traf_list
->head
; entry
; entry
= entry
->next
)
7437 isom_traf_entry_t
*traf
= (isom_traf_entry_t
*)entry
->data
;
7438 if( !traf
|| !traf
->tfhd
|| !traf
->root
|| !traf
->root
->moov
|| !traf
->root
->moov
->mvex
)
7440 isom_tfhd_t
*tfhd
= traf
->tfhd
;
7441 isom_trex_entry_t
*trex
= isom_get_trex( root
->moov
->mvex
, tfhd
->track_ID
);
7444 struct sample_flags_stats_t
7446 uint32_t is_leading
[4];
7447 uint32_t sample_depends_on
[4];
7448 uint32_t sample_is_depended_on
[4];
7449 uint32_t sample_has_redundancy
[4];
7450 uint32_t sample_is_non_sync_sample
[2];
7451 } stats
= { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } };
7452 for( lsmash_entry_t
*trun_entry
= traf
->trun_list
->head
; trun_entry
; trun_entry
= trun_entry
->next
)
7454 isom_trun_entry_t
*trun
= (isom_trun_entry_t
*)trun_entry
->data
;
7455 if( !trun
|| !trun
->sample_count
)
7457 isom_sample_flags_t
*sample_flags
;
7458 if( trun
->flags
& ISOM_TR_FLAGS_SAMPLE_FLAGS_PRESENT
)
7460 if( !trun
->optional
)
7462 for( lsmash_entry_t
*optional_entry
= trun
->optional
->head
; optional_entry
; optional_entry
= optional_entry
->next
)
7464 isom_trun_optional_row_t
*row
= (isom_trun_optional_row_t
*)optional_entry
->data
;
7467 sample_flags
= &row
->sample_flags
;
7468 ++ stats
.is_leading
[ sample_flags
->is_leading
];
7469 ++ stats
.sample_depends_on
[ sample_flags
->sample_depends_on
];
7470 ++ stats
.sample_is_depended_on
[ sample_flags
->sample_is_depended_on
];
7471 ++ stats
.sample_has_redundancy
[ sample_flags
->sample_has_redundancy
];
7472 ++ stats
.sample_is_non_sync_sample
[ sample_flags
->sample_is_non_sync_sample
];
7477 sample_flags
= &tfhd
->default_sample_flags
;
7478 stats
.is_leading
[ sample_flags
->is_leading
] += trun
->sample_count
;
7479 stats
.sample_depends_on
[ sample_flags
->sample_depends_on
] += trun
->sample_count
;
7480 stats
.sample_is_depended_on
[ sample_flags
->sample_is_depended_on
] += trun
->sample_count
;
7481 stats
.sample_has_redundancy
[ sample_flags
->sample_has_redundancy
] += trun
->sample_count
;
7482 stats
.sample_is_non_sync_sample
[ sample_flags
->sample_is_non_sync_sample
] += trun
->sample_count
;
7485 uint32_t most_used
[5] = { 0, 0, 0, 0, 0 };
7486 for( int i
= 0; i
< 4; i
++ )
7488 GET_MOST_USED( tfhd
, 0, is_leading
);
7489 GET_MOST_USED( tfhd
, 1, sample_depends_on
);
7490 GET_MOST_USED( tfhd
, 2, sample_is_depended_on
);
7491 GET_MOST_USED( tfhd
, 3, sample_has_redundancy
);
7493 GET_MOST_USED( tfhd
, 4, sample_is_non_sync_sample
);
7495 int useful_default_sample_duration
= 0;
7496 int useful_default_sample_size
= 0;
7497 for( lsmash_entry_t
*trun_entry
= traf
->trun_list
->head
; trun_entry
; trun_entry
= trun_entry
->next
)
7499 isom_trun_entry_t
*trun
= (isom_trun_entry_t
*)trun_entry
->data
;
7500 if( !(trun
->flags
& ISOM_TR_FLAGS_SAMPLE_DURATION_PRESENT
) )
7501 useful_default_sample_duration
= 1;
7502 if( !(trun
->flags
& ISOM_TR_FLAGS_SAMPLE_SIZE_PRESENT
) )
7503 useful_default_sample_size
= 1;
7504 int useful_first_sample_flags
= 1;
7505 int useful_default_sample_flags
= 1;
7506 if( trun
->sample_count
== 1 )
7508 /* It is enough to check only if first_sample_flags equals default_sample_flags or not.
7509 * If it is equal, just use default_sample_flags.
7510 * If not, just use first_sample_flags of this run. */
7511 if( !memcmp( &trun
->first_sample_flags
, &tfhd
->default_sample_flags
, sizeof(isom_sample_flags_t
) ) )
7512 useful_first_sample_flags
= 0;
7514 else if( trun
->optional
&& trun
->optional
->head
)
7516 lsmash_entry_t
*optional_entry
= trun
->optional
->head
->next
;
7517 isom_trun_optional_row_t
*row
= (isom_trun_optional_row_t
*)optional_entry
->data
;
7518 isom_sample_flags_t representative_sample_flags
= row
->sample_flags
;
7519 if( memcmp( &tfhd
->default_sample_flags
, &representative_sample_flags
, sizeof(isom_sample_flags_t
) ) )
7520 useful_default_sample_flags
= 0;
7521 if( !memcmp( &trun
->first_sample_flags
, &representative_sample_flags
, sizeof(isom_sample_flags_t
) ) )
7522 useful_first_sample_flags
= 0;
7523 if( useful_default_sample_flags
)
7524 for( optional_entry
= optional_entry
->next
; optional_entry
; optional_entry
= optional_entry
->next
)
7526 row
= (isom_trun_optional_row_t
*)optional_entry
->data
;
7527 if( memcmp( &representative_sample_flags
, &row
->sample_flags
, sizeof(isom_sample_flags_t
) ) )
7529 useful_default_sample_flags
= 0;
7534 if( useful_default_sample_flags
)
7536 tfhd
->flags
|= ISOM_TF_FLAGS_DEFAULT_SAMPLE_FLAGS_PRESENT
;
7537 trun
->flags
&= ~ISOM_TR_FLAGS_SAMPLE_FLAGS_PRESENT
;
7541 useful_first_sample_flags
= 0;
7542 trun
->flags
|= ISOM_TR_FLAGS_SAMPLE_FLAGS_PRESENT
;
7544 if( useful_first_sample_flags
)
7545 trun
->flags
|= ISOM_TR_FLAGS_FIRST_SAMPLE_FLAGS_PRESENT
;
7547 if( useful_default_sample_duration
&& tfhd
->default_sample_duration
!= trex
->default_sample_duration
)
7548 tfhd
->flags
|= ISOM_TF_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT
;
7550 tfhd
->default_sample_duration
= trex
->default_sample_duration
; /* This might be redundant, but is to be more natural. */
7551 if( useful_default_sample_size
&& tfhd
->default_sample_size
!= trex
->default_sample_size
)
7552 tfhd
->flags
|= ISOM_TF_FLAGS_DEFAULT_SAMPLE_SIZE_PRESENT
;
7554 tfhd
->default_sample_size
= trex
->default_sample_size
; /* This might be redundant, but is to be more natural. */
7555 if( !(tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_SAMPLE_FLAGS_PRESENT
) )
7556 tfhd
->default_sample_flags
= trex
->default_sample_flags
; /* This might be redundant, but is to be more natural. */
7557 else if( !memcmp( &tfhd
->default_sample_flags
, &trex
->default_sample_flags
, sizeof(isom_sample_flags_t
) ) )
7558 tfhd
->flags
&= ~ISOM_TF_FLAGS_DEFAULT_SAMPLE_FLAGS_PRESENT
;
7560 /* When using for live streaming, setting explicit base_data_offset is not preferable.
7561 * However, it's OK because we haven't supported this yet.
7562 * Implicit base_data_offsets that originate in the first byte of each Movie Fragment Box will be implemented
7563 * by the feature of ISO Base Media File Format version 5 or later.
7564 * Media Data Box starts immediately after Movie Fragment Box. */
7565 for( lsmash_entry_t
*entry
= moof
->traf_list
->head
; entry
; entry
= entry
->next
)
7567 isom_traf_entry_t
*traf
= (isom_traf_entry_t
*)entry
->data
;
7568 traf
->tfhd
->flags
|= ISOM_TF_FLAGS_BASE_DATA_OFFSET_PRESENT
;
7570 /* Consider the update of tf_flags here. */
7571 if( isom_update_moof_entry_size( moof
) )
7573 /* Now, we can calculate offsets in the current movie fragment, so do it. */
7574 for( lsmash_entry_t
*entry
= moof
->traf_list
->head
; entry
; entry
= entry
->next
)
7576 isom_traf_entry_t
*traf
= (isom_traf_entry_t
*)entry
->data
;
7577 traf
->tfhd
->base_data_offset
= root
->size
+ moof
->size
+ ISOM_DEFAULT_BOX_HEADER_SIZE
;
7579 if( isom_write_moof( root
->bs
, moof
) )
7581 root
->size
+= moof
->size
;
7582 /* Output samples. */
7583 return isom_output_fragment_media_data( root
);
7586 #undef GET_MOST_USED
7588 static isom_trun_optional_row_t
*isom_request_trun_optional_row( isom_trun_entry_t
*trun
, isom_tfhd_t
*tfhd
, uint32_t sample_number
)
7590 isom_trun_optional_row_t
*row
= NULL
;
7591 if( !trun
->optional
)
7593 trun
->optional
= lsmash_create_entry_list();
7594 if( !trun
->optional
)
7597 if( trun
->optional
->entry_count
< sample_number
)
7599 while( trun
->optional
->entry_count
< sample_number
)
7601 row
= malloc( sizeof(isom_trun_optional_row_t
) );
7604 /* Copy from default. */
7605 row
->sample_duration
= tfhd
->default_sample_duration
;
7606 row
->sample_size
= tfhd
->default_sample_size
;
7607 row
->sample_flags
= tfhd
->default_sample_flags
;
7608 row
->sample_composition_time_offset
= 0;
7609 if( lsmash_add_entry( trun
->optional
, row
) )
7618 for( lsmash_entry_t
*entry
= trun
->optional
->head
; entry
; entry
= entry
->next
)
7620 row
= (isom_trun_optional_row_t
*)entry
->data
;
7623 if( ++i
== sample_number
)
7629 int lsmash_create_fragment_empty_duration( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t duration
)
7631 if( !root
|| !root
->fragment
|| !root
->fragment
->movie
|| !root
->moov
)
7633 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
7634 if( !trak
|| !trak
->tkhd
)
7636 isom_trex_entry_t
*trex
= isom_get_trex( root
->moov
->mvex
, track_ID
);
7639 isom_moof_entry_t
*moof
= root
->fragment
->movie
;
7640 isom_traf_entry_t
*traf
= isom_get_traf( moof
, track_ID
);
7643 traf
= isom_add_traf( root
, moof
);
7644 if( isom_add_tfhd( traf
) )
7646 isom_tfhd_t
*tfhd
= traf
->tfhd
;
7647 tfhd
->flags
= ISOM_TF_FLAGS_DURATION_IS_EMPTY
; /* no samples for this track fragment yet */
7648 tfhd
->track_ID
= trak
->tkhd
->track_ID
;
7649 tfhd
->default_sample_duration
= duration
;
7650 if( duration
!= trex
->default_sample_duration
)
7651 tfhd
->flags
|= ISOM_TF_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT
;
7652 traf
->cache
= trak
->cache
;
7653 traf
->cache
->fragment
->traf_number
= moof
->traf_list
->entry_count
;
7654 traf
->cache
->fragment
->last_duration
+= duration
; /* The duration of the last sample includes this empty-duration. */
7658 static int isom_set_fragment_last_duration( isom_traf_entry_t
*traf
, uint32_t last_duration
)
7660 isom_tfhd_t
*tfhd
= traf
->tfhd
;
7661 if( !traf
->trun_list
|| !traf
->trun_list
->tail
|| !traf
->trun_list
->tail
->data
)
7663 /* There are no track runs in this track fragment, so it is a empty-duration. */
7664 isom_trex_entry_t
*trex
= isom_get_trex( traf
->root
->moov
->mvex
, tfhd
->track_ID
);
7667 tfhd
->flags
|= ISOM_TF_FLAGS_DURATION_IS_EMPTY
;
7668 if( last_duration
!= trex
->default_sample_duration
)
7669 tfhd
->flags
|= ISOM_TF_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT
;
7670 tfhd
->default_sample_duration
= last_duration
;
7671 traf
->cache
->fragment
->last_duration
= last_duration
;
7674 /* Update the last sample_duration if needed. */
7675 isom_trun_entry_t
*trun
= (isom_trun_entry_t
*)traf
->trun_list
->tail
->data
;
7676 if( trun
->sample_count
== 1 && traf
->trun_list
->entry_count
== 1 )
7678 isom_trex_entry_t
*trex
= isom_get_trex( traf
->root
->moov
->mvex
, tfhd
->track_ID
);
7681 if( last_duration
!= trex
->default_sample_duration
)
7682 tfhd
->flags
|= ISOM_TF_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT
;
7683 tfhd
->default_sample_duration
= last_duration
;
7685 else if( last_duration
!= tfhd
->default_sample_duration
)
7686 trun
->flags
|= ISOM_TR_FLAGS_SAMPLE_DURATION_PRESENT
;
7689 isom_trun_optional_row_t
*row
= isom_request_trun_optional_row( trun
, tfhd
, trun
->sample_count
);
7692 row
->sample_duration
= last_duration
;
7694 traf
->cache
->fragment
->last_duration
= last_duration
;
7698 int lsmash_set_last_sample_delta( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t sample_delta
)
7700 if( !root
|| !track_ID
)
7702 if( root
->fragment
&& root
->fragment
->movie
)
7704 isom_traf_entry_t
*traf
= isom_get_traf( root
->fragment
->movie
, track_ID
);
7705 if( !traf
|| !traf
->cache
|| !traf
->tfhd
|| !traf
->trun_list
)
7707 return isom_set_fragment_last_duration( traf
, sample_delta
);
7709 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
7710 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->mdhd
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
7711 || !trak
->mdia
->minf
->stbl
->stsz
|| !trak
->mdia
->minf
->stbl
->stts
|| !trak
->mdia
->minf
->stbl
->stts
->list
)
7713 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
7714 isom_stts_t
*stts
= stbl
->stts
;
7715 uint32_t sample_count
= isom_get_sample_count( trak
);
7716 if( !stts
->list
->tail
)
7719 return 0; /* no samples */
7720 if( sample_count
> 1 )
7721 return -1; /* irregular sample_count */
7722 if( isom_add_stts_entry( stbl
, sample_delta
) )
7724 return lsmash_update_track_duration( root
, track_ID
, 0 );
7727 for( lsmash_entry_t
*entry
= stts
->list
->head
; entry
; entry
= entry
->next
)
7728 i
+= ((isom_stts_entry_t
*)entry
->data
)->sample_count
;
7729 if( sample_count
< i
)
7731 isom_stts_entry_t
*last_stts_data
= (isom_stts_entry_t
*)stts
->list
->tail
->data
;
7732 if( !last_stts_data
)
7734 if( sample_count
> i
)
7736 if( sample_count
- i
> 1 )
7738 /* Add a sample_delta. */
7739 if( sample_delta
== last_stts_data
->sample_delta
)
7740 ++ last_stts_data
->sample_count
;
7741 else if( isom_add_stts_entry( stbl
, sample_delta
) )
7744 else if( sample_count
== i
&& isom_replace_last_sample_delta( stbl
, sample_delta
) )
7746 return lsmash_update_track_duration( root
, track_ID
, sample_delta
);
7749 void lsmash_discard_boxes( lsmash_root_t
*root
)
7753 isom_remove_ftyp( root
->ftyp
);
7754 isom_remove_moov( root
);
7755 lsmash_remove_list( root
->moof_list
, isom_remove_moof
);
7756 isom_remove_mdat( root
->mdat
);
7757 isom_remove_free( root
->free
);
7758 isom_remove_mfra( root
->mfra
);
7761 root
->moof_list
= NULL
;
7767 void lsmash_destroy_root( lsmash_root_t
*root
)
7771 #ifdef LSMASH_DEMUXER_ENABLED
7772 isom_remove_print_funcs( root
);
7773 isom_remove_timelines( root
);
7775 lsmash_discard_boxes( root
);
7778 if( root
->bs
->stream
)
7779 fclose( root
->bs
->stream
);
7780 if( root
->bs
->data
)
7781 free( root
->bs
->data
);
7784 if( root
->fragment
)
7786 lsmash_remove_list( root
->fragment
->pool
, lsmash_delete_sample
);
7787 free( root
->fragment
);
7792 /*---- timeline manipulator ----*/
7794 int lsmash_modify_timeline_map( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t entry_number
, uint64_t segment_duration
, int64_t media_time
, int32_t media_rate
)
7796 if( !segment_duration
|| media_time
< -1 )
7798 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
7799 if( !trak
|| !trak
->edts
|| !trak
->edts
->elst
|| !trak
->edts
->elst
->list
)
7801 isom_elst_t
*elst
= trak
->edts
->elst
;
7802 isom_elst_entry_t
*data
= (isom_elst_entry_t
*)lsmash_get_entry_data( elst
->list
, entry_number
);
7805 data
->segment_duration
= segment_duration
;
7806 data
->media_time
= media_time
;
7807 data
->media_rate
= media_rate
;
7808 if( !elst
->pos
|| !root
->fragment
|| root
->bs
->stream
== stdout
)
7809 return isom_update_tkhd_duration( trak
);
7810 /* Rewrite the specified entry.
7811 * Note: we don't update the version of the Edit List Box. */
7812 lsmash_bs_t
*bs
= root
->bs
;
7813 FILE *stream
= bs
->stream
;
7814 uint64_t current_pos
= lsmash_ftell( stream
);
7815 uint64_t entry_pos
= elst
->pos
+ ISOM_DEFAULT_LIST_FULLBOX_HEADER_SIZE
+ ((uint64_t)entry_number
- 1) * (elst
->version
== 1 ? 20 : 12);
7816 lsmash_fseek( stream
, entry_pos
, SEEK_SET
);
7819 lsmash_bs_put_be64( bs
, data
->segment_duration
);
7820 lsmash_bs_put_be64( bs
, data
->media_time
);
7824 lsmash_bs_put_be32( bs
, (uint32_t)data
->segment_duration
);
7825 lsmash_bs_put_be32( bs
, (uint32_t)data
->media_time
);
7827 lsmash_bs_put_be32( bs
, data
->media_rate
);
7828 int ret
= lsmash_bs_write_data( bs
);
7829 lsmash_fseek( stream
, current_pos
, SEEK_SET
);
7833 int lsmash_create_explicit_timeline_map( lsmash_root_t
*root
, uint32_t track_ID
, uint64_t segment_duration
, int64_t media_time
, int32_t media_rate
)
7835 if( media_time
< -1 )
7837 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
7838 if( !trak
|| !trak
->tkhd
)
7840 segment_duration
= (segment_duration
|| root
->fragment
) ? segment_duration
7841 : trak
->tkhd
->duration
? trak
->tkhd
->duration
7842 : isom_update_tkhd_duration( trak
) ? 0
7843 : trak
->tkhd
->duration
;
7844 if( isom_add_edts( trak
)
7845 || isom_add_elst( trak
->edts
)
7846 || isom_add_elst_entry( trak
->edts
->elst
, segment_duration
, media_time
, media_rate
) )
7848 return isom_update_tkhd_duration( trak
);
7851 /*---- create / modification time fields manipulators ----*/
7853 int lsmash_update_media_modification_time( lsmash_root_t
*root
, uint32_t track_ID
)
7855 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
7856 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->mdhd
)
7858 isom_mdhd_t
*mdhd
= trak
->mdia
->mdhd
;
7859 mdhd
->modification_time
= isom_get_current_mp4time();
7860 /* overwrite strange creation_time */
7861 if( mdhd
->creation_time
> mdhd
->modification_time
)
7862 mdhd
->creation_time
= mdhd
->modification_time
;
7866 int lsmash_update_track_modification_time( lsmash_root_t
*root
, uint32_t track_ID
)
7868 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
7869 if( !trak
|| !trak
->tkhd
)
7871 isom_tkhd_t
*tkhd
= trak
->tkhd
;
7872 tkhd
->modification_time
= isom_get_current_mp4time();
7873 /* overwrite strange creation_time */
7874 if( tkhd
->creation_time
> tkhd
->modification_time
)
7875 tkhd
->creation_time
= tkhd
->modification_time
;
7879 int lsmash_update_movie_modification_time( lsmash_root_t
*root
)
7881 if( !root
|| !root
->moov
|| !root
->moov
->mvhd
)
7883 isom_mvhd_t
*mvhd
= root
->moov
->mvhd
;
7884 mvhd
->modification_time
= isom_get_current_mp4time();
7885 /* overwrite strange creation_time */
7886 if( mvhd
->creation_time
> mvhd
->modification_time
)
7887 mvhd
->creation_time
= mvhd
->modification_time
;
7891 /*---- sample manipulators ----*/
7892 lsmash_sample_t
*lsmash_create_sample( uint32_t size
)
7894 lsmash_sample_t
*sample
= malloc( sizeof(lsmash_sample_t
) );
7897 memset( sample
, 0, sizeof(lsmash_sample_t
) );
7900 sample
->data
= malloc( size
);
7906 sample
->length
= size
;
7911 int lsmash_sample_alloc( lsmash_sample_t
*sample
, uint32_t size
)
7918 free( sample
->data
);
7919 sample
->data
= NULL
;
7923 if( size
== sample
->length
)
7927 data
= malloc( size
);
7929 data
= realloc( sample
->data
, size
);
7932 sample
->data
= data
;
7933 sample
->length
= size
;
7937 void lsmash_delete_sample( lsmash_sample_t
*sample
)
7942 free( sample
->data
);
7946 static uint32_t isom_add_size( isom_trak_entry_t
*trak
, uint32_t sample_size
)
7948 if( isom_add_stsz_entry( trak
->mdia
->minf
->stbl
, sample_size
) )
7950 return isom_get_sample_count( trak
);
7953 static uint32_t isom_add_dts( isom_trak_entry_t
*trak
, uint64_t dts
)
7955 if( !trak
->cache
|| !trak
->mdia
->minf
->stbl
->stts
|| !trak
->mdia
->minf
->stbl
->stts
->list
)
7957 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
7958 isom_stts_t
*stts
= stbl
->stts
;
7959 isom_timestamp_t
*cache
= &trak
->cache
->timestamp
;
7960 if( !stts
->list
->entry_count
)
7962 if( isom_add_stts_entry( stbl
, dts
) )
7967 if( dts
<= cache
->dts
)
7969 uint32_t sample_delta
= dts
- cache
->dts
;
7970 isom_stts_entry_t
*data
= (isom_stts_entry_t
*)stts
->list
->tail
->data
;
7971 if( data
->sample_delta
== sample_delta
)
7972 ++ data
->sample_count
;
7973 else if( isom_add_stts_entry( stbl
, sample_delta
) )
7976 return sample_delta
;
7979 static int isom_add_cts( isom_trak_entry_t
*trak
, uint64_t cts
)
7983 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
7984 isom_ctts_t
*ctts
= stbl
->ctts
;
7985 isom_timestamp_t
*cache
= &trak
->cache
->timestamp
;
7988 if( cts
== cache
->dts
)
7993 /* Add ctts box and the first ctts entry. */
7994 if( isom_add_ctts( stbl
) || isom_add_ctts_entry( stbl
, 0 ) )
7996 uint32_t sample_count
= isom_get_sample_count( trak
);
7998 isom_ctts_entry_t
*data
= (isom_ctts_entry_t
*)ctts
->list
->head
->data
;
7999 if( sample_count
!= 1 )
8001 data
->sample_count
= isom_get_sample_count( trak
) - 1;
8002 if( isom_add_ctts_entry( stbl
, cts
- cache
->dts
) )
8006 data
->sample_offset
= cts
;
8012 isom_ctts_entry_t
*data
= (isom_ctts_entry_t
*)ctts
->list
->tail
->data
;
8013 uint32_t sample_offset
= cts
- cache
->dts
;
8014 if( data
->sample_offset
== sample_offset
)
8015 ++ data
->sample_count
;
8016 else if( isom_add_ctts_entry( stbl
, sample_offset
) )
8022 static int isom_add_timestamp( isom_trak_entry_t
*trak
, uint64_t dts
, uint64_t cts
)
8026 uint32_t sample_count
= isom_get_sample_count( trak
);
8027 uint32_t sample_delta
= sample_count
> 1 ? isom_add_dts( trak
, dts
) : 0;
8028 if( sample_count
> 1 && !sample_delta
)
8030 if( isom_add_cts( trak
, cts
) )
8032 if( trak
->cache
->fragment
)
8034 isom_cache_t
*cache
= trak
->cache
;
8035 cache
->fragment
->last_duration
= sample_delta
;
8036 cache
->fragment
->largest_cts
= LSMASH_MAX( cache
->timestamp
.cts
, cache
->fragment
->largest_cts
);
8041 static int isom_add_sync_point( isom_trak_entry_t
*trak
, uint32_t sample_number
, lsmash_sample_property_t
*prop
)
8043 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
8044 isom_cache_t
*cache
= trak
->cache
;
8045 if( prop
->random_access_type
!= ISOM_SAMPLE_RANDOM_ACCESS_TYPE_SYNC
) /* no null check for prop */
8047 if( !cache
->all_sync
)
8049 if( !stbl
->stss
&& isom_add_stss( stbl
) )
8051 if( isom_add_stss_entry( stbl
, 1 ) ) /* Declare here the first sample is a sync sample. */
8053 cache
->all_sync
= 0;
8056 if( cache
->all_sync
) /* We don't need stss box if all samples are sync sample. */
8060 if( isom_get_sample_count( trak
) == 1 )
8062 cache
->all_sync
= 1; /* Also the first sample is a sync sample. */
8065 if( isom_add_stss( stbl
) )
8068 return isom_add_stss_entry( stbl
, sample_number
);
8071 static int isom_add_partial_sync( isom_trak_entry_t
*trak
, uint32_t sample_number
, lsmash_sample_property_t
*prop
)
8073 if( !trak
->root
->qt_compatible
)
8075 if( prop
->random_access_type
!= QT_SAMPLE_RANDOM_ACCESS_TYPE_PARTIAL_SYNC
8076 && !(prop
->random_access_type
== ISOM_SAMPLE_RANDOM_ACCESS_TYPE_RECOVERY
&& prop
->recovery
.identifier
== prop
->recovery
.complete
) )
8078 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
8079 if( !stbl
->stps
&& isom_add_stps( stbl
) )
8081 return isom_add_stps_entry( stbl
, sample_number
);
8084 static int isom_add_dependency_type( isom_trak_entry_t
*trak
, lsmash_sample_property_t
*prop
)
8086 if( !trak
->root
->qt_compatible
&& !trak
->root
->avc_extensions
)
8088 uint8_t avc_extensions
= trak
->root
->avc_extensions
;
8089 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
8091 return isom_add_sdtp_entry( stbl
, prop
, avc_extensions
);
8092 if( !prop
->allow_earlier
&& !prop
->leading
&& !prop
->independent
&& !prop
->disposable
&& !prop
->redundant
) /* no null check for prop */
8094 if( isom_add_sdtp( stbl
) )
8096 uint32_t count
= isom_get_sample_count( trak
);
8097 /* fill past samples with ISOM_SAMPLE_*_UNKNOWN */
8098 lsmash_sample_property_t null_prop
= { 0 };
8099 for( uint32_t i
= 1; i
< count
; i
++ )
8100 if( isom_add_sdtp_entry( stbl
, &null_prop
, avc_extensions
) )
8102 return isom_add_sdtp_entry( stbl
, prop
, avc_extensions
);
8105 static int isom_group_random_access( isom_trak_entry_t
*trak
, lsmash_sample_property_t
*prop
)
8107 if( trak
->root
->max_isom_version
< 6 )
8109 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
8110 isom_sbgp_entry_t
*sbgp
= isom_get_sample_to_group( stbl
, ISOM_GROUP_TYPE_RAP
);
8111 isom_sgpd_entry_t
*sgpd
= isom_get_sample_group_description( stbl
, ISOM_GROUP_TYPE_RAP
);
8112 if( !sbgp
|| !sgpd
)
8114 uint8_t is_rap
= prop
->random_access_type
== ISOM_SAMPLE_RANDOM_ACCESS_TYPE_CLOSED_RAP
8115 || prop
->random_access_type
== ISOM_SAMPLE_RANDOM_ACCESS_TYPE_OPEN_RAP
8116 || prop
->random_access_type
== ISOM_SAMPLE_RANDOM_ACCESS_TYPE_UNKNOWN_RAP
8117 || (prop
->random_access_type
== ISOM_SAMPLE_RANDOM_ACCESS_TYPE_RECOVERY
&& prop
->recovery
.identifier
== prop
->recovery
.complete
);
8118 isom_rap_group_t
*group
= trak
->cache
->rap
;
8121 /* This sample is the first sample, create a grouping cache. */
8122 assert( isom_get_sample_count( trak
) == 1 );
8123 group
= malloc( sizeof(isom_rap_group_t
) );
8128 group
->random_access
= isom_add_rap_group_entry( sgpd
);
8129 group
->assignment
= isom_add_group_assignment_entry( sbgp
, 1, sgpd
->list
->entry_count
);
8133 /* The first sample is not always random access point. */
8134 group
->random_access
= NULL
;
8135 group
->assignment
= isom_add_group_assignment_entry( sbgp
, 1, 0 );
8137 if( !group
->assignment
)
8142 /* No need checking if group->assignment exists from here. */
8143 group
->is_prev_rap
= is_rap
;
8144 trak
->cache
->rap
= group
;
8147 if( group
->is_prev_rap
)
8149 /* OK. here, the previous sample is a menber of 'rap '. */
8152 /* This sample isn't a member of 'rap ' and the previous sample is.
8153 * So we create a new group and set 0 on its group_description_index. */
8154 group
->assignment
= isom_add_group_assignment_entry( sbgp
, 1, 0 );
8155 if( !group
->assignment
)
8161 else if( prop
->random_access_type
!= ISOM_SAMPLE_RANDOM_ACCESS_TYPE_CLOSED_RAP
)
8163 /* Create a new group since there is the possibility the next sample is a leading sample.
8164 * This sample is a member of 'rap ', so we set appropriate value on its group_description_index. */
8165 if( group
->random_access
)
8166 group
->random_access
->num_leading_samples_known
= 1;
8167 group
->random_access
= isom_add_rap_group_entry( sgpd
);
8168 group
->assignment
= isom_add_group_assignment_entry( sbgp
, 1, sgpd
->list
->entry_count
);
8169 if( !group
->assignment
)
8175 else /* The previous and current sample are a member of 'rap ', and the next sample must not be a leading sample. */
8176 ++ group
->assignment
->sample_count
;
8180 /* This sample is a member of 'rap ' and the previous sample isn't.
8181 * So we create a new group and set appropriate value on its group_description_index. */
8182 if( group
->random_access
)
8183 group
->random_access
->num_leading_samples_known
= 1;
8184 group
->random_access
= isom_add_rap_group_entry( sgpd
);
8185 group
->assignment
= isom_add_group_assignment_entry( sbgp
, 1, sgpd
->list
->entry_count
);
8186 if( !group
->assignment
)
8192 else /* The previous and current sample aren't a member of 'rap '. */
8193 ++ group
->assignment
->sample_count
;
8194 /* Obtain the property of the latest random access point group. */
8195 if( !is_rap
&& group
->random_access
)
8197 if( prop
->leading
== ISOM_SAMPLE_LEADING_UNKNOWN
)
8199 /* We can no longer know num_leading_samples in this group. */
8200 group
->random_access
->num_leading_samples_known
= 0;
8201 group
->random_access
= NULL
;
8205 if( prop
->leading
== ISOM_SAMPLE_IS_UNDECODABLE_LEADING
|| prop
->leading
== ISOM_SAMPLE_IS_DECODABLE_LEADING
)
8206 ++ group
->random_access
->num_leading_samples
;
8209 /* no more consecutive leading samples in this group */
8210 group
->random_access
->num_leading_samples_known
= 1;
8211 group
->random_access
= NULL
;
8215 group
->is_prev_rap
= is_rap
;
8219 static int isom_group_roll_recovery( isom_trak_entry_t
*trak
, lsmash_sample_property_t
*prop
)
8221 if( !trak
->root
->avc_extensions
)
8223 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
8224 isom_sbgp_entry_t
*sbgp
= isom_get_sample_to_group( stbl
, ISOM_GROUP_TYPE_ROLL
);
8225 isom_sgpd_entry_t
*sgpd
= isom_get_sample_group_description( stbl
, ISOM_GROUP_TYPE_ROLL
);
8226 if( !sbgp
|| !sgpd
)
8228 lsmash_entry_list_t
*pool
= trak
->cache
->roll
.pool
;
8231 pool
= lsmash_create_entry_list();
8234 trak
->cache
->roll
.pool
= pool
;
8236 isom_roll_group_t
*group
= (isom_roll_group_t
*)lsmash_get_entry_data( pool
, pool
->entry_count
);
8237 uint32_t sample_count
= isom_get_sample_count( trak
);
8238 if( !group
|| prop
->random_access_type
== ISOM_SAMPLE_RANDOM_ACCESS_TYPE_RECOVERY
)
8241 group
->delimited
= 1;
8243 assert( sample_count
== 1 );
8244 /* Create a new group. This group is not 'roll' yet, so we set 0 on its group_description_index. */
8245 group
= malloc( sizeof(isom_roll_group_t
) );
8248 memset( group
, 0, sizeof(isom_roll_group_t
) );
8249 group
->first_sample
= sample_count
;
8250 group
->recovery_point
= prop
->recovery
.complete
;
8251 group
->assignment
= isom_add_group_assignment_entry( sbgp
, 1, 0 );
8252 if( !group
->assignment
|| lsmash_add_entry( pool
, group
) )
8259 ++ group
->assignment
->sample_count
;
8260 /* If encountered a sync sample, all recoveries are completed here. */
8261 if( prop
->random_access_type
== ISOM_SAMPLE_RANDOM_ACCESS_TYPE_CLOSED_RAP
)
8263 for( lsmash_entry_t
*entry
= pool
->head
; entry
; entry
= entry
->next
)
8265 group
= (isom_roll_group_t
*)entry
->data
;
8268 group
->described
= 1;
8272 for( lsmash_entry_t
*entry
= pool
->head
; entry
; entry
= entry
->next
)
8274 group
= (isom_roll_group_t
*)entry
->data
;
8277 if( group
->described
)
8279 if( prop
->recovery
.identifier
== group
->recovery_point
)
8281 group
->described
= 1;
8282 int16_t distance
= sample_count
- group
->first_sample
;
8283 /* Add a roll recovery entry only when roll_distance isn't zero since roll_distance = 0 must not be used. */
8286 /* Now, this group is a 'roll'. */
8287 if( !isom_add_roll_group_entry( sgpd
, distance
) )
8289 group
->assignment
->group_description_index
= sgpd
->list
->entry_count
;
8290 /* All groups before the current group are described. */
8291 lsmash_entry_t
*current
= entry
;
8292 for( entry
= pool
->head
; entry
!= current
; entry
= entry
->next
)
8294 group
= (isom_roll_group_t
*)entry
->data
;
8297 group
->described
= 1;
8300 break; /* Avoid evaluating groups, in the pool, having the same identifier for recovery point again. */
8303 /* Remove pooled caches that has become unnecessary. */
8304 for( lsmash_entry_t
*entry
= pool
->head
; entry
; entry
= pool
->head
)
8306 group
= (isom_roll_group_t
*)entry
->data
;
8309 if( !group
->delimited
|| !group
->described
)
8311 if( lsmash_remove_entry_direct( pool
, entry
, NULL
) )
8317 /* returns 1 if pooled samples must be flushed. */
8318 /* FIXME: I wonder if this function should have a extra argument which indicates force_to_flush_cached_chunk.
8319 see lsmash_append_sample for detail. */
8320 static int isom_add_chunk( isom_trak_entry_t
*trak
, lsmash_sample_t
*sample
)
8322 if( !trak
->root
|| !trak
->cache
|| !trak
->mdia
->mdhd
|| !trak
->mdia
->mdhd
->timescale
8323 || !trak
->mdia
->minf
->stbl
->stsc
|| !trak
->mdia
->minf
->stbl
->stsc
->list
)
8325 lsmash_root_t
*root
= trak
->root
;
8326 isom_chunk_t
*current
= &trak
->cache
->chunk
;
8327 if( !current
->pool
)
8329 /* Very initial settings, just once per track */
8330 current
->pool
= lsmash_create_entry_list();
8331 if( !current
->pool
)
8334 if( !current
->pool
->entry_count
)
8336 /* Cannot decide whether we should flush the current sample or not here yet. */
8337 ++ current
->chunk_number
;
8338 current
->sample_description_index
= sample
->index
;
8339 current
->first_dts
= sample
->dts
;
8342 if( sample
->dts
< current
->first_dts
)
8343 return -1; /* easy error check. */
8344 if( (root
->max_chunk_duration
>= ((double)(sample
->dts
- current
->first_dts
) / trak
->mdia
->mdhd
->timescale
))
8345 && (root
->max_chunk_size
>= current
->pool_size
+ sample
->length
)
8346 && (current
->sample_description_index
== sample
->index
) )
8347 return 0; /* No need to flush current cached chunk, the current sample must be put into that. */
8348 /* NOTE: chunk relative stuff must be pushed into root after a chunk is fully determined with its contents. */
8349 /* now current cached chunk is fixed, actually add chunk relative properties to root accordingly. */
8350 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
8351 lsmash_entry_t
*last_stsc_entry
= stbl
->stsc
->list
->tail
;
8352 /* Create a new chunk sequence in this track if needed. */
8353 if( (!last_stsc_entry
|| current
->pool
->entry_count
!= ((isom_stsc_entry_t
*)last_stsc_entry
->data
)->samples_per_chunk
)
8354 && isom_add_stsc_entry( stbl
, current
->chunk_number
, current
->pool
->entry_count
, current
->sample_description_index
) )
8356 /* Add a new chunk offset in this track. */
8357 uint64_t offset
= root
->size
;
8358 if( root
->fragment
)
8359 offset
+= ISOM_DEFAULT_BOX_HEADER_SIZE
+ root
->fragment
->pool_size
;
8360 if( isom_add_stco_entry( stbl
, offset
) )
8362 /* update cache information */
8363 ++ current
->chunk_number
;
8364 /* re-initialize cache, using the current sample */
8365 current
->sample_description_index
= sample
->index
;
8366 current
->first_dts
= sample
->dts
;
8367 /* current->pool must be flushed in isom_append_sample_internal() */
8371 static int isom_write_pooled_samples( lsmash_root_t
*root
, isom_chunk_t
*chunk
)
8373 if( !root
|| !root
->mdat
|| !root
->bs
|| !root
->bs
->stream
)
8375 uint64_t chunk_size
= 0;
8376 for( lsmash_entry_t
*entry
= chunk
->pool
->head
; entry
; entry
= entry
->next
)
8378 lsmash_sample_t
*sample
= (lsmash_sample_t
*)entry
->data
;
8379 if( !sample
|| !sample
->data
)
8381 lsmash_bs_put_bytes( root
->bs
, sample
->data
, sample
->length
);
8382 chunk_size
+= sample
->length
;
8384 if( lsmash_bs_write_data( root
->bs
) )
8386 root
->mdat
->size
+= chunk_size
;
8387 root
->size
+= chunk_size
;
8388 lsmash_remove_entries( chunk
->pool
, lsmash_delete_sample
);
8389 chunk
->pool_size
= 0;
8393 static int isom_update_sample_tables( isom_trak_entry_t
*trak
, lsmash_sample_t
*sample
)
8395 /* Add a sample_size and increment sample_count. */
8396 uint32_t sample_count
= isom_add_size( trak
, sample
->length
);
8399 /* Add a decoding timestamp and a composition timestamp. */
8400 if( isom_add_timestamp( trak
, sample
->dts
, sample
->cts
) )
8402 /* Add a sync point if needed. */
8403 if( isom_add_sync_point( trak
, sample_count
, &sample
->prop
) )
8405 /* Add a partial sync point if needed. */
8406 if( isom_add_partial_sync( trak
, sample_count
, &sample
->prop
) )
8408 /* Add leading, independent, disposable and redundant information if needed. */
8409 if( isom_add_dependency_type( trak
, &sample
->prop
) )
8411 /* Group samples into random access point type if needed. */
8412 if( isom_group_random_access( trak
, &sample
->prop
) )
8414 /* Group samples into random access recovery point type if needed. */
8415 if( isom_group_roll_recovery( trak
, &sample
->prop
) )
8417 /* Add a chunk if needed. */
8418 return isom_add_chunk( trak
, sample
);
8421 static void isom_append_fragment_track_run( lsmash_root_t
*root
, isom_chunk_t
*chunk
)
8423 if( !chunk
->pool
|| !chunk
->pool
->head
)
8425 isom_fragment_manager_t
*fragment
= root
->fragment
;
8426 /* Move samples in the pool of the current track fragment to the pool of the current movie fragment.
8427 * Empty the pool of current track. We don't delete data of samples here. */
8428 if( fragment
->pool
->tail
)
8430 fragment
->pool
->tail
->next
= chunk
->pool
->head
;
8431 fragment
->pool
->tail
->next
->prev
= fragment
->pool
->tail
;
8434 fragment
->pool
->head
= chunk
->pool
->head
;
8435 fragment
->pool
->tail
= chunk
->pool
->tail
;
8436 fragment
->pool
->entry_count
+= chunk
->pool
->entry_count
;
8437 fragment
->pool_size
+= chunk
->pool_size
;
8438 chunk
->pool_size
= 0;
8439 chunk
->pool
->entry_count
= 0;
8440 chunk
->pool
->head
= NULL
;
8441 chunk
->pool
->tail
= NULL
;
8444 static int isom_output_cached_chunk( isom_trak_entry_t
*trak
)
8446 lsmash_root_t
*root
= trak
->root
;
8447 isom_chunk_t
*chunk
= &trak
->cache
->chunk
;
8448 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
8449 lsmash_entry_t
*last_stsc_entry
= stbl
->stsc
->list
->tail
;
8450 /* Create a new chunk sequence in this track if needed. */
8451 if( (!last_stsc_entry
|| chunk
->pool
->entry_count
!= ((isom_stsc_entry_t
*)last_stsc_entry
->data
)->samples_per_chunk
)
8452 && isom_add_stsc_entry( stbl
, chunk
->chunk_number
, chunk
->pool
->entry_count
, chunk
->sample_description_index
) )
8454 if( root
->fragment
)
8456 /* Add a new chunk offset in this track. */
8457 if( isom_add_stco_entry( stbl
, root
->size
+ ISOM_DEFAULT_BOX_HEADER_SIZE
+ root
->fragment
->pool_size
) )
8459 isom_append_fragment_track_run( root
, chunk
);
8462 /* Add a new chunk offset in this track. */
8463 if( isom_add_stco_entry( stbl
, root
->size
) )
8465 /* Output pooled samples in this track. */
8466 return isom_write_pooled_samples( root
, chunk
);
8469 static int isom_append_sample_internal( isom_trak_entry_t
*trak
, lsmash_sample_t
*sample
)
8471 int flush
= isom_update_sample_tables( trak
, sample
);
8474 /* flush == 1 means pooled samples must be flushed. */
8475 lsmash_root_t
*root
= trak
->root
;
8476 isom_chunk_t
*current
= &trak
->cache
->chunk
;
8477 if( flush
== 1 && isom_write_pooled_samples( root
, current
) )
8479 /* Arbitration system between tracks with extremely scattering dts.
8480 * Here, we check whether asynchronization between the tracks exceeds the tolerance.
8481 * If a track has too old "first DTS" in its cached chunk than current sample's DTS, then its pooled samples must be flushed.
8482 * We don't consider presentation of media since any edit can pick an arbitrary portion of media in track.
8483 * Note: you needn't read this loop until you grasp the basic handling of chunks. */
8484 double tolerance
= root
->max_async_tolerance
;
8485 for( lsmash_entry_t
*entry
= root
->moov
->trak_list
->head
; entry
; entry
= entry
->next
)
8487 isom_trak_entry_t
*other
= (isom_trak_entry_t
*)entry
->data
;
8490 if( !other
|| !other
->cache
|| !other
->mdia
|| !other
->mdia
->mdhd
|| !other
->mdia
->mdhd
->timescale
8491 || !other
->mdia
->minf
|| !other
->mdia
->minf
->stbl
|| !other
->mdia
->minf
->stbl
->stsc
|| !other
->mdia
->minf
->stbl
->stsc
->list
)
8493 isom_chunk_t
*chunk
= &other
->cache
->chunk
;
8494 if( !chunk
->pool
|| !chunk
->pool
->entry_count
)
8496 double diff
= ((double)sample
->dts
/ trak
->mdia
->mdhd
->timescale
)
8497 - ((double)chunk
->first_dts
/ other
->mdia
->mdhd
->timescale
);
8498 if( diff
> tolerance
&& isom_output_cached_chunk( other
) )
8500 /* Note: we don't flush the cached chunk in the current track and the current sample here
8501 * even if the conditional expression of '-diff > tolerance' meets.
8502 * That's useless because appending a sample to another track would be a good equivalent.
8503 * It's even harmful because it causes excess chunk division by calling
8504 * isom_output_cached_chunk() which always generates a new chunk.
8505 * Anyway some excess chunk division will be there, but rather less without it.
8506 * To completely avoid this, we need to observe at least whether the current sample will be placed
8507 * right next to the previous chunk of the same track or not. */
8509 /* anyway the current sample must be pooled. */
8510 if( lsmash_add_entry( current
->pool
, sample
) )
8512 current
->pool_size
+= sample
->length
;
8516 static int isom_append_sample( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_sample_t
*sample
)
8518 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
8519 if( !trak
|| !trak
->root
|| !trak
->cache
|| !trak
->mdia
8520 || !trak
->mdia
->mdhd
|| !trak
->mdia
->mdhd
->timescale
8521 || !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
8522 || !trak
->mdia
->minf
->stbl
->stsd
|| !trak
->mdia
->minf
->stbl
->stsd
->list
8523 || !trak
->mdia
->minf
->stbl
->stsc
|| !trak
->mdia
->minf
->stbl
->stsc
->list
)
8525 /* If there is no available Media Data Box to write samples, add and write a new one before any chunk offset is decided. */
8528 if( isom_new_mdat( root
, 0 ) )
8530 /* Add the size of the Media Data Box and the placeholder. */
8531 root
->size
+= 2 * ISOM_DEFAULT_BOX_HEADER_SIZE
;
8533 isom_sample_entry_t
*sample_entry
= (isom_sample_entry_t
*)lsmash_get_entry_data( trak
->mdia
->minf
->stbl
->stsd
->list
, sample
->index
);
8536 if( isom_is_lpcm_audio( sample_entry
->type
) )
8538 uint32_t frame_size
= ((isom_audio_entry_t
*)sample_entry
)->constBytesPerAudioPacket
;
8539 uint64_t dts
= sample
->dts
;
8540 uint64_t cts
= sample
->cts
;
8541 /* Append samples splitted into each LPCMFrame. */
8542 for( uint32_t offset
= 0; offset
< sample
->length
; offset
+= frame_size
)
8544 lsmash_sample_t
*lpcm_sample
= lsmash_create_sample( frame_size
);
8547 memcpy( lpcm_sample
->data
, sample
->data
+ offset
, frame_size
);
8548 lpcm_sample
->dts
= dts
++;
8549 lpcm_sample
->cts
= cts
++;
8550 lpcm_sample
->prop
= sample
->prop
;
8551 lpcm_sample
->index
= sample
->index
;
8552 if( isom_append_sample_internal( trak
, lpcm_sample
) )
8554 lsmash_delete_sample( lpcm_sample
);
8558 lsmash_delete_sample( sample
);
8561 return isom_append_sample_internal( trak
, sample
);
8564 static int isom_output_cache( isom_trak_entry_t
*trak
)
8566 if( trak
->cache
->chunk
.pool
&& trak
->cache
->chunk
.pool
->entry_count
8567 && isom_output_cached_chunk( trak
) )
8569 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
8570 if( !stbl
->sgpd_list
)
8572 for( lsmash_entry_t
*entry
= stbl
->sgpd_list
->head
; entry
; entry
= entry
->next
)
8574 isom_sgpd_entry_t
*sgpd
= (isom_sgpd_entry_t
*)entry
->data
;
8577 switch( sgpd
->grouping_type
)
8579 case ISOM_GROUP_TYPE_RAP
:
8581 isom_rap_group_t
*group
= trak
->cache
->rap
;
8584 if( trak
->root
->fragment
)
8589 if( !group
->random_access
)
8591 group
->random_access
->num_leading_samples_known
= 1;
8594 case ISOM_GROUP_TYPE_ROLL
:
8595 if( !trak
->cache
->roll
.pool
)
8597 if( trak
->root
->fragment
)
8602 for( lsmash_entry_t
*roll_entry
= trak
->cache
->roll
.pool
->head
; roll_entry
; roll_entry
= roll_entry
->next
)
8604 isom_roll_group_t
*group
= (isom_roll_group_t
*)roll_entry
->data
;
8607 group
->described
= 1;
8617 static int isom_flush_fragment_pooled_samples( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t last_sample_duration
)
8619 isom_traf_entry_t
*traf
= isom_get_traf( root
->fragment
->movie
, track_ID
);
8621 return 0; /* no samples */
8622 if( !traf
->cache
|| !traf
->cache
->fragment
)
8624 if( traf
->trun_list
&& traf
->trun_list
->entry_count
&& traf
->trun_list
->tail
&& traf
->trun_list
->tail
->data
)
8626 /* Media Data Box preceded by Movie Fragment Box could change base_data_offsets in each track fragments later.
8627 * We can't consider this here because the length of Movie Fragment Box is unknown at this step yet. */
8628 isom_trun_entry_t
*trun
= (isom_trun_entry_t
*)traf
->trun_list
->tail
->data
;
8629 if( root
->fragment
->pool_size
)
8630 trun
->flags
|= ISOM_TR_FLAGS_DATA_OFFSET_PRESENT
;
8631 trun
->data_offset
= root
->fragment
->pool_size
;
8633 isom_append_fragment_track_run( root
, &traf
->cache
->chunk
);
8634 return isom_set_fragment_last_duration( traf
, last_sample_duration
);
8637 int lsmash_flush_pooled_samples( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t last_sample_delta
)
8641 if( root
->fragment
&& root
->fragment
->movie
)
8642 return isom_flush_fragment_pooled_samples( root
, track_ID
, last_sample_delta
);
8643 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
8644 if( !trak
|| !trak
->cache
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
8645 || !trak
->mdia
->minf
->stbl
->stsc
|| !trak
->mdia
->minf
->stbl
->stsc
->list
)
8647 if( isom_output_cache( trak
) )
8649 return lsmash_set_last_sample_delta( root
, track_ID
, last_sample_delta
);
8652 /* This function doesn't update sample_duration of the last sample in the previous movie fragment.
8653 * Instead of this, isom_finish_movie_fragment undertakes this task. */
8654 static int isom_update_fragment_previous_sample_duration( isom_traf_entry_t
*traf
, isom_trex_entry_t
*trex
, uint32_t duration
)
8656 isom_tfhd_t
*tfhd
= traf
->tfhd
;
8657 isom_trun_entry_t
*trun
= (isom_trun_entry_t
*)traf
->trun_list
->tail
->data
;
8658 int previous_run_has_previous_sample
= 0;
8659 if( trun
->sample_count
== 1 )
8661 if( traf
->trun_list
->entry_count
== 1 )
8662 return 0; /* The previous track run belongs to the previous movie fragment if it exists. */
8663 if( !traf
->trun_list
->tail
->prev
|| !traf
->trun_list
->tail
->prev
->data
)
8665 /* OK. The previous sample exists in the previous track run in the same track fragment. */
8666 trun
= (isom_trun_entry_t
*)traf
->trun_list
->tail
->prev
->data
;
8667 previous_run_has_previous_sample
= 1;
8669 /* Update default_sample_duration of the Track Fragment Header Box
8670 * if this duration is what the first sample in the current track fragment owns. */
8671 if( (trun
->sample_count
== 2 && traf
->trun_list
->entry_count
== 1)
8672 || (trun
->sample_count
== 1 && traf
->trun_list
->entry_count
== 2) )
8674 if( duration
!= trex
->default_sample_duration
)
8675 tfhd
->flags
|= ISOM_TF_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT
;
8676 tfhd
->default_sample_duration
= duration
;
8678 /* Update the previous sample_duration if needed. */
8679 if( duration
!= tfhd
->default_sample_duration
)
8680 trun
->flags
|= ISOM_TR_FLAGS_SAMPLE_DURATION_PRESENT
;
8683 uint32_t sample_number
= trun
->sample_count
- !previous_run_has_previous_sample
;
8684 isom_trun_optional_row_t
*row
= isom_request_trun_optional_row( trun
, tfhd
, sample_number
);
8687 row
->sample_duration
= duration
;
8689 traf
->cache
->fragment
->last_duration
= duration
;
8693 static isom_sample_flags_t
isom_generate_fragment_sample_flags( lsmash_sample_t
*sample
)
8695 isom_sample_flags_t flags
;
8697 flags
.is_leading
= sample
->prop
.leading
& 0x3;
8698 flags
.sample_depends_on
= sample
->prop
.independent
& 0x3;
8699 flags
.sample_is_depended_on
= sample
->prop
.disposable
& 0x3;
8700 flags
.sample_has_redundancy
= sample
->prop
.redundant
& 0x3;
8701 flags
.sample_padding_value
= 0;
8702 flags
.sample_is_non_sync_sample
= sample
->prop
.random_access_type
!= ISOM_SAMPLE_RANDOM_ACCESS_TYPE_SYNC
;
8703 flags
.sample_degradation_priority
= 0;
8707 static int isom_update_fragment_sample_tables( isom_traf_entry_t
*traf
, lsmash_sample_t
*sample
)
8709 isom_tfhd_t
*tfhd
= traf
->tfhd
;
8710 isom_trex_entry_t
*trex
= isom_get_trex( traf
->root
->moov
->mvex
, tfhd
->track_ID
);
8713 lsmash_root_t
*root
= traf
->root
;
8714 isom_cache_t
*cache
= traf
->cache
;
8715 /* Create a new track run if the duration exceeds max_chunk_duration.
8716 * Old one will be appended to the pool of this movie fragment. */
8717 int delimit
= (root
->max_chunk_duration
< ((double)(sample
->dts
- traf
->cache
->chunk
.first_dts
) / lsmash_get_media_timescale( root
, tfhd
->track_ID
)))
8718 || (root
->max_chunk_size
< (cache
->chunk
.pool_size
+ sample
->length
));
8719 isom_trun_entry_t
*trun
= NULL
;
8720 if( !traf
->trun_list
|| !traf
->trun_list
->entry_count
|| delimit
)
8722 if( delimit
&& traf
->trun_list
&& traf
->trun_list
->entry_count
&& traf
->trun_list
->tail
&& traf
->trun_list
->tail
->data
)
8724 /* Media Data Box preceded by Movie Fragment Box could change base data offsets in each track fragments later.
8725 * We can't consider this here because the length of Movie Fragment Box is unknown at this step yet. */
8726 trun
= (isom_trun_entry_t
*)traf
->trun_list
->tail
->data
;
8727 if( root
->fragment
->pool_size
)
8728 trun
->flags
|= ISOM_TR_FLAGS_DATA_OFFSET_PRESENT
;
8729 trun
->data_offset
= root
->fragment
->pool_size
;
8731 trun
= isom_add_trun( traf
);
8734 if( !cache
->chunk
.pool
)
8736 /* Very initial settings, just once per track */
8737 cache
->chunk
.pool
= lsmash_create_entry_list();
8738 if( !cache
->chunk
.pool
)
8744 if( !traf
->trun_list
->tail
|| !traf
->trun_list
->tail
->data
)
8746 trun
= (isom_trun_entry_t
*)traf
->trun_list
->tail
->data
;
8748 uint32_t sample_composition_time_offset
= sample
->cts
- sample
->dts
;
8749 isom_sample_flags_t sample_flags
= isom_generate_fragment_sample_flags( sample
);
8750 if( ++trun
->sample_count
== 1 )
8752 if( traf
->trun_list
->entry_count
== 1 )
8754 /* This track fragment isn't empty-duration-fragment any more. */
8755 tfhd
->flags
&= ~ISOM_TF_FLAGS_DURATION_IS_EMPTY
;
8756 /* Set up sample_description_index in this track fragment. */
8757 if( sample
->index
!= trex
->default_sample_description_index
)
8758 tfhd
->flags
|= ISOM_TF_FLAGS_SAMPLE_DESCRIPTION_INDEX_PRESENT
;
8759 tfhd
->sample_description_index
= cache
->chunk
.sample_description_index
= sample
->index
;
8760 /* Set up default_sample_size used in this track fragment. */
8761 tfhd
->default_sample_size
= sample
->length
;
8762 /* Set up default_sample_flags used in this track fragment.
8763 * Note: we decide an appropriate default value at the end of this movie fragment. */
8764 tfhd
->default_sample_flags
= sample_flags
;
8765 /* Set up random access information if this sample is random accessible sample.
8766 * We inform only the first sample in each movie fragment. */
8767 if( root
->bs
->stream
!= stdout
&& sample
->prop
.random_access_type
)
8769 isom_tfra_entry_t
*tfra
= isom_get_tfra( root
->mfra
, tfhd
->track_ID
);
8772 tfra
= isom_add_tfra( root
->mfra
);
8775 tfra
->track_ID
= tfhd
->track_ID
;
8779 tfra
->list
= lsmash_create_entry_list();
8783 isom_tfra_location_time_entry_t
*rap
= malloc( sizeof(isom_tfra_location_time_entry_t
) );
8786 rap
->time
= sample
->cts
; /* If this is wrong, blame vague descriptions of 'presentation time' in the spec. */
8787 rap
->moof_offset
= root
->size
; /* We place Movie Fragment Box in the head of each movie fragment. */
8788 rap
->traf_number
= cache
->fragment
->traf_number
;
8789 rap
->trun_number
= traf
->trun_list
->entry_count
;
8790 rap
->sample_number
= trun
->sample_count
;
8791 if( lsmash_add_entry( tfra
->list
, rap
) )
8793 tfra
->number_of_entry
= tfra
->list
->entry_count
;
8795 for( length
= 1; rap
->traf_number
>> (length
* 8); length
++ );
8796 tfra
->length_size_of_traf_num
= LSMASH_MAX( length
- 1, tfra
->length_size_of_traf_num
);
8797 for( length
= 1; rap
->traf_number
>> (length
* 8); length
++ );
8798 tfra
->length_size_of_trun_num
= LSMASH_MAX( length
- 1, tfra
->length_size_of_trun_num
);
8799 for( length
= 1; rap
->sample_number
>> (length
* 8); length
++ );
8800 tfra
->length_size_of_sample_num
= LSMASH_MAX( length
- 1, tfra
->length_size_of_sample_num
);
8803 trun
->first_sample_flags
= sample_flags
;
8804 cache
->chunk
.first_dts
= sample
->dts
;
8806 /* Update the optional rows in the current track run except for sample_duration if needed. */
8807 if( sample
->length
!= tfhd
->default_sample_size
)
8808 trun
->flags
|= ISOM_TR_FLAGS_SAMPLE_SIZE_PRESENT
;
8809 if( memcmp( &sample_flags
, &tfhd
->default_sample_flags
, sizeof(isom_sample_flags_t
) ) )
8810 trun
->flags
|= ISOM_TR_FLAGS_SAMPLE_FLAGS_PRESENT
;
8811 if( sample_composition_time_offset
)
8812 trun
->flags
|= ISOM_TR_FLAGS_SAMPLE_COMPOSITION_TIME_OFFSET_PRESENT
;
8815 isom_trun_optional_row_t
*row
= isom_request_trun_optional_row( trun
, tfhd
, trun
->sample_count
);
8818 row
->sample_size
= sample
->length
;
8819 row
->sample_flags
= sample_flags
;
8820 row
->sample_composition_time_offset
= sample_composition_time_offset
;
8822 /* Set up the previous sample_duration if this sample is not the first sample in the overall movie. */
8823 if( cache
->fragment
->has_samples
)
8825 /* Note: when using for live streaming, it is not good idea to return error (-1) by sample->dts < prev_dts
8826 * since that's trivial for such semi-permanent presentation. */
8827 uint64_t prev_dts
= cache
->timestamp
.dts
;
8828 if( sample
->dts
<= prev_dts
|| sample
->dts
> prev_dts
+ UINT32_MAX
)
8830 uint32_t sample_duration
= sample
->dts
- prev_dts
;
8831 if( isom_update_fragment_previous_sample_duration( traf
, trex
, sample_duration
) )
8834 cache
->timestamp
.dts
= sample
->dts
;
8835 cache
->fragment
->largest_cts
= LSMASH_MAX( sample
->cts
, cache
->fragment
->largest_cts
);
8839 static int isom_append_fragment_sample_internal_initial( isom_trak_entry_t
*trak
, lsmash_sample_t
*sample
)
8842 /* Update the sample tables of this track fragment.
8843 * If a new chunk was created, append the previous one to the pool of this movie fragment. */
8844 delimit
= isom_update_sample_tables( trak
, sample
);
8847 else if( delimit
== 1 )
8848 isom_append_fragment_track_run( trak
->root
, &trak
->cache
->chunk
);
8849 /* Add a new sample into the pool of this track fragment. */
8850 if( lsmash_add_entry( trak
->cache
->chunk
.pool
, sample
) )
8852 trak
->cache
->chunk
.pool_size
+= sample
->length
;
8853 trak
->cache
->fragment
->has_samples
= 1;
8857 static int isom_append_fragment_sample_internal( isom_traf_entry_t
*traf
, lsmash_sample_t
*sample
)
8860 /* Update the sample tables of this track fragment.
8861 * If a new track run was created, append the previous one to the pool of this movie fragment. */
8862 delimit
= isom_update_fragment_sample_tables( traf
, sample
);
8865 else if( delimit
== 1 )
8866 isom_append_fragment_track_run( traf
->root
, &traf
->cache
->chunk
);
8867 /* Add a new sample into the pool of this track fragment. */
8868 if( lsmash_add_entry( traf
->cache
->chunk
.pool
, sample
) )
8870 traf
->cache
->chunk
.pool_size
+= sample
->length
;
8871 traf
->cache
->fragment
->has_samples
= 1;
8875 static int isom_append_fragment_sample( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_sample_t
*sample
)
8877 isom_fragment_manager_t
*fragment
= root
->fragment
;
8878 if( !fragment
|| !fragment
->pool
)
8880 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
8881 if( !trak
|| !trak
->root
|| !trak
->cache
|| !trak
->cache
->fragment
|| !trak
->tkhd
|| !trak
->mdia
8882 || !trak
->mdia
->mdhd
|| !trak
->mdia
->mdhd
->timescale
8883 || !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
8884 || !trak
->mdia
->minf
->stbl
->stsd
|| !trak
->mdia
->minf
->stbl
->stsd
->list
8885 || !trak
->mdia
->minf
->stbl
->stsc
|| !trak
->mdia
->minf
->stbl
->stsc
->list
)
8887 int (*append_sample_func
)( void *, lsmash_sample_t
* ) = NULL
;
8888 void *track_fragment
= NULL
;
8889 if( !fragment
->movie
)
8891 append_sample_func
= (int (*)( void *, lsmash_sample_t
* ))isom_append_fragment_sample_internal_initial
;
8892 track_fragment
= trak
;
8896 isom_traf_entry_t
*traf
= isom_get_traf( fragment
->movie
, track_ID
);
8899 traf
= isom_add_traf( root
, fragment
->movie
);
8900 if( isom_add_tfhd( traf
) )
8902 traf
->tfhd
->flags
= ISOM_TF_FLAGS_DURATION_IS_EMPTY
; /* no samples for this track fragment yet */
8903 traf
->tfhd
->track_ID
= trak
->tkhd
->track_ID
;
8904 traf
->cache
= trak
->cache
;
8905 traf
->cache
->fragment
->traf_number
= fragment
->movie
->traf_list
->entry_count
;
8907 else if( !traf
->root
|| !traf
->root
->moov
|| !traf
->root
->moov
->mvex
|| !traf
->cache
|| !traf
->tfhd
)
8909 append_sample_func
= (int (*)( void *, lsmash_sample_t
* ))isom_append_fragment_sample_internal
;
8910 track_fragment
= traf
;
8912 isom_sample_entry_t
*sample_entry
= (isom_sample_entry_t
*)lsmash_get_entry_data( trak
->mdia
->minf
->stbl
->stsd
->list
, sample
->index
);
8915 if( isom_is_lpcm_audio( sample_entry
->type
) )
8917 uint32_t frame_size
= ((isom_audio_entry_t
*)sample_entry
)->constBytesPerAudioPacket
;
8918 uint64_t dts
= sample
->dts
;
8919 uint64_t cts
= sample
->cts
;
8920 /* Append samples splitted into each LPCMFrame. */
8921 for( uint32_t offset
= 0; offset
< sample
->length
; offset
+= frame_size
)
8923 lsmash_sample_t
*lpcm_sample
= lsmash_create_sample( frame_size
);
8926 memcpy( lpcm_sample
->data
, sample
->data
+ offset
, frame_size
);
8927 lpcm_sample
->dts
= dts
++;
8928 lpcm_sample
->cts
= cts
++;
8929 lpcm_sample
->prop
= sample
->prop
;
8930 lpcm_sample
->index
= sample
->index
;
8931 if( append_sample_func( track_fragment
, lpcm_sample
) )
8933 lsmash_delete_sample( lpcm_sample
);
8937 lsmash_delete_sample( sample
);
8940 return append_sample_func( track_fragment
, sample
);
8943 int lsmash_append_sample( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_sample_t
*sample
)
8945 /* We think max_chunk_duration == 0, which means all samples will be cached on memory, should be prevented.
8946 * This means removal of a feature that we used to have, but anyway very alone chunk does not make sense. */
8947 if( !root
|| !root
->bs
|| !sample
|| !sample
->data
|| !track_ID
8948 || root
->max_chunk_duration
== 0 || root
->max_async_tolerance
== 0 )
8950 /* Write File Type Box here if it was not written yet. */
8951 if( !root
->file_type_written
&& isom_write_ftyp( root
) )
8953 if( root
->fragment
&& root
->fragment
->pool
)
8954 return isom_append_fragment_sample( root
, track_ID
, sample
);
8955 return isom_append_sample( root
, track_ID
, sample
);
8958 /*---- misc functions ----*/
8960 #define CHAPTER_BUFSIZE 512 /* for chapter handling */
8962 static int isom_get_start_time( char *chap_time
, isom_chapter_entry_t
*data
)
8966 if( sscanf( chap_time
, "%"SCNu64
":%2"SCNu64
":%lf", &hh
, &mm
, &ss
) != 3 )
8968 /* check overflow */
8969 if( hh
>= 5124095 || mm
>= 60 || ss
>= 60 )
8972 data
->start_time
= (hh
* 3600 + mm
* 60 + ss
) * 1e9
;
8976 static int isom_lumber_line( char *buff
, int bufsize
, FILE *chapter
)
8979 /* remove newline codes and skip empty line */
8981 if( fgets( buff
, bufsize
, chapter
) == NULL
)
8983 tail
= &buff
[ strlen( buff
) - 1 ];
8984 while( tail
>= buff
&& ( *tail
== '\n' || *tail
== '\r' ) )
8986 }while( tail
< buff
);
8990 static int isom_read_simple_chapter( FILE *chapter
, isom_chapter_entry_t
*data
)
8992 char buff
[CHAPTER_BUFSIZE
];
8995 /* get start_time */
8996 if( isom_lumber_line( buff
, CHAPTER_BUFSIZE
, chapter
) )
8998 char *chapter_time
= strchr( buff
, '=' ); /* find separator */
9000 || isom_get_start_time( chapter_time
, data
)
9001 || isom_lumber_line( buff
, CHAPTER_BUFSIZE
, chapter
) ) /* get chapter_name */
9003 char *chapter_name
= strchr( buff
, '=' ); /* find separator */
9004 if( !chapter_name
++ )
9006 len
= LSMASH_MIN( 255, strlen( chapter_name
) ); /* We support length of chapter_name up to 255 */
9007 data
->chapter_name
= ( char* )malloc( len
+ 1 );
9008 if( !data
->chapter_name
)
9010 memcpy( data
->chapter_name
, chapter_name
, len
);
9011 data
->chapter_name
[len
] = '\0';
9015 static int isom_read_minimum_chapter( FILE *chapter
, isom_chapter_entry_t
*data
)
9017 char buff
[CHAPTER_BUFSIZE
];
9020 if( isom_lumber_line( buff
, CHAPTER_BUFSIZE
, chapter
) /* read newline */
9021 || isom_get_start_time( buff
, data
) ) /* get start_time */
9023 /* get chapter_name */
9024 char *chapter_name
= strchr( buff
, ' ' ); /* find separator */
9025 if( !chapter_name
++ )
9027 len
= LSMASH_MIN( 255, strlen( chapter_name
) ); /* We support length of chapter_name up to 255 */
9028 data
->chapter_name
= ( char* )malloc( len
+ 1 );
9029 if( !data
->chapter_name
)
9031 memcpy( data
->chapter_name
, chapter_name
, len
);
9032 data
->chapter_name
[len
] = '\0';
9036 typedef int (*fn_get_chapter_data
)( FILE *, isom_chapter_entry_t
* );
9038 static fn_get_chapter_data
isom_check_chap_line( char *file_name
)
9040 char buff
[CHAPTER_BUFSIZE
];
9041 FILE *fp
= fopen( file_name
, "rb" );
9044 fn_get_chapter_data fnc
= NULL
;
9045 if( fgets( buff
, CHAPTER_BUFSIZE
, fp
) != NULL
)
9047 if( strncmp( buff
, "CHAPTER", 7 ) == 0 )
9048 fnc
= isom_read_simple_chapter
;
9049 else if( isdigit( buff
[0] ) && isdigit( buff
[1] ) && buff
[2] == ':'
9050 && isdigit( buff
[3] ) && isdigit( buff
[4] ) && buff
[5] == ':' )
9051 fnc
= isom_read_minimum_chapter
;
9057 int lsmash_set_tyrant_chapter( lsmash_root_t
*root
, char *file_name
)
9059 /* This function should be called after updating of the latest movie duration. */
9060 if( !root
|| !root
->moov
|| !root
->moov
->mvhd
|| !root
->moov
->mvhd
->timescale
|| !root
->moov
->mvhd
->duration
)
9062 /* check each line format */
9063 fn_get_chapter_data fnc
= isom_check_chap_line( file_name
);
9066 FILE *chapter
= fopen( file_name
, "rb" );
9069 if( isom_add_udta( root
, 0 ) || isom_add_chpl( root
->moov
) )
9071 isom_chapter_entry_t data
;
9072 while( !fnc( chapter
, &data
) )
9074 data
.start_time
= (data
.start_time
+ 50) / 100; /* convert to 100ns unit */
9075 if( data
.start_time
/ 1e7
> (double)root
->moov
->mvhd
->duration
/ root
->moov
->mvhd
->timescale
9076 || isom_add_chpl_entry( root
->moov
->udta
->chpl
, &data
) )
9078 free( data
.chapter_name
);
9079 data
.chapter_name
= NULL
;
9084 if( data
.chapter_name
)
9085 free( data
.chapter_name
);
9090 int lsmash_create_reference_chapter_track( lsmash_root_t
*root
, uint32_t track_ID
, char *file_name
)
9092 if( !root
|| (!root
->qt_compatible
&& !root
->itunes_audio
) || !root
->moov
|| !root
->moov
->mvhd
)
9094 FILE *chapter
= NULL
; /* shut up 'uninitialized' warning */
9095 /* Create a Track Reference Box. */
9096 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
9097 if( !trak
|| isom_add_tref( trak
) )
9099 /* Create a track_ID for a new chapter track. */
9100 uint32_t *id
= (uint32_t *)malloc( sizeof(uint32_t) );
9103 uint32_t chapter_track_ID
= *id
= root
->moov
->mvhd
->next_track_ID
;
9104 /* Create a Track Reference Type Box. */
9105 isom_tref_type_t
*chap
= isom_add_track_reference_type( trak
->tref
, QT_TREF_TYPE_CHAP
, 1, id
);
9107 return -1; /* no need to free id */
9108 /* Create a reference chapter track. */
9109 if( chapter_track_ID
!= lsmash_create_track( root
, ISOM_MEDIA_HANDLER_TYPE_TEXT_TRACK
) )
9111 /* Set track parameters. */
9112 lsmash_track_parameters_t track_param
;
9113 lsmash_initialize_track_parameters( &track_param
);
9114 track_param
.mode
= ISOM_TRACK_IN_MOVIE
| ISOM_TRACK_IN_PREVIEW
;
9115 if( lsmash_set_track_parameters( root
, chapter_track_ID
, &track_param
) )
9117 /* Set media parameters. */
9118 uint64_t media_timescale
= lsmash_get_media_timescale( root
, track_ID
);
9119 if( !media_timescale
)
9121 lsmash_media_parameters_t media_param
;
9122 lsmash_initialize_media_parameters( &media_param
);
9123 media_param
.timescale
= media_timescale
;
9124 media_param
.ISO_language
= root
->max_3gpp_version
>= 6 || root
->itunes_audio
? "und" : NULL
;
9125 media_param
.MAC_language
= 0;
9126 if( lsmash_set_media_parameters( root
, chapter_track_ID
, &media_param
) )
9128 /* Create a sample description. */
9129 uint32_t sample_type
= root
->max_3gpp_version
>= 6 || root
->itunes_audio
? ISOM_CODEC_TYPE_TX3G_TEXT
: QT_CODEC_TYPE_TEXT_TEXT
;
9130 uint32_t sample_entry
= lsmash_add_sample_entry( root
, chapter_track_ID
, sample_type
, NULL
);
9133 /* Check each line format. */
9134 fn_get_chapter_data fnc
= isom_check_chap_line( file_name
);
9137 /* Open chapter format file. */
9138 chapter
= fopen( file_name
, "rb" );
9141 /* Parse the file and write text samples. */
9142 isom_chapter_entry_t data
;
9143 while( !fnc( chapter
, &data
) )
9145 /* set start_time */
9146 data
.start_time
= data
.start_time
* 1e-9 * media_timescale
+ 0.5;
9147 /* write a text sample here */
9148 uint16_t name_length
= strlen( data
.chapter_name
);
9149 lsmash_sample_t
*sample
= lsmash_create_sample( 2 + name_length
+ 12 * (sample_type
== QT_CODEC_TYPE_TEXT_TEXT
) );
9152 sample
->data
[0] = (name_length
>> 8) & 0xff;
9153 sample
->data
[1] = name_length
& 0xff;
9154 memcpy( sample
->data
+ 2, data
.chapter_name
, name_length
);
9155 if( sample_type
== QT_CODEC_TYPE_TEXT_TEXT
)
9157 /* QuickTime Player requires Text Encoding Attribute Box ('encd') if media language is ISO language codes : undefined.
9158 * Also this box can avoid garbling if the QuickTime text sample is encoded by Unicode characters.
9159 * Note: 3GPP Timed Text supports only UTF-8 or UTF-16, so this box isn't needed. */
9160 static const uint8_t encd
[12] =
9162 0x00, 0x00, 0x00, 0x0C, /* size: 12 */
9163 0x65, 0x6E, 0x63, 0x64, /* type: 'encd' */
9164 0x00, 0x00, 0x01, 0x00 /* Unicode Encoding */
9166 memcpy( sample
->data
+ 2 + name_length
, encd
, 12 );
9168 sample
->dts
= sample
->cts
= data
.start_time
;
9169 sample
->prop
.random_access_type
= ISOM_SAMPLE_RANDOM_ACCESS_TYPE_SYNC
;
9170 sample
->index
= sample_entry
;
9171 if( lsmash_append_sample( root
, chapter_track_ID
, sample
) )
9173 free( data
.chapter_name
);
9174 data
.chapter_name
= NULL
;
9176 if( lsmash_flush_pooled_samples( root
, chapter_track_ID
, 0 ) )
9178 trak
= isom_get_trak( root
, chapter_track_ID
);
9182 trak
->is_chapter
= 1;
9183 trak
->related_track_ID
= track_ID
;
9188 if( data
.chapter_name
)
9189 free( data
.chapter_name
);
9190 free( chap
->track_ID
);
9191 chap
->track_ID
= NULL
;
9192 /* Remove the reference chapter track attached at tail of the list. */
9193 lsmash_remove_entry_direct( root
->moov
->trak_list
, root
->moov
->trak_list
->tail
, isom_remove_trak
);
9197 void lsmash_delete_explicit_timeline_map( lsmash_root_t
*root
, uint32_t track_ID
)
9199 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
9202 isom_remove_edts( trak
->edts
);
9206 void lsmash_delete_tyrant_chapter( lsmash_root_t
*root
)
9208 if( !root
|| !root
->moov
|| !root
->moov
->udta
)
9210 isom_remove_chpl( root
->moov
->udta
->chpl
);
9211 root
->moov
->udta
->chpl
= NULL
;