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
[] = {
91 for( int i
= 0; i
< sizeof(fullbox_table
)/sizeof(uint32_t); i
++ )
92 if( type
== fullbox_table
[i
] )
97 /* Return 1 if the sample type is LPCM audio, Otherwise return 0. */
98 int isom_is_lpcm_audio( uint32_t type
)
100 return type
== QT_CODEC_TYPE_23NI_AUDIO
101 || type
== QT_CODEC_TYPE_NONE_AUDIO
102 || type
== QT_CODEC_TYPE_LPCM_AUDIO
103 || type
== QT_CODEC_TYPE_RAW_AUDIO
104 || type
== QT_CODEC_TYPE_SOWT_AUDIO
105 || type
== QT_CODEC_TYPE_TWOS_AUDIO
106 || type
== QT_CODEC_TYPE_FL32_AUDIO
107 || type
== QT_CODEC_TYPE_FL64_AUDIO
108 || type
== QT_CODEC_TYPE_IN24_AUDIO
109 || type
== QT_CODEC_TYPE_IN32_AUDIO
110 || type
== QT_CODEC_TYPE_NOT_SPECIFIED
;
113 char *isom_4cc2str( uint32_t fourcc
)
116 str
[0] = (fourcc
>> 24) & 0xff;
117 str
[1] = (fourcc
>> 16) & 0xff;
118 str
[2] = (fourcc
>> 8) & 0xff;
119 str
[3] = fourcc
& 0xff;
124 static inline void isom_init_basebox_common( isom_box_t
*box
, isom_box_t
*parent
, uint32_t type
)
126 box
->root
= parent
->root
;
127 box
->parent
= parent
;
130 box
->usertype
= NULL
;
133 static inline void isom_init_fullbox_common( isom_box_t
*box
, isom_box_t
*parent
, uint32_t type
)
135 box
->root
= parent
->root
;
136 box
->parent
= parent
;
139 box
->usertype
= NULL
;
144 void isom_init_box_common( void *box
, void *parent
, uint32_t type
)
146 assert( parent
&& ((isom_box_t
*)parent
)->root
);
147 if( ((isom_box_t
*)parent
)->type
== ISOM_BOX_TYPE_STSD
)
149 isom_init_basebox_common( (isom_box_t
*)box
, (isom_box_t
*)parent
, type
);
152 if( isom_is_fullbox( box
) )
153 isom_init_fullbox_common( (isom_box_t
*)box
, (isom_box_t
*)parent
, type
);
155 isom_init_basebox_common( (isom_box_t
*)box
, (isom_box_t
*)parent
, type
);
158 static void isom_bs_put_basebox_common( lsmash_bs_t
*bs
, isom_box_t
*box
)
160 if( box
->size
> UINT32_MAX
)
162 lsmash_bs_put_be32( bs
, 1 );
163 lsmash_bs_put_be32( bs
, box
->type
);
164 lsmash_bs_put_be64( bs
, box
->size
); /* largesize */
168 lsmash_bs_put_be32( bs
, (uint32_t)box
->size
);
169 lsmash_bs_put_be32( bs
, box
->type
);
171 if( box
->type
== ISOM_BOX_TYPE_UUID
)
172 lsmash_bs_put_bytes( bs
, box
->usertype
, 16 );
175 static void isom_bs_put_fullbox_common( lsmash_bs_t
*bs
, isom_box_t
*box
)
177 isom_bs_put_basebox_common( bs
, box
);
178 lsmash_bs_put_byte( bs
, box
->version
);
179 lsmash_bs_put_be24( bs
, box
->flags
);
182 static void isom_bs_put_box_common( lsmash_bs_t
*bs
, void *box
)
189 isom_box_t
*parent
= ((isom_box_t
*)box
)->parent
;
190 if( parent
&& parent
->type
== ISOM_BOX_TYPE_STSD
)
192 isom_bs_put_basebox_common( bs
, (isom_box_t
*)box
);
195 if( isom_is_fullbox( box
) )
196 isom_bs_put_fullbox_common( bs
, (isom_box_t
*)box
);
198 isom_bs_put_basebox_common( bs
, (isom_box_t
*)box
);
201 isom_trak_entry_t
*isom_get_trak( lsmash_root_t
*root
, uint32_t track_ID
)
203 if( !track_ID
|| !root
|| !root
->moov
|| !root
->moov
->trak_list
)
205 for( lsmash_entry_t
*entry
= root
->moov
->trak_list
->head
; entry
; entry
= entry
->next
)
207 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)entry
->data
;
208 if( !trak
|| !trak
->tkhd
)
210 if( trak
->tkhd
->track_ID
== track_ID
)
216 static isom_trex_entry_t
*isom_get_trex( isom_mvex_t
*mvex
, uint32_t track_ID
)
218 if( !track_ID
|| !mvex
|| !mvex
->trex_list
)
220 for( lsmash_entry_t
*entry
= mvex
->trex_list
->head
; entry
; entry
= entry
->next
)
222 isom_trex_entry_t
*trex
= (isom_trex_entry_t
*)entry
->data
;
225 if( trex
->track_ID
== track_ID
)
231 static isom_traf_entry_t
*isom_get_traf( isom_moof_entry_t
*moof
, uint32_t track_ID
)
233 if( !track_ID
|| !moof
|| !moof
->traf_list
)
235 for( lsmash_entry_t
*entry
= moof
->traf_list
->head
; entry
; entry
= entry
->next
)
237 isom_traf_entry_t
*traf
= (isom_traf_entry_t
*)entry
->data
;
238 if( !traf
|| !traf
->tfhd
)
240 if( traf
->tfhd
->track_ID
== track_ID
)
246 static isom_tfra_entry_t
*isom_get_tfra( isom_mfra_t
*mfra
, uint32_t track_ID
)
248 if( !track_ID
|| !mfra
|| !mfra
->tfra_list
)
250 for( lsmash_entry_t
*entry
= mfra
->tfra_list
->head
; entry
; entry
= entry
->next
)
252 isom_tfra_entry_t
*tfra
= (isom_tfra_entry_t
*)entry
->data
;
255 if( tfra
->track_ID
== track_ID
)
261 static int isom_add_elst_entry( isom_elst_t
*elst
, uint64_t segment_duration
, int64_t media_time
, int32_t media_rate
)
263 isom_elst_entry_t
*data
= malloc( sizeof(isom_elst_entry_t
) );
266 data
->segment_duration
= segment_duration
;
267 data
->media_time
= media_time
;
268 data
->media_rate
= media_rate
;
269 if( lsmash_add_entry( elst
->list
, data
) )
274 if( data
->segment_duration
> UINT32_MAX
|| data
->media_time
> INT32_MAX
|| data
->media_time
< INT32_MIN
)
279 static isom_tref_type_t
*isom_add_track_reference_type( isom_tref_t
*tref
, isom_track_reference_type type
, uint32_t ref_count
, uint32_t *track_ID
)
281 if( !tref
|| !tref
->ref_list
)
283 isom_tref_type_t
*ref
= malloc( sizeof(isom_tref_type_t
) );
286 isom_init_box_common( ref
, tref
, type
);
287 ref
->ref_count
= ref_count
;
288 ref
->track_ID
= track_ID
;
289 if( lsmash_add_entry( tref
->ref_list
, ref
) )
297 static int isom_add_dref_entry( isom_dref_t
*dref
, uint32_t flags
, char *name
, char *location
)
299 if( !dref
|| !dref
->list
)
301 isom_dref_entry_t
*data
= malloc( sizeof(isom_dref_entry_t
) );
304 memset( data
, 0, sizeof(isom_dref_entry_t
) );
305 isom_init_box_common( data
, dref
, name
? ISOM_BOX_TYPE_URN
: ISOM_BOX_TYPE_URL
);
309 data
->location_length
= strlen( location
) + 1;
310 data
->location
= malloc( data
->location_length
);
311 if( !data
->location
)
316 memcpy( data
->location
, location
, data
->location_length
);
320 data
->name_length
= strlen( name
) + 1;
321 data
->name
= malloc( data
->name_length
);
325 free( data
->location
);
329 memcpy( data
->name
, name
, data
->name_length
);
331 if( lsmash_add_entry( dref
->list
, data
) )
334 free( data
->location
);
343 isom_avcC_ps_entry_t
*isom_create_ps_entry( uint8_t *ps
, uint32_t ps_size
)
345 isom_avcC_ps_entry_t
*entry
= malloc( sizeof(isom_avcC_ps_entry_t
) );
348 entry
->parameterSetLength
= ps_size
;
349 entry
->parameterSetNALUnit
= malloc( ps_size
);
350 if( !entry
->parameterSetNALUnit
)
355 memcpy( entry
->parameterSetNALUnit
, ps
, ps_size
);
359 void isom_remove_avcC_ps( isom_avcC_ps_entry_t
*ps
)
363 if( ps
->parameterSetNALUnit
)
364 free( ps
->parameterSetNALUnit
);
368 int lsmash_add_sps_entry( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t entry_number
, uint8_t *sps
, uint32_t sps_size
)
370 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
371 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
|| !trak
->mdia
->minf
->stbl
->stsd
|| !trak
->mdia
->minf
->stbl
->stsd
->list
)
373 isom_visual_entry_t
*data
= (isom_visual_entry_t
*)lsmash_get_entry_data( trak
->mdia
->minf
->stbl
->stsd
->list
, entry_number
);
374 if( !data
|| !data
->avcC
)
376 isom_avcC_t
*avcC
= (isom_avcC_t
*)data
->avcC
;
377 isom_avcC_ps_entry_t
*ps
= isom_create_ps_entry( sps
, sps_size
);
380 if( lsmash_add_entry( avcC
->sequenceParameterSets
, ps
) )
382 isom_remove_avcC_ps( ps
);
385 avcC
->numOfSequenceParameterSets
= avcC
->sequenceParameterSets
->entry_count
;
389 int lsmash_add_pps_entry( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t entry_number
, uint8_t *pps
, uint32_t pps_size
)
391 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
392 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
|| !trak
->mdia
->minf
->stbl
->stsd
|| !trak
->mdia
->minf
->stbl
->stsd
->list
)
394 isom_visual_entry_t
*data
= (isom_visual_entry_t
*)lsmash_get_entry_data( trak
->mdia
->minf
->stbl
->stsd
->list
, entry_number
);
395 if( !data
|| !data
->avcC
)
397 isom_avcC_t
*avcC
= (isom_avcC_t
*)data
->avcC
;
398 isom_avcC_ps_entry_t
*ps
= isom_create_ps_entry( pps
, pps_size
);
401 if( lsmash_add_entry( avcC
->pictureParameterSets
, ps
) )
403 isom_remove_avcC_ps( ps
);
406 avcC
->numOfPictureParameterSets
= avcC
->pictureParameterSets
->entry_count
;
410 int lsmash_add_spsext_entry( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t entry_number
, uint8_t *spsext
, uint32_t spsext_size
)
412 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
413 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
|| !trak
->mdia
->minf
->stbl
->stsd
|| !trak
->mdia
->minf
->stbl
->stsd
->list
)
415 isom_visual_entry_t
*data
= (isom_visual_entry_t
*)lsmash_get_entry_data( trak
->mdia
->minf
->stbl
->stsd
->list
, entry_number
);
416 if( !data
|| !data
->avcC
)
418 isom_avcC_t
*avcC
= (isom_avcC_t
*)data
->avcC
;
419 isom_avcC_ps_entry_t
*ps
= isom_create_ps_entry( spsext
, spsext_size
);
422 if( lsmash_add_entry( avcC
->sequenceParameterSetExt
, ps
) )
424 isom_remove_avcC_ps( ps
);
427 avcC
->numOfSequenceParameterSetExt
= avcC
->sequenceParameterSetExt
->entry_count
;
431 int isom_add_avcC( isom_visual_entry_t
*visual
)
435 isom_create_box( avcC
, visual
, ISOM_BOX_TYPE_AVCC
);
436 avcC
->sequenceParameterSets
= lsmash_create_entry_list();
437 if( !avcC
->sequenceParameterSets
)
442 avcC
->pictureParameterSets
= lsmash_create_entry_list();
443 if( !avcC
->pictureParameterSets
)
445 isom_remove_avcC( avcC
);
448 avcC
->sequenceParameterSetExt
= lsmash_create_entry_list();
449 if( !avcC
->sequenceParameterSetExt
)
451 isom_remove_avcC( avcC
);
458 int isom_add_clap( isom_visual_entry_t
*visual
)
460 if( !visual
|| visual
->clap
)
462 isom_create_box( clap
, visual
, ISOM_BOX_TYPE_CLAP
);
463 clap
->cleanApertureWidthN
= 1;
464 clap
->cleanApertureWidthD
= 1;
465 clap
->cleanApertureHeightN
= 1;
466 clap
->cleanApertureHeightD
= 1;
475 int isom_add_pasp( isom_visual_entry_t
*visual
)
477 if( !visual
|| visual
->pasp
)
479 isom_create_box( pasp
, visual
, ISOM_BOX_TYPE_PASP
);
486 int isom_add_colr( isom_visual_entry_t
*visual
)
488 if( !visual
|| visual
->colr
)
490 isom_create_box( colr
, visual
, QT_BOX_TYPE_COLR
);
491 isom_color_parameter_t
*param
= (isom_color_parameter_t
*)(&isom_color_parameter_tbl
[0]);
492 colr
->color_parameter_type
= QT_COLOR_PARAMETER_TYPE_NCLC
;
493 colr
->primaries_index
= param
->primaries
;
494 colr
->transfer_function_index
= param
->transfer
;
495 colr
->matrix_index
= param
->matrix
;
500 int isom_add_stsl( isom_visual_entry_t
*visual
)
502 if( !visual
|| visual
->stsl
)
504 isom_create_box( stsl
, visual
, ISOM_BOX_TYPE_STSL
);
505 stsl
->scale_method
= ISOM_SCALING_METHOD_HIDDEN
;
510 static void isom_remove_esds( isom_esds_t
*esds
);
511 static void isom_remove_visual_extensions( isom_visual_entry_t
*visual
);
513 static int isom_add_visual_extensions( isom_visual_entry_t
*visual
, lsmash_video_summary_t
*summary
)
515 /* Check if set up Track Aperture Modes. */
516 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)visual
->parent
->parent
->parent
->parent
->parent
;
517 int qt_compatible
= trak
->root
->qt_compatible
;
518 isom_tapt_t
*tapt
= trak
->tapt
;
519 int set_aperture_modes
= qt_compatible
/* Track Aperture Modes is only available under QuickTime file format. */
520 && !summary
->scaling_method
/* Sample scaling method might conflict with this feature. */
521 && tapt
&& tapt
->clef
&& tapt
->prof
&& tapt
->enof
/* Check if required boxes exist. */
522 && !((isom_stsd_t
*)visual
->parent
)->list
->entry_count
; /* Multiple sample description might conflict with this, so in that case, disable this feature.
523 * Note: this sample description isn't added yet here. */
524 if( !set_aperture_modes
)
525 isom_remove_tapt( trak
->tapt
);
526 /* Set up Clean Aperture. */
527 if( set_aperture_modes
|| summary
->crop_top
|| summary
->crop_left
|| summary
->crop_bottom
|| summary
->crop_right
)
529 if( isom_add_clap( visual
) )
531 isom_remove_visual_extensions( visual
);
534 isom_clap_t
*clap
= visual
->clap
;
535 clap
->cleanApertureWidthN
= summary
->width
- (summary
->crop_left
+ summary
->crop_right
);
536 clap
->cleanApertureHeightN
= summary
->height
- (summary
->crop_top
+ summary
->crop_bottom
);
537 clap
->horizOffN
= (int64_t)summary
->crop_left
- summary
->crop_right
;
538 clap
->vertOffN
= (int64_t)summary
->crop_top
- summary
->crop_bottom
;
539 if( !(clap
->horizOffN
& 0x1) )
541 clap
->horizOffN
/= 2;
546 if( !(clap
->vertOffN
& 0x1) )
554 /* Set up Pixel Aspect Ratio. */
555 if( set_aperture_modes
|| (summary
->par_h
&& summary
->par_v
) )
557 if( isom_add_pasp( visual
) )
559 isom_remove_visual_extensions( visual
);
562 isom_pasp_t
*pasp
= visual
->pasp
;
563 pasp
->hSpacing
= summary
->par_h
;
564 pasp
->vSpacing
= summary
->par_v
;
566 /* Set up Color Parameter. */
567 if( qt_compatible
&& (summary
->primaries
|| summary
->transfer
|| summary
->matrix
) )
569 if( isom_add_colr( visual
) )
571 isom_remove_visual_extensions( visual
);
574 isom_colr_t
*colr
= visual
->colr
;
575 uint16_t primaries
= summary
->primaries
;
576 uint16_t transfer
= summary
->transfer
;
577 uint16_t matrix
= summary
->matrix
;
578 /* Set 'nclc' to parameter type, we don't support 'prof'. */
579 colr
->color_parameter_type
= QT_COLOR_PARAMETER_TYPE_NCLC
;
581 if( primaries
>= QT_COLOR_PARAMETER_END
)
583 else if( primaries
> UINT16_MAX
)
584 colr
->primaries_index
= isom_color_parameter_tbl
[primaries
- UINT16_MAX_PLUS_ONE
].primaries
;
586 colr
->primaries_index
= (primaries
== 1 || primaries
== 5 || primaries
== 6) ? primaries
: 2;
588 if( transfer
>= QT_COLOR_PARAMETER_END
)
590 else if( transfer
> UINT16_MAX
)
591 colr
->transfer_function_index
= isom_color_parameter_tbl
[transfer
- UINT16_MAX_PLUS_ONE
].transfer
;
593 colr
->transfer_function_index
= (transfer
== 1 || transfer
== 7) ? transfer
: 2;
595 if( matrix
>= QT_COLOR_PARAMETER_END
)
597 else if( matrix
> UINT16_MAX
)
598 colr
->matrix_index
= isom_color_parameter_tbl
[matrix
- UINT16_MAX_PLUS_ONE
].matrix
;
600 colr
->matrix_index
= (matrix
== 1 || matrix
== 6 || matrix
== 7 ) ? matrix
: 2;
602 /* Set up Sample Scaling. */
603 if( !qt_compatible
&& summary
->scaling_method
)
605 if( isom_add_stsl( visual
) )
607 isom_remove_visual_extensions( visual
);
610 isom_stsl_t
*stsl
= visual
->stsl
;
611 stsl
->constraint_flag
= 1;
612 stsl
->scale_method
= summary
->scaling_method
;
614 /* Set up AVC Decoder Configuration. */
615 static const uint32_t avc_type
[] =
617 ISOM_CODEC_TYPE_AVC1_VIDEO
,
618 ISOM_CODEC_TYPE_AVC2_VIDEO
,
619 ISOM_CODEC_TYPE_AVCP_VIDEO
621 for( int i
= 0; i
< sizeof(avc_type
)/sizeof(avc_type
[0]); i
++ )
622 if( visual
->type
== avc_type
[i
] )
624 if( isom_add_avcC( visual
) )
628 /* Set up Track Apeture Modes. */
629 if( set_aperture_modes
)
631 uint32_t width
= visual
->width
<< 16;
632 uint32_t height
= visual
->height
<< 16;
633 double clap_width
= ((double)visual
->clap
->cleanApertureWidthN
/ visual
->clap
->cleanApertureWidthD
) * (1<<16);
634 double clap_height
= ((double)visual
->clap
->cleanApertureHeightN
/ visual
->clap
->cleanApertureHeightD
) * (1<<16);
635 double par
= (double)visual
->pasp
->hSpacing
/ visual
->pasp
->vSpacing
;
638 tapt
->clef
->width
= clap_width
* par
;
639 tapt
->clef
->height
= clap_height
;
640 tapt
->prof
->width
= width
* par
;
641 tapt
->prof
->height
= height
;
645 tapt
->clef
->width
= clap_width
;
646 tapt
->clef
->height
= clap_height
/ par
;
647 tapt
->prof
->width
= width
;
648 tapt
->prof
->height
= height
/ par
;
650 tapt
->enof
->width
= width
;
651 tapt
->enof
->height
= height
;
656 static int isom_add_visual_entry( isom_stsd_t
*stsd
, uint32_t sample_type
, lsmash_video_summary_t
*summary
)
658 if( !stsd
|| !stsd
->list
|| !summary
)
660 lsmash_entry_list_t
*list
= stsd
->list
;
661 isom_visual_entry_t
*visual
= malloc( sizeof(isom_visual_entry_t
) );
664 memset( visual
, 0, sizeof(isom_visual_entry_t
) );
665 isom_init_box_common( visual
, stsd
, sample_type
);
666 visual
->data_reference_index
= 1;
667 visual
->width
= (uint16_t)summary
->width
;
668 visual
->height
= (uint16_t)summary
->height
;
669 visual
->horizresolution
= visual
->vertresolution
= 0x00480000;
670 visual
->frame_count
= 1;
671 switch( sample_type
)
673 case ISOM_CODEC_TYPE_AVC1_VIDEO
:
674 case ISOM_CODEC_TYPE_AVC2_VIDEO
:
675 strcpy( visual
->compressorname
, "\012AVC Coding" );
677 case ISOM_CODEC_TYPE_AVCP_VIDEO
:
678 strcpy( visual
->compressorname
, "\016AVC Parameters" );
683 visual
->depth
= 0x0018;
684 visual
->color_table_ID
= -1;
685 if( isom_add_visual_extensions( visual
, summary
)
686 || lsmash_add_entry( list
, visual
) )
688 isom_remove_visual_extensions( visual
);
696 static int isom_add_mp4s_entry( isom_stsd_t
*stsd
)
698 if( !stsd
|| !stsd
->list
)
700 isom_mp4s_entry_t
*mp4s
= malloc( sizeof(isom_mp4s_entry_t
) );
703 memset( mp4s
, 0, sizeof(isom_mp4s_entry_t
) );
704 isom_init_box_common( mp4s
, stsd
, ISOM_CODEC_TYPE_MP4S_SYSTEM
);
705 mp4s
->data_reference_index
= 1;
706 if( lsmash_add_entry( stsd
->list
, mp4s
) )
715 int isom_add_wave( isom_audio_entry_t
*audio
)
717 if( !audio
|| audio
->wave
)
719 isom_create_box( wave
, audio
, QT_BOX_TYPE_WAVE
);
724 int isom_add_frma( isom_wave_t
*wave
)
726 if( !wave
|| wave
->frma
)
728 isom_create_box( frma
, wave
, QT_BOX_TYPE_FRMA
);
733 int isom_add_enda( isom_wave_t
*wave
)
735 if( !wave
|| wave
->enda
)
737 isom_create_box( enda
, wave
, QT_BOX_TYPE_ENDA
);
742 int isom_add_mp4a( isom_wave_t
*wave
)
744 if( !wave
|| wave
->mp4a
)
746 isom_create_box( mp4a
, wave
, QT_BOX_TYPE_MP4A
);
751 int isom_add_terminator( isom_wave_t
*wave
)
753 if( !wave
|| wave
->terminator
)
755 isom_create_box( terminator
, wave
, QT_BOX_TYPE_TERMINATOR
);
756 wave
->terminator
= terminator
;
760 int isom_add_chan( isom_audio_entry_t
*audio
)
762 if( !audio
|| audio
->chan
)
764 isom_create_box( chan
, audio
, QT_BOX_TYPE_CHAN
);
765 chan
->channelLayoutTag
= QT_CHANNEL_LAYOUT_UNKNOWN
;
770 static int isom_set_qtff_mp4a_description( isom_audio_entry_t
*audio
)
772 lsmash_audio_summary_t
*summary
= &audio
->summary
;
773 if( isom_add_wave( audio
)
774 || isom_add_frma( audio
->wave
)
775 || isom_add_mp4a( audio
->wave
)
776 || isom_add_terminator( audio
->wave
) )
778 audio
->data_reference_index
= 1;
779 audio
->version
= (summary
->channels
> 2 || summary
->frequency
> UINT16_MAX
) ? 2 : 1;
780 audio
->channelcount
= audio
->version
== 2 ? 3 : LSMASH_MIN( summary
->channels
, 2 );
781 audio
->samplesize
= 16;
782 audio
->compression_ID
= QT_COMPRESSION_ID_VARIABLE_COMPRESSION
;
783 audio
->packet_size
= 0;
784 if( audio
->version
== 1 )
786 audio
->samplerate
= summary
->frequency
<< 16;
787 audio
->samplesPerPacket
= summary
->samples_in_frame
;
788 audio
->bytesPerPacket
= 1; /* Apparently, this field is set to 1. */
789 audio
->bytesPerFrame
= audio
->bytesPerPacket
* summary
->channels
;
790 audio
->bytesPerSample
= 1 + (summary
->bit_depth
!= 8);
792 else /* audio->version == 2 */
794 audio
->samplerate
= 0x00010000;
795 audio
->sizeOfStructOnly
= 72;
796 audio
->audioSampleRate
= (union {double d
; uint64_t i
;}){summary
->frequency
}.i
;
797 audio
->numAudioChannels
= summary
->channels
;
798 audio
->always7F000000
= 0x7F000000;
799 audio
->constBitsPerChannel
= 0; /* compressed audio */
800 audio
->formatSpecificFlags
= 0;
801 audio
->constBytesPerAudioPacket
= 0; /* variable */
802 audio
->constLPCMFramesPerAudioPacket
= summary
->samples_in_frame
;
804 audio
->wave
->frma
->data_format
= audio
->type
;
805 /* create ES Descriptor */
806 isom_esds_t
*esds
= malloc( sizeof(isom_esds_t
) );
809 memset( esds
, 0, sizeof(isom_esds_t
) );
810 isom_init_box_common( esds
, audio
->wave
, ISOM_BOX_TYPE_ESDS
);
811 mp4sys_ES_Descriptor_params_t esd_param
;
812 memset( &esd_param
, 0, sizeof(mp4sys_ES_Descriptor_params_t
) );
813 esd_param
.objectTypeIndication
= summary
->object_type_indication
;
814 esd_param
.streamType
= summary
->stream_type
;
815 esd_param
.dsi_payload
= summary
->exdata
;
816 esd_param
.dsi_payload_length
= summary
->exdata_length
;
817 esds
->ES
= mp4sys_setup_ES_Descriptor( &esd_param
);
820 audio
->wave
->esds
= esds
;
824 static int isom_set_isom_mp4a_description( isom_audio_entry_t
*audio
)
826 lsmash_audio_summary_t
*summary
= &audio
->summary
;
827 if( summary
->stream_type
!= MP4SYS_STREAM_TYPE_AudioStream
)
829 switch( summary
->object_type_indication
)
831 case MP4SYS_OBJECT_TYPE_Audio_ISO_14496_3
:
832 case MP4SYS_OBJECT_TYPE_Audio_ISO_13818_7_Main_Profile
:
833 case MP4SYS_OBJECT_TYPE_Audio_ISO_13818_7_LC_Profile
:
834 case MP4SYS_OBJECT_TYPE_Audio_ISO_13818_7_SSR_Profile
:
835 case MP4SYS_OBJECT_TYPE_Audio_ISO_13818_3
: /* Legacy Interface */
836 case MP4SYS_OBJECT_TYPE_Audio_ISO_11172_3
: /* Legacy Interface */
841 isom_create_box( esds
, audio
, ISOM_BOX_TYPE_ESDS
);
842 mp4sys_ES_Descriptor_params_t esd_param
;
843 esd_param
.ES_ID
= 0; /* This is esds internal, so 0 is allowed. */
844 esd_param
.objectTypeIndication
= summary
->object_type_indication
;
845 esd_param
.streamType
= summary
->stream_type
;
846 esd_param
.bufferSizeDB
= 0; /* NOTE: ISO/IEC 14496-3 does not mention this, so we use 0. */
847 esd_param
.maxBitrate
= 0; /* This will be updated later if needed. or... I think this can be arbitrary value. */
848 esd_param
.avgBitrate
= 0; /* FIXME: 0 if VBR. */
849 esd_param
.dsi_payload
= summary
->exdata
;
850 esd_param
.dsi_payload_length
= summary
->exdata_length
;
851 esds
->ES
= mp4sys_setup_ES_Descriptor( &esd_param
);
854 audio
->data_reference_index
= 1;
855 /* WARNING: This field cannot retain frequency above 65535Hz.
856 This is not "FIXME", I just honestly implemented what the spec says.
857 BTW, who ever expects sampling frequency takes fixed-point decimal??? */
858 audio
->samplerate
= summary
->frequency
<= UINT16_MAX
? summary
->frequency
<< 16 : 0;
859 /* In pure mp4 file, these "template" fields shall be default values according to the spec.
860 But not pure - hybrid with other spec - mp4 file can take other values.
861 Which is to say, these template values shall be ignored in terms of mp4, except some object_type_indications.
862 see 14496-14, "Template fields used". */
863 audio
->channelcount
= 2;
864 audio
->samplesize
= 16;
869 static int isom_set_qtff_lpcm_description( isom_audio_entry_t
*audio
)
871 uint32_t sample_type
= audio
->type
;
872 lsmash_audio_summary_t
*summary
= &audio
->summary
;
873 /* Convert the sample type into 'lpcm' if the description doesn't match the format or version = 2 fields are needed. */
874 if( (sample_type
== QT_CODEC_TYPE_RAW_AUDIO
&& (summary
->bit_depth
!= 8 || summary
->sample_format
))
875 || (sample_type
== QT_CODEC_TYPE_FL32_AUDIO
&& (summary
->bit_depth
!= 32 || !summary
->sample_format
))
876 || (sample_type
== QT_CODEC_TYPE_FL64_AUDIO
&& (summary
->bit_depth
!= 64 || !summary
->sample_format
))
877 || (sample_type
== QT_CODEC_TYPE_IN24_AUDIO
&& (summary
->bit_depth
!= 24 || summary
->sample_format
))
878 || (sample_type
== QT_CODEC_TYPE_IN32_AUDIO
&& (summary
->bit_depth
!= 32 || summary
->sample_format
))
879 || (sample_type
== QT_CODEC_TYPE_23NI_AUDIO
&& (summary
->bit_depth
!= 32 || summary
->sample_format
|| !summary
->endianness
))
880 || (sample_type
== QT_CODEC_TYPE_SOWT_AUDIO
&& (summary
->bit_depth
!= 16 || summary
->sample_format
|| !summary
->endianness
))
881 || (sample_type
== QT_CODEC_TYPE_TWOS_AUDIO
&& ((summary
->bit_depth
!= 16 && summary
->bit_depth
!= 8) || summary
->sample_format
|| summary
->endianness
))
882 || (sample_type
== QT_CODEC_TYPE_NONE_AUDIO
&& ((summary
->bit_depth
!= 16 && summary
->bit_depth
!= 8) || summary
->sample_format
|| summary
->endianness
))
883 || (sample_type
== QT_CODEC_TYPE_NOT_SPECIFIED
&& ((summary
->bit_depth
!= 16 && summary
->bit_depth
!= 8) || summary
->sample_format
|| summary
->endianness
))
884 || (summary
->channels
> 2 || summary
->frequency
> UINT16_MAX
|| summary
->bit_depth
% 8) )
886 audio
->type
= QT_CODEC_TYPE_LPCM_AUDIO
;
889 else if( sample_type
== QT_CODEC_TYPE_LPCM_AUDIO
)
891 else if( summary
->bit_depth
> 16
892 || (sample_type
!= QT_CODEC_TYPE_RAW_AUDIO
&& sample_type
!= QT_CODEC_TYPE_TWOS_AUDIO
893 && sample_type
!= QT_CODEC_TYPE_NONE_AUDIO
&& sample_type
!= QT_CODEC_TYPE_NOT_SPECIFIED
) )
895 audio
->data_reference_index
= 1;
896 /* Set up constBytesPerAudioPacket field.
897 * We use constBytesPerAudioPacket as the actual size of audio frame even when version is not 2. */
898 audio
->constBytesPerAudioPacket
= (summary
->bit_depth
* summary
->channels
) / 8;
899 /* Set up other fields in this description by its version. */
900 if( audio
->version
== 2 )
902 audio
->channelcount
= 3;
903 audio
->samplesize
= 16;
904 audio
->compression_ID
= -2;
905 audio
->samplerate
= 0x00010000;
906 audio
->sizeOfStructOnly
= 72;
907 audio
->audioSampleRate
= (union {double d
; uint64_t i
;}){summary
->frequency
}.i
;
908 audio
->numAudioChannels
= summary
->channels
;
909 audio
->always7F000000
= 0x7F000000;
910 audio
->constBitsPerChannel
= summary
->bit_depth
;
911 audio
->constLPCMFramesPerAudioPacket
= 1;
912 if( summary
->sample_format
)
913 audio
->formatSpecificFlags
|= QT_LPCM_FORMAT_FLAG_FLOAT
;
914 if( sample_type
== QT_CODEC_TYPE_TWOS_AUDIO
|| !summary
->endianness
)
915 audio
->formatSpecificFlags
|= QT_LPCM_FORMAT_FLAG_BIG_ENDIAN
;
916 if( !summary
->sample_format
&& summary
->signedness
)
917 audio
->formatSpecificFlags
|= QT_LPCM_FORMAT_FLAG_SIGNED_INTEGER
;
918 if( summary
->packed
)
919 audio
->formatSpecificFlags
|= QT_LPCM_FORMAT_FLAG_PACKED
;
920 if( !summary
->packed
&& summary
->alignment
)
921 audio
->formatSpecificFlags
|= QT_LPCM_FORMAT_FLAG_ALIGNED_HIGH
;
922 if( !summary
->interleaved
)
923 audio
->formatSpecificFlags
|= QT_LPCM_FORMAT_FLAG_NON_INTERLEAVED
;
925 else if( audio
->version
== 1 )
927 audio
->channelcount
= summary
->channels
;
928 audio
->samplesize
= 16;
929 /* Audio formats other than 'raw ' and 'twos' are treated as compressed audio. */
930 if( sample_type
== QT_CODEC_TYPE_RAW_AUDIO
|| sample_type
== QT_CODEC_TYPE_TWOS_AUDIO
)
931 audio
->compression_ID
= QT_COMPRESSION_ID_NOT_COMPRESSED
;
933 audio
->compression_ID
= QT_COMPRESSION_ID_FIXED_COMPRESSION
;
934 audio
->samplerate
= summary
->frequency
<< 16;
935 audio
->samplesPerPacket
= 1;
936 audio
->bytesPerPacket
= summary
->bit_depth
/ 8;
937 audio
->bytesPerFrame
= audio
->bytesPerPacket
* summary
->channels
; /* sample_size field in stsz box is NOT used. */
938 audio
->bytesPerSample
= 1 + (summary
->bit_depth
!= 8);
939 if( sample_type
== QT_CODEC_TYPE_FL32_AUDIO
|| sample_type
== QT_CODEC_TYPE_FL64_AUDIO
940 || sample_type
== QT_CODEC_TYPE_IN24_AUDIO
|| sample_type
== QT_CODEC_TYPE_IN32_AUDIO
)
942 if( isom_add_wave( audio
)
943 || isom_add_frma( audio
->wave
)
944 || isom_add_enda( audio
->wave
)
945 || isom_add_terminator( audio
->wave
) )
947 audio
->wave
->frma
->data_format
= sample_type
;
948 audio
->wave
->enda
->littleEndian
= summary
->endianness
;
951 else /* audio->version == 0 */
953 audio
->channelcount
= summary
->channels
;
954 audio
->samplesize
= summary
->bit_depth
;
955 audio
->compression_ID
= QT_COMPRESSION_ID_NOT_COMPRESSED
;
956 audio
->samplerate
= summary
->frequency
<< 16;
961 static int isom_set_extra_description( isom_audio_entry_t
*audio
)
963 lsmash_audio_summary_t
*summary
= &audio
->summary
;
964 audio
->data_reference_index
= 1;
965 audio
->samplerate
= summary
->frequency
<= UINT16_MAX
? summary
->frequency
<< 16 : 0;
966 audio
->channelcount
= 2;
967 audio
->samplesize
= 16;
968 if( summary
->exdata
)
970 audio
->exdata_length
= summary
->exdata_length
;
971 audio
->exdata
= malloc( audio
->exdata_length
);
974 memcpy( audio
->exdata
, summary
->exdata
, audio
->exdata_length
);
977 audio
->exdata
= NULL
;
981 static int isom_add_audio_entry( isom_stsd_t
*stsd
, uint32_t sample_type
, lsmash_audio_summary_t
*summary
)
983 if( !stsd
|| !stsd
->list
|| !summary
)
985 isom_audio_entry_t
*audio
= malloc( sizeof(isom_audio_entry_t
) );
988 memset( audio
, 0, sizeof(isom_audio_entry_t
) );
989 isom_init_box_common( audio
, stsd
, sample_type
);
990 memcpy( &audio
->summary
, summary
, sizeof(lsmash_audio_summary_t
) );
992 lsmash_root_t
*root
= stsd
->root
;
993 if( sample_type
== ISOM_CODEC_TYPE_MP4A_AUDIO
)
995 if( root
->ftyp
&& root
->ftyp
->major_brand
== ISOM_BRAND_TYPE_QT
)
996 ret
= isom_set_qtff_mp4a_description( audio
);
998 ret
= isom_set_isom_mp4a_description( audio
);
1000 else if( isom_is_lpcm_audio( sample_type
) )
1001 ret
= isom_set_qtff_lpcm_description( audio
);
1003 ret
= isom_set_extra_description( audio
);
1006 if( root
->qt_compatible
)
1008 lsmash_channel_layout_tag layout_tag
= summary
->layout_tag
;
1009 lsmash_channel_bitmap bitmap
= summary
->bitmap
;
1010 if( layout_tag
== QT_CHANNEL_LAYOUT_USE_CHANNEL_DESCRIPTIONS
/* We don't support the feature of Channel Descriptions. */
1011 || (layout_tag
== QT_CHANNEL_LAYOUT_USE_CHANNEL_BITMAP
&& (!bitmap
|| bitmap
> QT_CHANNEL_BIT_FULL
)) )
1013 layout_tag
= summary
->layout_tag
= QT_CHANNEL_LAYOUT_UNKNOWN
| summary
->channels
;
1014 bitmap
= summary
->bitmap
= 0;
1016 /* Don't create Channel Compositor Box if the channel layout is unknown. */
1017 if( (layout_tag
^ QT_CHANNEL_LAYOUT_UNKNOWN
) >> 16 )
1019 if( isom_add_chan( audio
) )
1021 audio
->chan
->channelLayoutTag
= layout_tag
;
1022 audio
->chan
->channelBitmap
= bitmap
;
1025 if( lsmash_add_entry( stsd
->list
, audio
) )
1029 isom_remove_esds( audio
->esds
);
1030 isom_remove_wave( audio
->wave
);
1031 isom_remove_chan( audio
->chan
);
1033 free( audio
->exdata
);
1038 static int isom_add_text_entry( isom_stsd_t
*stsd
)
1040 if( !stsd
|| !stsd
->list
)
1042 isom_text_entry_t
*text
= malloc( sizeof(isom_text_entry_t
) );
1045 memset( text
, 0, sizeof(isom_text_entry_t
) );
1046 isom_init_box_common( text
, stsd
, QT_CODEC_TYPE_TEXT_TEXT
);
1047 text
->data_reference_index
= 1;
1048 if( lsmash_add_entry( stsd
->list
, text
) )
1056 int isom_add_ftab( isom_tx3g_entry_t
*tx3g
)
1060 isom_ftab_t
*ftab
= malloc( sizeof(isom_ftab_t
) );
1063 memset( ftab
, 0, sizeof(isom_ftab_t
) );
1064 isom_init_box_common( ftab
, tx3g
, ISOM_BOX_TYPE_FTAB
);
1065 ftab
->list
= lsmash_create_entry_list();
1075 static int isom_add_tx3g_entry( isom_stsd_t
*stsd
)
1077 if( !stsd
|| !stsd
->list
)
1079 isom_tx3g_entry_t
*tx3g
= malloc( sizeof(isom_tx3g_entry_t
) );
1082 memset( tx3g
, 0, sizeof(isom_tx3g_entry_t
) );
1083 isom_init_box_common( tx3g
, stsd
, ISOM_CODEC_TYPE_TX3G_TEXT
);
1084 tx3g
->data_reference_index
= 1;
1085 if( isom_add_ftab( tx3g
) ||
1086 lsmash_add_entry( stsd
->list
, tx3g
) )
1094 /* This function returns 0 if failed, sample_entry_number if succeeded. */
1095 int lsmash_add_sample_entry( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t sample_type
, void *summary
)
1097 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
1098 if( !trak
|| !trak
->root
|| !trak
->root
->ftyp
|| !trak
->mdia
|| !trak
->mdia
->minf
1099 || !trak
->mdia
->minf
->stbl
|| !trak
->mdia
->minf
->stbl
->stsd
|| !trak
->mdia
->minf
->stbl
->stsd
->list
)
1101 isom_stsd_t
*stsd
= trak
->mdia
->minf
->stbl
->stsd
;
1102 lsmash_entry_list_t
*list
= stsd
->list
;
1104 switch( sample_type
)
1106 case ISOM_CODEC_TYPE_AVC1_VIDEO
:
1108 case ISOM_CODEC_TYPE_AVC2_VIDEO
:
1109 case ISOM_CODEC_TYPE_AVCP_VIDEO
:
1110 case ISOM_CODEC_TYPE_SVC1_VIDEO
:
1111 case ISOM_CODEC_TYPE_MVC1_VIDEO
:
1112 case ISOM_CODEC_TYPE_MVC2_VIDEO
:
1113 case ISOM_CODEC_TYPE_MP4V_VIDEO
:
1114 case ISOM_CODEC_TYPE_DRAC_VIDEO
:
1115 case ISOM_CODEC_TYPE_ENCV_VIDEO
:
1116 case ISOM_CODEC_TYPE_MJP2_VIDEO
:
1117 case ISOM_CODEC_TYPE_S263_VIDEO
:
1118 case ISOM_CODEC_TYPE_VC_1_VIDEO
:
1120 ret
= isom_add_visual_entry( stsd
, sample_type
, (lsmash_video_summary_t
*)summary
);
1123 case ISOM_CODEC_TYPE_MP4S_SYSTEM
:
1124 ret
= isom_add_mp4s_entry( stsd
);
1127 case ISOM_CODEC_TYPE_MP4A_AUDIO
:
1128 case ISOM_CODEC_TYPE_AC_3_AUDIO
:
1129 case ISOM_CODEC_TYPE_ALAC_AUDIO
:
1130 case ISOM_CODEC_TYPE_SAMR_AUDIO
:
1131 case ISOM_CODEC_TYPE_SAWB_AUDIO
:
1132 case QT_CODEC_TYPE_23NI_AUDIO
:
1133 case QT_CODEC_TYPE_NONE_AUDIO
:
1134 case QT_CODEC_TYPE_LPCM_AUDIO
:
1135 case QT_CODEC_TYPE_RAW_AUDIO
:
1136 case QT_CODEC_TYPE_SOWT_AUDIO
:
1137 case QT_CODEC_TYPE_TWOS_AUDIO
:
1138 case QT_CODEC_TYPE_FL32_AUDIO
:
1139 case QT_CODEC_TYPE_FL64_AUDIO
:
1140 case QT_CODEC_TYPE_IN24_AUDIO
:
1141 case QT_CODEC_TYPE_IN32_AUDIO
:
1142 case QT_CODEC_TYPE_NOT_SPECIFIED
:
1144 case ISOM_CODEC_TYPE_DRA1_AUDIO
:
1145 case ISOM_CODEC_TYPE_DTSC_AUDIO
:
1146 case ISOM_CODEC_TYPE_DTSH_AUDIO
:
1147 case ISOM_CODEC_TYPE_DTSL_AUDIO
:
1148 case ISOM_CODEC_TYPE_EC_3_AUDIO
:
1149 case ISOM_CODEC_TYPE_ENCA_AUDIO
:
1150 case ISOM_CODEC_TYPE_G719_AUDIO
:
1151 case ISOM_CODEC_TYPE_G726_AUDIO
:
1152 case ISOM_CODEC_TYPE_M4AE_AUDIO
:
1153 case ISOM_CODEC_TYPE_MLPA_AUDIO
:
1154 case ISOM_CODEC_TYPE_RAW_AUDIO
:
1155 case ISOM_CODEC_TYPE_SAWP_AUDIO
:
1156 case ISOM_CODEC_TYPE_SEVC_AUDIO
:
1157 case ISOM_CODEC_TYPE_SQCP_AUDIO
:
1158 case ISOM_CODEC_TYPE_SSMV_AUDIO
:
1159 case ISOM_CODEC_TYPE_TWOS_AUDIO
:
1161 ret
= isom_add_audio_entry( stsd
, sample_type
, (lsmash_audio_summary_t
*)summary
);
1163 case ISOM_CODEC_TYPE_TX3G_TEXT
:
1164 ret
= isom_add_tx3g_entry( stsd
);
1166 case QT_CODEC_TYPE_TEXT_TEXT
:
1167 ret
= isom_add_text_entry( stsd
);
1172 return ret
? 0 : list
->entry_count
;
1175 static int isom_add_stts_entry( isom_stbl_t
*stbl
, uint32_t sample_delta
)
1177 if( !stbl
|| !stbl
->stts
|| !stbl
->stts
->list
)
1179 isom_stts_entry_t
*data
= malloc( sizeof(isom_stts_entry_t
) );
1182 data
->sample_count
= 1;
1183 data
->sample_delta
= sample_delta
;
1184 if( lsmash_add_entry( stbl
->stts
->list
, data
) )
1192 static int isom_add_ctts_entry( isom_stbl_t
*stbl
, uint32_t sample_offset
)
1194 if( !stbl
|| !stbl
->ctts
|| !stbl
->ctts
->list
)
1196 isom_ctts_entry_t
*data
= malloc( sizeof(isom_ctts_entry_t
) );
1199 data
->sample_count
= 1;
1200 data
->sample_offset
= sample_offset
;
1201 if( lsmash_add_entry( stbl
->ctts
->list
, data
) )
1209 static int isom_add_stsc_entry( isom_stbl_t
*stbl
, uint32_t first_chunk
, uint32_t samples_per_chunk
, uint32_t sample_description_index
)
1211 if( !stbl
|| !stbl
->stsc
|| !stbl
->stsc
->list
)
1213 isom_stsc_entry_t
*data
= malloc( sizeof(isom_stsc_entry_t
) );
1216 data
->first_chunk
= first_chunk
;
1217 data
->samples_per_chunk
= samples_per_chunk
;
1218 data
->sample_description_index
= sample_description_index
;
1219 if( lsmash_add_entry( stbl
->stsc
->list
, data
) )
1227 static int isom_add_stsz_entry( isom_stbl_t
*stbl
, uint32_t entry_size
)
1229 if( !stbl
|| !stbl
->stsz
)
1231 isom_stsz_t
*stsz
= stbl
->stsz
;
1232 /* retrieve initial sample_size */
1233 if( !stsz
->sample_count
)
1234 stsz
->sample_size
= entry_size
;
1235 /* if it seems constant access_unit size at present, update sample_count only */
1236 if( !stsz
->list
&& stsz
->sample_size
== entry_size
)
1238 ++ stsz
->sample_count
;
1241 /* found sample_size varies, create sample_size list */
1244 stsz
->list
= lsmash_create_entry_list();
1247 for( uint32_t i
= 0; i
< stsz
->sample_count
; i
++ )
1249 isom_stsz_entry_t
*data
= malloc( sizeof(isom_stsz_entry_t
) );
1252 data
->entry_size
= stsz
->sample_size
;
1253 if( lsmash_add_entry( stsz
->list
, data
) )
1259 stsz
->sample_size
= 0;
1261 isom_stsz_entry_t
*data
= malloc( sizeof(isom_stsz_entry_t
) );
1264 data
->entry_size
= entry_size
;
1265 if( lsmash_add_entry( stsz
->list
, data
) )
1270 ++ stsz
->sample_count
;
1274 static int isom_add_stss_entry( isom_stbl_t
*stbl
, uint32_t sample_number
)
1276 if( !stbl
|| !stbl
->stss
|| !stbl
->stss
->list
)
1278 isom_stss_entry_t
*data
= malloc( sizeof(isom_stss_entry_t
) );
1281 data
->sample_number
= sample_number
;
1282 if( lsmash_add_entry( stbl
->stss
->list
, data
) )
1290 static int isom_add_stps_entry( isom_stbl_t
*stbl
, uint32_t sample_number
)
1292 if( !stbl
|| !stbl
->stps
|| !stbl
->stps
->list
)
1294 isom_stps_entry_t
*data
= malloc( sizeof(isom_stps_entry_t
) );
1297 data
->sample_number
= sample_number
;
1298 if( lsmash_add_entry( stbl
->stps
->list
, data
) )
1306 static int isom_add_sdtp_entry( isom_stbl_t
*stbl
, lsmash_sample_property_t
*prop
, uint8_t avc_extensions
)
1310 if( !stbl
|| !stbl
->sdtp
|| !stbl
->sdtp
->list
)
1312 isom_sdtp_entry_t
*data
= malloc( sizeof(isom_sdtp_entry_t
) );
1315 /* isom_sdtp_entry_t is smaller than lsmash_sample_property_t. */
1316 data
->is_leading
= (avc_extensions
? prop
->leading
: prop
->allow_earlier
) & 0x03;
1317 data
->sample_depends_on
= prop
->independent
& 0x03;
1318 data
->sample_is_depended_on
= prop
->disposable
& 0x03;
1319 data
->sample_has_redundancy
= prop
->redundant
& 0x03;
1320 if( lsmash_add_entry( stbl
->sdtp
->list
, data
) )
1328 static int isom_add_co64( isom_stbl_t
*stbl
)
1330 if( !stbl
|| stbl
->stco
)
1332 isom_create_list_box( stco
, stbl
, ISOM_BOX_TYPE_CO64
);
1333 stco
->large_presentation
= 1;
1338 static int isom_add_stco( isom_stbl_t
*stbl
)
1340 if( !stbl
|| stbl
->stco
)
1342 isom_create_list_box( stco
, stbl
, ISOM_BOX_TYPE_STCO
);
1343 stco
->large_presentation
= 0;
1348 static int isom_add_co64_entry( isom_stbl_t
*stbl
, uint64_t chunk_offset
)
1350 if( !stbl
|| !stbl
->stco
|| !stbl
->stco
->list
)
1352 isom_co64_entry_t
*data
= malloc( sizeof(isom_co64_entry_t
) );
1355 data
->chunk_offset
= chunk_offset
;
1356 if( lsmash_add_entry( stbl
->stco
->list
, data
) )
1364 static int isom_convert_stco_to_co64( isom_stbl_t
* stbl
)
1367 isom_stco_t
*stco
= stbl
->stco
;
1369 if( isom_add_co64( stbl
) )
1371 /* move chunk_offset to co64 from stco */
1372 for( lsmash_entry_t
*entry
= stco
->list
->head
; entry
; entry
= entry
->next
)
1374 isom_stco_entry_t
*data
= (isom_stco_entry_t
*)entry
->data
;
1375 if( isom_add_co64_entry( stbl
, data
->chunk_offset
) )
1378 lsmash_remove_list( stco
->list
, NULL
);
1383 static int isom_add_stco_entry( isom_stbl_t
*stbl
, uint64_t chunk_offset
)
1385 if( !stbl
|| !stbl
->stco
|| !stbl
->stco
->list
)
1387 if( stbl
->stco
->large_presentation
)
1388 return isom_add_co64_entry( stbl
, chunk_offset
);
1389 if( chunk_offset
> UINT32_MAX
)
1391 if( isom_convert_stco_to_co64( stbl
) )
1393 return isom_add_co64_entry( stbl
, chunk_offset
);
1395 isom_stco_entry_t
*data
= malloc( sizeof(isom_stco_entry_t
) );
1398 data
->chunk_offset
= (uint32_t)chunk_offset
;
1399 if( lsmash_add_entry( stbl
->stco
->list
, data
) )
1407 isom_sgpd_entry_t
*isom_get_sample_group_description( isom_stbl_t
*stbl
, uint32_t grouping_type
)
1409 if( !stbl
->sgpd_list
)
1411 for( lsmash_entry_t
*entry
= stbl
->sgpd_list
->head
; entry
; entry
= entry
->next
)
1413 isom_sgpd_entry_t
*sgpd
= (isom_sgpd_entry_t
*)entry
->data
;
1414 if( !sgpd
|| !sgpd
->list
)
1416 if( sgpd
->grouping_type
== grouping_type
)
1422 isom_sbgp_entry_t
*isom_get_sample_to_group( isom_stbl_t
*stbl
, uint32_t grouping_type
)
1424 if( !stbl
->sbgp_list
)
1426 for( lsmash_entry_t
*entry
= stbl
->sbgp_list
->head
; entry
; entry
= entry
->next
)
1428 isom_sbgp_entry_t
*sbgp
= (isom_sbgp_entry_t
*)entry
->data
;
1429 if( !sbgp
|| !sbgp
->list
)
1431 if( sbgp
->grouping_type
== grouping_type
)
1437 static isom_rap_entry_t
*isom_add_rap_group_entry( isom_sgpd_entry_t
*sgpd
)
1441 isom_rap_entry_t
*data
= malloc( sizeof(isom_rap_entry_t
) );
1444 memset( data
, 0, sizeof(isom_rap_entry_t
) );
1445 if( lsmash_add_entry( sgpd
->list
, data
) )
1453 static isom_roll_entry_t
*isom_add_roll_group_entry( isom_sgpd_entry_t
*sgpd
, int16_t roll_distance
)
1457 isom_roll_entry_t
*data
= malloc( sizeof(isom_roll_entry_t
) );
1460 data
->description_length
= 0;
1461 data
->roll_distance
= roll_distance
;
1462 if( lsmash_add_entry( sgpd
->list
, data
) )
1470 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
)
1474 isom_group_assignment_entry_t
*data
= malloc( sizeof(isom_group_assignment_entry_t
) );
1477 data
->sample_count
= sample_count
;
1478 data
->group_description_index
= group_description_index
;
1479 if( lsmash_add_entry( sbgp
->list
, data
) )
1487 static int isom_add_chpl_entry( isom_chpl_t
*chpl
, isom_chapter_entry_t
*chap_data
)
1489 if( !chap_data
->chapter_name
|| !chpl
|| !chpl
->list
)
1491 isom_chpl_entry_t
*data
= malloc( sizeof(isom_chpl_entry_t
) );
1494 data
->start_time
= chap_data
->start_time
;
1495 data
->chapter_name_length
= strlen( chap_data
->chapter_name
);
1496 data
->chapter_name
= ( char* )malloc( data
->chapter_name_length
+ 1 );
1497 if( !data
->chapter_name
)
1502 memcpy( data
->chapter_name
, chap_data
->chapter_name
, data
->chapter_name_length
);
1503 data
->chapter_name
[data
->chapter_name_length
] = '\0';
1504 if( lsmash_add_entry( chpl
->list
, data
) )
1506 free( data
->chapter_name
);
1513 static isom_trex_entry_t
*isom_add_trex( isom_mvex_t
*mvex
)
1517 if( !mvex
->trex_list
)
1519 mvex
->trex_list
= lsmash_create_entry_list();
1520 if( !mvex
->trex_list
)
1523 isom_trex_entry_t
*trex
= malloc( sizeof(isom_trex_entry_t
) );
1526 memset( trex
, 0, sizeof(isom_trex_entry_t
) );
1527 isom_init_box_common( trex
, mvex
, ISOM_BOX_TYPE_TREX
);
1528 if( lsmash_add_entry( mvex
->trex_list
, trex
) )
1536 static isom_trun_entry_t
*isom_add_trun( isom_traf_entry_t
*traf
)
1540 if( !traf
->trun_list
)
1542 traf
->trun_list
= lsmash_create_entry_list();
1543 if( !traf
->trun_list
)
1546 isom_trun_entry_t
*trun
= malloc( sizeof(isom_trun_entry_t
) );
1549 memset( trun
, 0, sizeof(isom_trun_entry_t
) );
1550 isom_init_box_common( trun
, traf
, ISOM_BOX_TYPE_TRUN
);
1551 if( lsmash_add_entry( traf
->trun_list
, trun
) )
1559 static isom_traf_entry_t
*isom_add_traf( lsmash_root_t
*root
, isom_moof_entry_t
*moof
)
1561 if( !root
|| !root
->moof_list
|| !moof
)
1563 if( !moof
->traf_list
)
1565 moof
->traf_list
= lsmash_create_entry_list();
1566 if( !moof
->traf_list
)
1569 isom_traf_entry_t
*traf
= malloc( sizeof(isom_traf_entry_t
) );
1572 memset( traf
, 0, sizeof(isom_traf_entry_t
) );
1573 isom_init_box_common( traf
, moof
, ISOM_BOX_TYPE_TRAF
);
1574 isom_cache_t
*cache
= malloc( sizeof(isom_cache_t
) );
1580 memset( cache
, 0, sizeof(isom_cache_t
) );
1581 if( lsmash_add_entry( moof
->traf_list
, traf
) )
1587 traf
->cache
= cache
;
1591 static isom_moof_entry_t
*isom_add_moof( lsmash_root_t
*root
)
1595 if( !root
->moof_list
)
1597 root
->moof_list
= lsmash_create_entry_list();
1598 if( !root
->moof_list
)
1601 isom_moof_entry_t
*moof
= malloc( sizeof(isom_moof_entry_t
) );
1604 memset( moof
, 0, sizeof(isom_moof_entry_t
) );
1605 isom_init_box_common( moof
, root
, ISOM_BOX_TYPE_MOOF
);
1606 if( lsmash_add_entry( root
->moof_list
, moof
) )
1614 static isom_tfra_entry_t
*isom_add_tfra( isom_mfra_t
*mfra
)
1618 if( !mfra
->tfra_list
)
1620 mfra
->tfra_list
= lsmash_create_entry_list();
1621 if( !mfra
->tfra_list
)
1624 isom_tfra_entry_t
*tfra
= malloc( sizeof(isom_tfra_entry_t
) );
1627 memset( tfra
, 0, sizeof(isom_tfra_entry_t
) );
1628 isom_init_box_common( tfra
, mfra
, ISOM_BOX_TYPE_TFRA
);
1629 if( lsmash_add_entry( mfra
->tfra_list
, tfra
) )
1637 static int isom_add_ftyp( lsmash_root_t
*root
)
1641 isom_create_box( ftyp
, root
, ISOM_BOX_TYPE_FTYP
);
1642 ftyp
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 8;
1647 static int isom_add_moov( lsmash_root_t
*root
)
1651 isom_create_box( moov
, root
, ISOM_BOX_TYPE_MOOV
);
1656 static int isom_add_mvhd( isom_moov_t
*moov
)
1658 if( !moov
|| moov
->mvhd
)
1660 isom_create_box( mvhd
, moov
, ISOM_BOX_TYPE_MVHD
);
1661 mvhd
->rate
= 0x00010000;
1662 mvhd
->volume
= 0x0100;
1663 mvhd
->matrix
[0] = 0x00010000;
1664 mvhd
->matrix
[4] = 0x00010000;
1665 mvhd
->matrix
[8] = 0x40000000;
1666 mvhd
->next_track_ID
= 1;
1671 static int isom_scan_trak_profileLevelIndication( isom_trak_entry_t
* trak
, mp4a_audioProfileLevelIndication
* audio_pli
, mp4sys_visualProfileLevelIndication
* visual_pli
)
1673 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
)
1675 isom_stsd_t
* stsd
= trak
->mdia
->minf
->stbl
->stsd
;
1676 if( !stsd
|| !stsd
->list
|| !stsd
->list
->head
)
1678 for( lsmash_entry_t
*entry
= stsd
->list
->head
; entry
; entry
= entry
->next
)
1680 isom_sample_entry_t
* sample_entry
= (isom_sample_entry_t
*)entry
->data
;
1683 switch( sample_entry
->type
)
1685 case ISOM_CODEC_TYPE_AVC1_VIDEO
:
1687 case ISOM_CODEC_TYPE_AVC2_VIDEO
:
1688 case ISOM_CODEC_TYPE_AVCP_VIDEO
:
1689 case ISOM_CODEC_TYPE_SVC1_VIDEO
:
1690 case ISOM_CODEC_TYPE_MVC1_VIDEO
:
1691 case ISOM_CODEC_TYPE_MVC2_VIDEO
:
1693 /* FIXME: Do we have to arbitrate like audio? */
1694 if( *visual_pli
== MP4SYS_VISUAL_PLI_NONE_REQUIRED
)
1695 *visual_pli
= MP4SYS_VISUAL_PLI_H264_AVC
;
1697 case ISOM_CODEC_TYPE_MP4A_AUDIO
:
1698 *audio_pli
= mp4a_max_audioProfileLevelIndication( *audio_pli
, mp4a_get_audioProfileLevelIndication( &((isom_audio_entry_t
*)sample_entry
)->summary
) );
1701 case ISOM_CODEC_TYPE_DRAC_VIDEO
:
1702 case ISOM_CODEC_TYPE_ENCV_VIDEO
:
1703 case ISOM_CODEC_TYPE_MJP2_VIDEO
:
1704 case ISOM_CODEC_TYPE_S263_VIDEO
:
1705 case ISOM_CODEC_TYPE_VC_1_VIDEO
:
1706 /* FIXME: Do we have to arbitrate like audio? */
1707 if( *visual_pli
== MP4SYS_VISUAL_PLI_NONE_REQUIRED
)
1708 *visual_pli
= MP4SYS_VISUAL_PLI_NOT_SPECIFIED
;
1711 case ISOM_CODEC_TYPE_AC_3_AUDIO
:
1712 case ISOM_CODEC_TYPE_ALAC_AUDIO
:
1713 case ISOM_CODEC_TYPE_SAMR_AUDIO
:
1714 case ISOM_CODEC_TYPE_SAWB_AUDIO
:
1715 #ifdef LSMASH_DEMUXER_ENABLED
1716 case ISOM_CODEC_TYPE_EC_3_AUDIO
:
1719 case ISOM_CODEC_TYPE_DRA1_AUDIO
:
1720 case ISOM_CODEC_TYPE_DTSC_AUDIO
:
1721 case ISOM_CODEC_TYPE_DTSH_AUDIO
:
1722 case ISOM_CODEC_TYPE_DTSL_AUDIO
:
1723 case ISOM_CODEC_TYPE_ENCA_AUDIO
:
1724 case ISOM_CODEC_TYPE_G719_AUDIO
:
1725 case ISOM_CODEC_TYPE_G726_AUDIO
:
1726 case ISOM_CODEC_TYPE_M4AE_AUDIO
:
1727 case ISOM_CODEC_TYPE_MLPA_AUDIO
:
1728 case ISOM_CODEC_TYPE_RAW_AUDIO
:
1729 case ISOM_CODEC_TYPE_SAWP_AUDIO
:
1730 case ISOM_CODEC_TYPE_SEVC_AUDIO
:
1731 case ISOM_CODEC_TYPE_SQCP_AUDIO
:
1732 case ISOM_CODEC_TYPE_SSMV_AUDIO
:
1733 case ISOM_CODEC_TYPE_TWOS_AUDIO
:
1735 /* NOTE: These audio codecs other than mp4a does not have appropriate pli. */
1736 *audio_pli
= MP4A_AUDIO_PLI_NOT_SPECIFIED
;
1739 case ISOM_CODEC_TYPE_FDP_HINT
:
1740 case ISOM_CODEC_TYPE_M2TS_HINT
:
1741 case ISOM_CODEC_TYPE_PM2T_HINT
:
1742 case ISOM_CODEC_TYPE_PRTP_HINT
:
1743 case ISOM_CODEC_TYPE_RM2T_HINT
:
1744 case ISOM_CODEC_TYPE_RRTP_HINT
:
1745 case ISOM_CODEC_TYPE_RSRP_HINT
:
1746 case ISOM_CODEC_TYPE_RTP_HINT
:
1747 case ISOM_CODEC_TYPE_SM2T_HINT
:
1748 case ISOM_CODEC_TYPE_SRTP_HINT
:
1749 /* FIXME: Do we have to set OD_profileLevelIndication? */
1751 case ISOM_CODEC_TYPE_IXSE_META
:
1752 case ISOM_CODEC_TYPE_METT_META
:
1753 case ISOM_CODEC_TYPE_METX_META
:
1754 case ISOM_CODEC_TYPE_MLIX_META
:
1755 case ISOM_CODEC_TYPE_OKSD_META
:
1756 case ISOM_CODEC_TYPE_SVCM_META
:
1757 case ISOM_CODEC_TYPE_TEXT_META
:
1758 case ISOM_CODEC_TYPE_URIM_META
:
1759 case ISOM_CODEC_TYPE_XML_META
:
1760 /* FIXME: Do we have to set OD_profileLevelIndication? */
1768 static int isom_add_iods( isom_moov_t
*moov
)
1770 if( !moov
|| !moov
->trak_list
|| moov
->iods
)
1772 isom_create_box( iods
, moov
, ISOM_BOX_TYPE_IODS
);
1773 iods
->OD
= mp4sys_create_ObjectDescriptor( 1 ); /* NOTE: Use 1 for ObjectDescriptorID of IOD. */
1779 mp4a_audioProfileLevelIndication audio_pli
= MP4A_AUDIO_PLI_NONE_REQUIRED
;
1780 mp4sys_visualProfileLevelIndication visual_pli
= MP4SYS_VISUAL_PLI_NONE_REQUIRED
;
1781 for( lsmash_entry_t
*entry
= moov
->trak_list
->head
; entry
; entry
= entry
->next
)
1783 isom_trak_entry_t
* trak
= (isom_trak_entry_t
*)entry
->data
;
1784 if( !trak
|| !trak
->tkhd
)
1786 if( isom_scan_trak_profileLevelIndication( trak
, &audio_pli
, &visual_pli
) )
1788 if( mp4sys_add_ES_ID_Inc( iods
->OD
, trak
->tkhd
->track_ID
) )
1791 if( mp4sys_to_InitialObjectDescriptor( iods
->OD
,
1792 0, /* FIXME: I'm not quite sure what the spec says. */
1793 MP4SYS_OD_PLI_NONE_REQUIRED
, MP4SYS_SCENE_PLI_NONE_REQUIRED
,
1794 audio_pli
, visual_pli
,
1795 MP4SYS_GRAPHICS_PLI_NONE_REQUIRED
) )
1804 static int isom_add_tkhd( isom_trak_entry_t
*trak
, uint32_t handler_type
)
1806 if( !trak
|| !trak
->root
|| !trak
->root
->moov
|| !trak
->root
->moov
->mvhd
|| !trak
->root
->moov
->trak_list
)
1810 isom_create_box( tkhd
, trak
, ISOM_BOX_TYPE_TKHD
);
1811 switch( handler_type
)
1813 case ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK
:
1814 tkhd
->matrix
[0] = 0x00010000;
1815 tkhd
->matrix
[4] = 0x00010000;
1816 tkhd
->matrix
[8] = 0x40000000;
1818 case ISOM_MEDIA_HANDLER_TYPE_AUDIO_TRACK
:
1819 tkhd
->volume
= 0x0100;
1824 tkhd
->duration
= 0xffffffff;
1825 tkhd
->track_ID
= trak
->root
->moov
->mvhd
->next_track_ID
;
1826 ++ trak
->root
->moov
->mvhd
->next_track_ID
;
1832 static int isom_add_clef( isom_tapt_t
*tapt
)
1836 isom_create_box( clef
, tapt
, QT_BOX_TYPE_CLEF
);
1841 static int isom_add_prof( isom_tapt_t
*tapt
)
1845 isom_create_box( prof
, tapt
, QT_BOX_TYPE_PROF
);
1850 static int isom_add_enof( isom_tapt_t
*tapt
)
1854 isom_create_box( enof
, tapt
, QT_BOX_TYPE_ENOF
);
1859 static int isom_add_tapt( isom_trak_entry_t
*trak
)
1863 isom_create_box( tapt
, trak
, QT_BOX_TYPE_TAPT
);
1868 int isom_add_elst( isom_edts_t
*edts
)
1872 isom_create_list_box( elst
, edts
, ISOM_BOX_TYPE_ELST
);
1877 int isom_add_edts( isom_trak_entry_t
*trak
)
1881 isom_create_box( edts
, trak
, ISOM_BOX_TYPE_EDTS
);
1886 static int isom_add_tref( isom_trak_entry_t
*trak
)
1890 isom_create_box( tref
, trak
, ISOM_BOX_TYPE_TREF
);
1891 tref
->ref_list
= lsmash_create_entry_list();
1892 if( !tref
->ref_list
)
1901 static int isom_add_mdhd( isom_mdia_t
*mdia
, uint16_t default_language
)
1903 if( !mdia
|| mdia
->mdhd
)
1905 isom_create_box( mdhd
, mdia
, ISOM_BOX_TYPE_MDHD
);
1906 mdhd
->language
= default_language
;
1911 static int isom_add_mdia( isom_trak_entry_t
*trak
)
1913 if( !trak
|| trak
->mdia
)
1915 isom_create_box( mdia
, trak
, ISOM_BOX_TYPE_MDIA
);
1920 static int isom_add_hdlr( isom_mdia_t
*mdia
, isom_meta_t
*meta
, isom_minf_t
*minf
, uint32_t media_type
)
1922 if( (!mdia
&& !meta
&& !minf
) || (mdia
&& meta
) || (meta
&& minf
) || (minf
&& mdia
) )
1923 return -1; /* Either one must be given. */
1924 if( (mdia
&& mdia
->hdlr
) || (meta
&& meta
->hdlr
) || (minf
&& minf
->hdlr
) )
1925 return -1; /* Selected one must not have hdlr yet. */
1926 isom_box_t
*parent
= mdia
? (isom_box_t
*)mdia
: meta
? (isom_box_t
*)meta
: (isom_box_t
*)minf
;
1927 isom_create_box( hdlr
, parent
, ISOM_BOX_TYPE_HDLR
);
1928 lsmash_root_t
*root
= hdlr
->root
;
1929 uint32_t type
= mdia
? (root
->qt_compatible
? QT_HANDLER_TYPE_MEDIA
: 0) : (meta
? 0 : QT_HANDLER_TYPE_DATA
);
1930 uint32_t subtype
= media_type
;
1931 hdlr
->componentType
= type
;
1932 hdlr
->componentSubtype
= subtype
;
1933 char *type_name
= NULL
;
1934 char *subtype_name
= NULL
;
1935 uint8_t type_name_length
= 0;
1936 uint8_t subtype_name_length
= 0;
1938 type_name
= "Media ";
1940 type_name
= "Metadata ";
1941 else /* if( minf ) */
1942 type_name
= "Data ";
1943 type_name_length
= strlen( type_name
);
1948 uint8_t subtype_name_length
;
1951 { ISOM_MEDIA_HANDLER_TYPE_AUDIO_TRACK
, "Sound ", 6 },
1952 { ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK
, "Video", 6 },
1953 { ISOM_MEDIA_HANDLER_TYPE_HINT_TRACK
, "Hint ", 5 },
1954 { ISOM_MEDIA_HANDLER_TYPE_TIMED_METADATA_TRACK
, "Metadata ", 9 },
1955 { ISOM_MEDIA_HANDLER_TYPE_TEXT_TRACK
, "Text ", 5 },
1956 { ISOM_META_HANDLER_TYPE_ITUNES_METADATA
, "iTunes ", 7 },
1957 { QT_REFERENCE_HANDLER_TYPE_ALIAS
, "Alias ", 6 },
1958 { QT_REFERENCE_HANDLER_TYPE_RESOURCE
, "Resource ", 9 },
1959 { QT_REFERENCE_HANDLER_TYPE_URL
, "URL ", 4 },
1960 { subtype
, "Unknown ", 8 }
1962 for( int i
= 0; subtype_table
[i
].subtype
; i
++ )
1963 if( subtype
== subtype_table
[i
].subtype
)
1965 subtype_name
= subtype_table
[i
].subtype_name
;
1966 subtype_name_length
= subtype_table
[i
].subtype_name_length
;
1969 uint32_t name_length
= 15 + subtype_name_length
+ type_name_length
+ root
->isom_compatible
+ root
->qt_compatible
;
1970 uint8_t *name
= malloc( name_length
);
1973 if( root
->qt_compatible
)
1974 name
[0] = name_length
& 0xff;
1975 memcpy( name
+ root
->qt_compatible
, "L-SMASH ", 8 );
1976 memcpy( name
+ root
->qt_compatible
+ 8, subtype_name
, subtype_name_length
);
1977 memcpy( name
+ root
->qt_compatible
+ 8 + subtype_name_length
, type_name
, type_name_length
);
1978 memcpy( name
+ root
->qt_compatible
+ 8 + subtype_name_length
+ type_name_length
, "Handler", 7 );
1979 if( root
->isom_compatible
)
1980 name
[name_length
- 1] = 0;
1981 hdlr
->componentName
= name
;
1982 hdlr
->componentName_length
= name_length
;
1992 static int isom_add_minf( isom_mdia_t
*mdia
)
1994 if( !mdia
|| mdia
->minf
)
1996 isom_create_box( minf
, mdia
, ISOM_BOX_TYPE_MINF
);
2001 static int isom_add_vmhd( isom_minf_t
*minf
)
2003 if( !minf
|| minf
->vmhd
)
2005 isom_create_box( vmhd
, minf
, ISOM_BOX_TYPE_VMHD
);
2006 vmhd
->flags
= 0x000001;
2011 static int isom_add_smhd( isom_minf_t
*minf
)
2013 if( !minf
|| minf
->smhd
)
2015 isom_create_box( smhd
, minf
, ISOM_BOX_TYPE_SMHD
);
2020 static int isom_add_hmhd( isom_minf_t
*minf
)
2022 if( !minf
|| minf
->hmhd
)
2024 isom_create_box( hmhd
, minf
, ISOM_BOX_TYPE_HMHD
);
2029 static int isom_add_nmhd( isom_minf_t
*minf
)
2031 if( !minf
|| minf
->nmhd
)
2033 isom_create_box( nmhd
, minf
, ISOM_BOX_TYPE_NMHD
);
2038 static int isom_add_gmin( isom_gmhd_t
*gmhd
)
2040 if( !gmhd
|| gmhd
->gmin
)
2042 isom_create_box( gmin
, gmhd
, QT_BOX_TYPE_GMIN
);
2047 static int isom_add_text( isom_gmhd_t
*gmhd
)
2049 if( !gmhd
|| gmhd
->text
)
2051 isom_create_box( text
, gmhd
, QT_BOX_TYPE_TEXT
);
2052 text
->matrix
[0] = 0x00010000;
2053 text
->matrix
[4] = 0x00010000;
2054 text
->matrix
[8] = 0x40000000;
2059 static int isom_add_gmhd( isom_minf_t
*minf
)
2061 if( !minf
|| minf
->gmhd
)
2063 isom_create_box( gmhd
, minf
, QT_BOX_TYPE_GMHD
);
2068 static int isom_add_dinf( isom_minf_t
*minf
)
2070 if( !minf
|| minf
->dinf
)
2072 isom_create_box( dinf
, minf
, ISOM_BOX_TYPE_DINF
);
2077 static int isom_add_dref( isom_dinf_t
*dinf
)
2079 if( !dinf
|| dinf
->dref
)
2081 isom_create_list_box( dref
, dinf
, ISOM_BOX_TYPE_DREF
);
2083 if( isom_add_dref_entry( dref
, 0x000001, NULL
, NULL
) )
2088 static int isom_add_stsd( isom_stbl_t
*stbl
)
2090 if( !stbl
|| stbl
->stsd
)
2092 isom_create_list_box( stsd
, stbl
, ISOM_BOX_TYPE_STSD
);
2097 int isom_add_btrt( isom_visual_entry_t
*visual
)
2099 if( !visual
|| visual
->btrt
)
2101 isom_create_box( btrt
, visual
, ISOM_BOX_TYPE_BTRT
);
2102 visual
->btrt
= btrt
;
2106 int lsmash_add_btrt( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t entry_number
)
2108 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
2109 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
|| !trak
->mdia
->minf
->stbl
->stsd
|| !trak
->mdia
->minf
->stbl
->stsd
->list
)
2111 isom_visual_entry_t
*data
= (isom_visual_entry_t
*)lsmash_get_entry_data( trak
->mdia
->minf
->stbl
->stsd
->list
, entry_number
);
2112 return isom_add_btrt( data
);
2115 static int isom_add_stts( isom_stbl_t
*stbl
)
2117 if( !stbl
|| stbl
->stts
)
2119 isom_create_list_box( stts
, stbl
, ISOM_BOX_TYPE_STTS
);
2124 static int isom_add_ctts( isom_stbl_t
*stbl
)
2126 if( !stbl
|| stbl
->ctts
)
2128 isom_create_list_box( ctts
, stbl
, ISOM_BOX_TYPE_CTTS
);
2133 static int isom_add_cslg( isom_stbl_t
*stbl
)
2135 if( !stbl
|| stbl
->cslg
)
2137 isom_create_box( cslg
, stbl
, ISOM_BOX_TYPE_CSLG
);
2142 static int isom_add_stsc( isom_stbl_t
*stbl
)
2144 if( !stbl
|| stbl
->stsc
)
2146 isom_create_list_box( stsc
, stbl
, ISOM_BOX_TYPE_STSC
);
2151 static int isom_add_stsz( isom_stbl_t
*stbl
)
2153 if( !stbl
|| stbl
->stsz
)
2155 isom_create_box( stsz
, stbl
, ISOM_BOX_TYPE_STSZ
); /* We don't create a list here. */
2160 static int isom_add_stss( isom_stbl_t
*stbl
)
2162 if( !stbl
|| stbl
->stss
)
2164 isom_create_list_box( stss
, stbl
, ISOM_BOX_TYPE_STSS
);
2169 static int isom_add_stps( isom_stbl_t
*stbl
)
2171 if( !stbl
|| stbl
->stps
)
2173 isom_create_list_box( stps
, stbl
, QT_BOX_TYPE_STPS
);
2178 static int isom_add_sdtp( isom_stbl_t
*stbl
)
2180 if( !stbl
|| stbl
->sdtp
)
2182 isom_create_list_box( sdtp
, stbl
, ISOM_BOX_TYPE_SDTP
);
2187 static isom_sgpd_entry_t
*isom_add_sgpd( isom_stbl_t
*stbl
, uint32_t grouping_type
)
2191 if( !stbl
->sgpd_list
)
2193 stbl
->sgpd_list
= lsmash_create_entry_list();
2194 if( !stbl
->sgpd_list
)
2197 isom_sgpd_entry_t
*sgpd
= malloc( sizeof(isom_sgpd_entry_t
) );
2200 memset( sgpd
, 0, sizeof(isom_sgpd_entry_t
) );
2201 isom_init_box_common( sgpd
, stbl
, ISOM_BOX_TYPE_SGPD
);
2202 sgpd
->list
= lsmash_create_entry_list();
2203 if( !sgpd
->list
|| lsmash_add_entry( stbl
->sgpd_list
, sgpd
) )
2208 sgpd
->grouping_type
= grouping_type
;
2209 sgpd
->version
= 1; /* We use version 1 because it is recommended in the spec. */
2210 switch( grouping_type
)
2212 case ISOM_GROUP_TYPE_RAP
:
2213 sgpd
->default_length
= 1;
2215 case ISOM_GROUP_TYPE_ROLL
:
2216 sgpd
->default_length
= 2;
2219 /* We don't consider other grouping types currently. */
2225 static isom_sbgp_entry_t
*isom_add_sbgp( isom_stbl_t
*stbl
, uint32_t grouping_type
)
2229 if( !stbl
->sbgp_list
)
2231 stbl
->sbgp_list
= lsmash_create_entry_list();
2232 if( !stbl
->sbgp_list
)
2235 isom_sbgp_entry_t
*sbgp
= malloc( sizeof(isom_sbgp_entry_t
) );
2238 memset( sbgp
, 0, sizeof(isom_sbgp_entry_t
) );
2239 isom_init_box_common( sbgp
, stbl
, ISOM_BOX_TYPE_SBGP
);
2240 sbgp
->list
= lsmash_create_entry_list();
2241 if( !sbgp
->list
|| lsmash_add_entry( stbl
->sbgp_list
, sbgp
) )
2246 sbgp
->grouping_type
= grouping_type
;
2250 static int isom_add_stbl( isom_minf_t
*minf
)
2252 if( !minf
|| minf
->stbl
)
2254 isom_create_box( stbl
, minf
, ISOM_BOX_TYPE_STBL
);
2259 static int isom_add_chpl( isom_moov_t
*moov
)
2261 if( !moov
|| !moov
->udta
|| moov
->udta
->chpl
)
2263 isom_create_list_box( chpl
, moov
->udta
, ISOM_BOX_TYPE_CHPL
);
2264 chpl
->version
= 1; /* version = 1 is popular. */
2265 moov
->udta
->chpl
= chpl
;
2269 #ifdef LSMASH_DEMUXER_ENABLED
2270 static int isom_add_mean( isom_metaitem_t
*metaitem
)
2272 if( !metaitem
|| metaitem
->mean
)
2274 isom_create_box( mean
, metaitem
, ISOM_BOX_TYPE_MEAN
);
2275 metaitem
->mean
= mean
;
2279 static int isom_add_name( isom_metaitem_t
*metaitem
)
2281 if( !metaitem
|| metaitem
->name
)
2283 isom_create_box( name
, metaitem
, ISOM_BOX_TYPE_NAME
);
2284 metaitem
->name
= name
;
2288 static int isom_add_data( isom_metaitem_t
*metaitem
)
2290 if( !metaitem
|| metaitem
->data
)
2292 isom_create_box( data
, metaitem
, ISOM_BOX_TYPE_DATA
);
2293 metaitem
->data
= data
;
2297 static int isom_add_ilst( isom_moov_t
*moov
)
2299 if( !moov
|| !moov
->udta
|| !moov
->udta
->meta
|| moov
->udta
->meta
->ilst
)
2301 isom_create_box( ilst
, moov
->udta
->meta
, ISOM_BOX_TYPE_ILST
);
2302 ilst
->item_list
= lsmash_create_entry_list();
2303 if( !ilst
->item_list
)
2308 moov
->udta
->meta
->ilst
= ilst
;
2312 static int isom_add_meta( isom_box_t
*parent
)
2316 isom_create_box( meta
, parent
, ISOM_BOX_TYPE_META
);
2319 lsmash_root_t
*root
= (lsmash_root_t
*)root
;
2324 else if( parent
->type
== ISOM_BOX_TYPE_MOOV
)
2326 isom_moov_t
*moov
= (isom_moov_t
*)parent
;
2331 else if( parent
->type
== ISOM_BOX_TYPE_TRAK
)
2333 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)trak
;
2340 isom_udta_t
*udta
= (isom_udta_t
*)parent
;
2347 #endif /* LSMASH_DEMUXER_ENABLED */
2349 static int isom_add_udta( lsmash_root_t
*root
, uint32_t track_ID
)
2351 /* track_ID == 0 means the direct addition to moov box */
2354 if( !root
|| !root
->moov
)
2356 if( root
->moov
->udta
)
2358 isom_create_box( udta
, root
->moov
, ISOM_BOX_TYPE_UDTA
);
2359 root
->moov
->udta
= udta
;
2362 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
2367 isom_create_box( udta
, trak
, ISOM_BOX_TYPE_UDTA
);
2372 static isom_trak_entry_t
*isom_add_trak( lsmash_root_t
*root
)
2374 if( !root
|| !root
->moov
)
2376 isom_moov_t
*moov
= root
->moov
;
2377 if( !moov
->trak_list
)
2379 moov
->trak_list
= lsmash_create_entry_list();
2380 if( !moov
->trak_list
)
2383 isom_trak_entry_t
*trak
= malloc( sizeof(isom_trak_entry_t
) );
2386 memset( trak
, 0, sizeof(isom_trak_entry_t
) );
2387 isom_init_box_common( trak
, moov
, ISOM_BOX_TYPE_TRAK
);
2388 isom_cache_t
*cache
= malloc( sizeof(isom_cache_t
) );
2394 memset( cache
, 0, sizeof(isom_cache_t
) );
2395 isom_fragment_t
*fragment
= NULL
;
2396 if( root
->fragment
)
2398 fragment
= malloc( sizeof(isom_fragment_t
) );
2405 memset( fragment
, 0, sizeof(isom_fragment_t
) );
2406 cache
->fragment
= fragment
;
2408 if( lsmash_add_entry( moov
->trak_list
, trak
) )
2416 trak
->cache
= cache
;
2420 static int isom_add_mvex( isom_moov_t
*moov
)
2422 if( !moov
|| moov
->mvex
)
2424 isom_create_box( mvex
, moov
, ISOM_BOX_TYPE_MVEX
);
2429 static int isom_add_mehd( isom_mvex_t
*mvex
)
2431 if( !mvex
|| mvex
->mehd
)
2433 isom_create_box( mehd
, mvex
, ISOM_BOX_TYPE_MEHD
);
2438 static int isom_add_tfhd( isom_traf_entry_t
*traf
)
2440 if( !traf
|| traf
->tfhd
)
2442 isom_create_box( tfhd
, traf
, ISOM_BOX_TYPE_TFHD
);
2447 static int isom_add_mfhd( isom_moof_entry_t
*moof
)
2449 if( !moof
|| moof
->mfhd
)
2451 isom_create_box( mfhd
, moof
, ISOM_BOX_TYPE_MFHD
);
2456 static int isom_add_mfra( lsmash_root_t
*root
)
2458 if( !root
|| root
->mfra
)
2460 isom_create_box( mfra
, root
, ISOM_BOX_TYPE_MFRA
);
2465 static int isom_add_mfro( isom_mfra_t
*mfra
)
2467 if( !mfra
|| mfra
->mfro
)
2469 isom_create_box( mfro
, mfra
, ISOM_BOX_TYPE_MFRO
);
2474 #define isom_remove_box( box_name, parent_type ) \
2477 parent_type *parent = (parent_type *)box_name->parent; \
2480 parent->box_name = NULL; \
2483 static void isom_remove_ftyp( isom_ftyp_t
*ftyp
)
2487 if( ftyp
->compatible_brands
)
2488 free( ftyp
->compatible_brands
);
2489 isom_remove_box( ftyp
, lsmash_root_t
);
2492 static void isom_remove_tkhd( isom_tkhd_t
*tkhd
)
2496 isom_remove_box( tkhd
, isom_trak_entry_t
);
2499 static void isom_remove_clef( isom_clef_t
*clef
)
2503 isom_remove_box( clef
, isom_tapt_t
);
2506 static void isom_remove_prof( isom_prof_t
*prof
)
2510 isom_remove_box( prof
, isom_tapt_t
);
2513 static void isom_remove_enof( isom_enof_t
*enof
)
2517 isom_remove_box( enof
, isom_tapt_t
);
2520 void isom_remove_tapt( isom_tapt_t
*tapt
)
2524 isom_remove_clef( tapt
->clef
);
2525 isom_remove_prof( tapt
->prof
);
2526 isom_remove_enof( tapt
->enof
);
2527 isom_remove_box( tapt
, isom_trak_entry_t
);
2530 static void isom_remove_elst( isom_elst_t
*elst
)
2534 lsmash_remove_list( elst
->list
, NULL
);
2535 isom_remove_box( elst
, isom_edts_t
);
2538 static void isom_remove_edts( isom_edts_t
*edts
)
2542 isom_remove_elst( edts
->elst
);
2543 isom_remove_box( edts
, isom_trak_entry_t
);
2546 static void isom_remove_track_reference_type( isom_tref_type_t
*ref
)
2551 free( ref
->track_ID
);
2555 static void isom_remove_tref( isom_tref_t
*tref
)
2559 lsmash_remove_list( tref
->ref_list
, isom_remove_track_reference_type
);
2560 isom_remove_box( tref
, isom_trak_entry_t
);
2563 static void isom_remove_mdhd( isom_mdhd_t
*mdhd
)
2567 isom_remove_box( mdhd
, isom_mdia_t
);
2570 static void isom_remove_vmhd( isom_vmhd_t
*vmhd
)
2574 isom_remove_box( vmhd
, isom_minf_t
);
2577 static void isom_remove_smhd( isom_smhd_t
*smhd
)
2581 isom_remove_box( smhd
, isom_minf_t
);
2584 static void isom_remove_hmhd( isom_hmhd_t
*hmhd
)
2588 isom_remove_box( hmhd
, isom_minf_t
);
2591 static void isom_remove_nmhd( isom_nmhd_t
*nmhd
)
2595 isom_remove_box( nmhd
, isom_minf_t
);
2598 static void isom_remove_gmin( isom_gmin_t
*gmin
)
2602 isom_remove_box( gmin
, isom_gmhd_t
);
2605 static void isom_remove_text( isom_text_t
*text
)
2609 isom_remove_box( text
, isom_gmhd_t
);
2612 static void isom_remove_gmhd( isom_gmhd_t
*gmhd
)
2616 isom_remove_gmin( gmhd
->gmin
);
2617 isom_remove_text( gmhd
->text
);
2618 isom_remove_box( gmhd
, isom_minf_t
);
2621 static void isom_remove_hdlr( isom_hdlr_t
*hdlr
)
2625 if( hdlr
->componentName
)
2626 free( hdlr
->componentName
);
2629 if( hdlr
->parent
->type
== ISOM_BOX_TYPE_MDIA
)
2630 isom_remove_box( hdlr
, isom_mdia_t
);
2631 else if( hdlr
->parent
->type
== ISOM_BOX_TYPE_META
)
2632 isom_remove_box( hdlr
, isom_meta_t
);
2633 else if( hdlr
->parent
->type
== ISOM_BOX_TYPE_MINF
)
2634 isom_remove_box( hdlr
, isom_minf_t
);
2642 void isom_remove_clap( isom_clap_t
*clap
)
2646 isom_remove_box( clap
, isom_visual_entry_t
);
2649 void isom_remove_pasp( isom_pasp_t
*pasp
)
2653 isom_remove_box( pasp
, isom_visual_entry_t
);
2656 void isom_remove_colr( isom_colr_t
*colr
)
2660 isom_remove_box( colr
, isom_visual_entry_t
);
2663 void isom_remove_stsl( isom_stsl_t
*stsl
)
2667 isom_remove_box( stsl
, isom_visual_entry_t
);
2670 static void isom_remove_esds( isom_esds_t
*esds
)
2674 mp4sys_remove_ES_Descriptor( esds
->ES
);
2677 switch( esds
->parent
->type
)
2679 case ISOM_CODEC_TYPE_MP4V_VIDEO
:
2680 isom_remove_box( esds
, isom_visual_entry_t
);
2682 case ISOM_CODEC_TYPE_MP4A_AUDIO
:
2683 case ISOM_CODEC_TYPE_M4AE_AUDIO
:
2684 isom_remove_box( esds
, isom_audio_entry_t
);
2686 case QT_BOX_TYPE_WAVE
:
2687 isom_remove_box( esds
, isom_wave_t
);
2689 case ISOM_CODEC_TYPE_MP4S_SYSTEM
:
2690 isom_remove_box( esds
, isom_mp4s_entry_t
);
2700 void isom_remove_avcC( isom_avcC_t
*avcC
)
2704 lsmash_remove_list( avcC
->sequenceParameterSets
, isom_remove_avcC_ps
);
2705 lsmash_remove_list( avcC
->pictureParameterSets
, isom_remove_avcC_ps
);
2706 lsmash_remove_list( avcC
->sequenceParameterSetExt
, isom_remove_avcC_ps
);
2707 isom_remove_box( avcC
, isom_visual_entry_t
);
2710 void isom_remove_btrt( isom_btrt_t
*btrt
)
2714 isom_remove_box( btrt
, isom_visual_entry_t
);
2717 static void isom_remove_visual_extensions( isom_visual_entry_t
*visual
)
2721 isom_remove_clap( visual
->clap
);
2722 isom_remove_pasp( visual
->pasp
);
2723 isom_remove_colr( visual
->colr
);
2724 isom_remove_stsl( visual
->stsl
);
2725 isom_remove_esds( visual
->esds
);
2726 isom_remove_avcC( visual
->avcC
);
2727 isom_remove_btrt( visual
->btrt
);
2730 static void isom_remove_font_record( isom_font_record_t
*font_record
)
2734 if( font_record
->font_name
)
2735 free( font_record
->font_name
);
2736 free( font_record
);
2739 void isom_remove_ftab( isom_ftab_t
*ftab
)
2743 lsmash_remove_list( ftab
->list
, isom_remove_font_record
);
2744 isom_remove_box( ftab
, isom_tx3g_entry_t
);
2747 void isom_remove_frma( isom_frma_t
*frma
)
2751 isom_remove_box( frma
, isom_wave_t
);
2754 void isom_remove_enda( isom_enda_t
*enda
)
2758 isom_remove_box( enda
, isom_wave_t
);
2761 void isom_remove_mp4a( isom_mp4a_t
*mp4a
)
2765 isom_remove_box( mp4a
, isom_wave_t
);
2768 void isom_remove_terminator( isom_terminator_t
*terminator
)
2772 isom_remove_box( terminator
, isom_wave_t
);
2775 void isom_remove_wave( isom_wave_t
*wave
)
2779 isom_remove_frma( wave
->frma
);
2780 isom_remove_enda( wave
->enda
);
2781 isom_remove_mp4a( wave
->mp4a
);
2782 isom_remove_esds( wave
->esds
);
2783 isom_remove_terminator( wave
->terminator
);
2785 free( wave
->exdata
);
2786 isom_remove_box( wave
, isom_audio_entry_t
);
2789 void isom_remove_chan( isom_chan_t
*chan
)
2793 if( chan
->channelDescriptions
)
2794 free( chan
->channelDescriptions
);
2795 isom_remove_box( chan
, isom_audio_entry_t
);
2798 void isom_remove_sample_description( isom_sample_entry_t
*sample
)
2802 switch( sample
->type
)
2804 case ISOM_CODEC_TYPE_AVC1_VIDEO
:
2805 case ISOM_CODEC_TYPE_AVC2_VIDEO
:
2806 case ISOM_CODEC_TYPE_AVCP_VIDEO
:
2807 case ISOM_CODEC_TYPE_SVC1_VIDEO
:
2808 case ISOM_CODEC_TYPE_MVC1_VIDEO
:
2809 case ISOM_CODEC_TYPE_MVC2_VIDEO
:
2810 case ISOM_CODEC_TYPE_MP4V_VIDEO
:
2811 case ISOM_CODEC_TYPE_DRAC_VIDEO
:
2812 case ISOM_CODEC_TYPE_ENCV_VIDEO
:
2813 case ISOM_CODEC_TYPE_MJP2_VIDEO
:
2814 case ISOM_CODEC_TYPE_S263_VIDEO
:
2815 case ISOM_CODEC_TYPE_VC_1_VIDEO
:
2817 isom_visual_entry_t
*visual
= (isom_visual_entry_t
*)sample
;
2818 isom_remove_visual_extensions( (isom_visual_entry_t
*)visual
);
2822 case ISOM_CODEC_TYPE_MP4A_AUDIO
:
2823 case ISOM_CODEC_TYPE_AC_3_AUDIO
:
2824 case ISOM_CODEC_TYPE_ALAC_AUDIO
:
2825 case ISOM_CODEC_TYPE_SAMR_AUDIO
:
2826 case ISOM_CODEC_TYPE_SAWB_AUDIO
:
2827 case QT_CODEC_TYPE_23NI_AUDIO
:
2828 case QT_CODEC_TYPE_NONE_AUDIO
:
2829 case QT_CODEC_TYPE_LPCM_AUDIO
:
2830 case QT_CODEC_TYPE_RAW_AUDIO
:
2831 case QT_CODEC_TYPE_SOWT_AUDIO
:
2832 case QT_CODEC_TYPE_TWOS_AUDIO
:
2833 case QT_CODEC_TYPE_FL32_AUDIO
:
2834 case QT_CODEC_TYPE_FL64_AUDIO
:
2835 case QT_CODEC_TYPE_IN24_AUDIO
:
2836 case QT_CODEC_TYPE_IN32_AUDIO
:
2837 case QT_CODEC_TYPE_NOT_SPECIFIED
:
2838 case ISOM_CODEC_TYPE_DRA1_AUDIO
:
2839 case ISOM_CODEC_TYPE_DTSC_AUDIO
:
2840 case ISOM_CODEC_TYPE_DTSH_AUDIO
:
2841 case ISOM_CODEC_TYPE_DTSL_AUDIO
:
2842 case ISOM_CODEC_TYPE_EC_3_AUDIO
:
2843 case ISOM_CODEC_TYPE_ENCA_AUDIO
:
2844 case ISOM_CODEC_TYPE_G719_AUDIO
:
2845 case ISOM_CODEC_TYPE_G726_AUDIO
:
2846 case ISOM_CODEC_TYPE_M4AE_AUDIO
:
2847 case ISOM_CODEC_TYPE_MLPA_AUDIO
:
2848 //case ISOM_CODEC_TYPE_RAW_AUDIO :
2849 case ISOM_CODEC_TYPE_SAWP_AUDIO
:
2850 case ISOM_CODEC_TYPE_SEVC_AUDIO
:
2851 case ISOM_CODEC_TYPE_SQCP_AUDIO
:
2852 case ISOM_CODEC_TYPE_SSMV_AUDIO
:
2853 //case ISOM_CODEC_TYPE_TWOS_AUDIO :
2855 isom_audio_entry_t
*audio
= (isom_audio_entry_t
*)sample
;
2856 isom_remove_esds( audio
->esds
);
2857 isom_remove_wave( audio
->wave
);
2858 isom_remove_chan( audio
->chan
);
2860 free( audio
->exdata
);
2864 case ISOM_CODEC_TYPE_FDP_HINT
:
2865 case ISOM_CODEC_TYPE_M2TS_HINT
:
2866 case ISOM_CODEC_TYPE_PM2T_HINT
:
2867 case ISOM_CODEC_TYPE_PRTP_HINT
:
2868 case ISOM_CODEC_TYPE_RM2T_HINT
:
2869 case ISOM_CODEC_TYPE_RRTP_HINT
:
2870 case ISOM_CODEC_TYPE_RSRP_HINT
:
2871 case ISOM_CODEC_TYPE_RTP_HINT
:
2872 case ISOM_CODEC_TYPE_SM2T_HINT
:
2873 case ISOM_CODEC_TYPE_SRTP_HINT
:
2875 isom_hint_entry_t
*hint
= (isom_hint_entry_t
*)sample
;
2881 case ISOM_CODEC_TYPE_IXSE_META
:
2882 case ISOM_CODEC_TYPE_METT_META
:
2883 case ISOM_CODEC_TYPE_METX_META
:
2884 case ISOM_CODEC_TYPE_MLIX_META
:
2885 case ISOM_CODEC_TYPE_OKSD_META
:
2886 case ISOM_CODEC_TYPE_SVCM_META
:
2887 //case ISOM_CODEC_TYPE_TEXT_META :
2888 case ISOM_CODEC_TYPE_URIM_META
:
2889 case ISOM_CODEC_TYPE_XML_META
:
2891 isom_metadata_entry_t
*metadata
= (isom_metadata_entry_t
*)sample
;
2895 case ISOM_CODEC_TYPE_TX3G_TEXT
:
2897 isom_tx3g_entry_t
*tx3g
= (isom_tx3g_entry_t
*)sample
;
2899 isom_remove_ftab( tx3g
->ftab
);
2903 case QT_CODEC_TYPE_TEXT_TEXT
:
2905 isom_text_entry_t
*text
= (isom_text_entry_t
*)sample
;
2906 if( text
->font_name
)
2907 free( text
->font_name
);
2911 case ISOM_CODEC_TYPE_MP4S_SYSTEM
:
2913 isom_mp4s_entry_t
*mp4s
= (isom_mp4s_entry_t
*)sample
;
2914 isom_remove_esds( mp4s
->esds
);
2923 static void isom_remove_stsd( isom_stsd_t
*stsd
)
2927 lsmash_remove_list( stsd
->list
, isom_remove_sample_description
);
2928 isom_remove_box( stsd
, isom_stbl_t
);
2931 static void isom_remove_stts( isom_stts_t
*stts
)
2935 lsmash_remove_list( stts
->list
, NULL
);
2936 isom_remove_box( stts
, isom_stbl_t
);
2939 static void isom_remove_ctts( isom_ctts_t
*ctts
)
2943 lsmash_remove_list( ctts
->list
, NULL
);
2944 isom_remove_box( ctts
, isom_stbl_t
);
2947 static void isom_remove_cslg( isom_cslg_t
*cslg
)
2951 isom_remove_box( cslg
, isom_stbl_t
);
2954 static void isom_remove_stsc( isom_stsc_t
*stsc
)
2958 lsmash_remove_list( stsc
->list
, NULL
);
2959 isom_remove_box( stsc
, isom_stbl_t
);
2962 static void isom_remove_stsz( isom_stsz_t
*stsz
)
2966 lsmash_remove_list( stsz
->list
, NULL
);
2967 isom_remove_box( stsz
, isom_stbl_t
);
2970 static void isom_remove_stss( isom_stss_t
*stss
)
2974 lsmash_remove_list( stss
->list
, NULL
);
2975 isom_remove_box( stss
, isom_stbl_t
);
2978 static void isom_remove_stps( isom_stps_t
*stps
)
2982 lsmash_remove_list( stps
->list
, NULL
);
2983 isom_remove_box( stps
, isom_stbl_t
);
2986 static void isom_remove_sdtp( isom_sdtp_t
*sdtp
)
2990 lsmash_remove_list( sdtp
->list
, NULL
);
2991 isom_remove_box( sdtp
, isom_stbl_t
);
2994 static void isom_remove_stco( isom_stco_t
*stco
)
2998 lsmash_remove_list( stco
->list
, NULL
);
2999 isom_remove_box( stco
, isom_stbl_t
);
3002 static void isom_remove_sgpd( isom_sgpd_entry_t
*sgpd
)
3006 lsmash_remove_list( sgpd
->list
, NULL
);
3010 static void isom_remove_sbgp( isom_sbgp_entry_t
*sbgp
)
3014 lsmash_remove_list( sbgp
->list
, NULL
);
3018 static void isom_remove_stbl( isom_stbl_t
*stbl
)
3022 isom_remove_stsd( stbl
->stsd
);
3023 isom_remove_stts( stbl
->stts
);
3024 isom_remove_ctts( stbl
->ctts
);
3025 isom_remove_cslg( stbl
->cslg
);
3026 isom_remove_stsc( stbl
->stsc
);
3027 isom_remove_stsz( stbl
->stsz
);
3028 isom_remove_stss( stbl
->stss
);
3029 isom_remove_stps( stbl
->stps
);
3030 isom_remove_sdtp( stbl
->sdtp
);
3031 isom_remove_stco( stbl
->stco
);
3032 lsmash_remove_list( stbl
->sgpd_list
, isom_remove_sgpd
);
3033 lsmash_remove_list( stbl
->sbgp_list
, isom_remove_sbgp
);
3034 isom_remove_box( stbl
, isom_minf_t
);
3037 static void isom_remove_dref( isom_dref_t
*dref
)
3046 for( lsmash_entry_t
*entry
= dref
->list
->head
; entry
; )
3048 isom_dref_entry_t
*data
= (isom_dref_entry_t
*)entry
->data
;
3053 if( data
->location
)
3054 free( data
->location
);
3057 lsmash_entry_t
*next
= entry
->next
;
3062 isom_remove_box( dref
, isom_dinf_t
);
3065 static void isom_remove_dinf( isom_dinf_t
*dinf
)
3069 isom_remove_dref( dinf
->dref
);
3070 isom_remove_box( dinf
, isom_minf_t
);
3073 static void isom_remove_minf( isom_minf_t
*minf
)
3077 isom_remove_vmhd( minf
->vmhd
);
3078 isom_remove_smhd( minf
->smhd
);
3079 isom_remove_hmhd( minf
->hmhd
);
3080 isom_remove_nmhd( minf
->nmhd
);
3081 isom_remove_gmhd( minf
->gmhd
);
3082 isom_remove_hdlr( minf
->hdlr
);
3083 isom_remove_dinf( minf
->dinf
);
3084 isom_remove_stbl( minf
->stbl
);
3085 isom_remove_box( minf
, isom_mdia_t
);
3088 static void isom_remove_mdia( isom_mdia_t
*mdia
)
3092 isom_remove_mdhd( mdia
->mdhd
);
3093 isom_remove_minf( mdia
->minf
);
3094 isom_remove_hdlr( mdia
->hdlr
);
3095 isom_remove_box( mdia
, isom_trak_entry_t
);
3098 static void isom_remove_chpl( isom_chpl_t
*chpl
)
3107 for( lsmash_entry_t
*entry
= chpl
->list
->head
; entry
; )
3109 isom_chpl_entry_t
*data
= (isom_chpl_entry_t
*)entry
->data
;
3112 if( data
->chapter_name
)
3113 free( data
->chapter_name
);
3116 lsmash_entry_t
*next
= entry
->next
;
3121 isom_remove_box( chpl
, isom_udta_t
);
3124 static void isom_remove_udta( isom_udta_t
*udta
)
3128 isom_remove_chpl( udta
->chpl
);
3131 if( udta
->parent
->type
== ISOM_BOX_TYPE_MOOV
)
3132 isom_remove_box( udta
, isom_moov_t
);
3133 else if( udta
->parent
->type
== ISOM_BOX_TYPE_TRAK
)
3134 isom_remove_box( udta
, isom_trak_entry_t
);
3142 static void isom_remove_mean( isom_mean_t
*mean
)
3146 if( mean
->meaning_string
)
3147 free( mean
->meaning_string
);
3148 isom_remove_box( mean
, isom_metaitem_t
);
3151 static void isom_remove_name( isom_name_t
*name
)
3157 isom_remove_box( name
, isom_metaitem_t
);
3160 static void isom_remove_data( isom_data_t
*data
)
3165 free( data
->value
);
3166 isom_remove_box( data
, isom_metaitem_t
);
3169 static void isom_remove_metaitem( isom_metaitem_t
*metaitem
)
3173 isom_remove_mean( metaitem
->mean
);
3174 isom_remove_name( metaitem
->name
);
3175 isom_remove_data( metaitem
->data
);
3179 static void isom_remove_ilst( isom_ilst_t
*ilst
)
3183 lsmash_remove_list( ilst
->item_list
, isom_remove_metaitem
);
3184 isom_remove_box( ilst
, isom_meta_t
);
3187 static void isom_remove_meta( isom_meta_t
*meta
)
3191 isom_remove_hdlr( meta
->hdlr
);
3192 isom_remove_dinf( meta
->dinf
);
3193 isom_remove_ilst( meta
->ilst
);
3196 if( !meta
->parent
->type
)
3197 isom_remove_box( meta
, lsmash_root_t
);
3198 else if( meta
->parent
->type
== ISOM_BOX_TYPE_MOOV
)
3199 isom_remove_box( meta
, isom_moov_t
);
3200 else if( meta
->parent
->type
== ISOM_BOX_TYPE_TRAK
)
3201 isom_remove_box( meta
, isom_trak_entry_t
);
3202 else if( meta
->parent
->type
== ISOM_BOX_TYPE_UDTA
)
3203 isom_remove_box( meta
, isom_udta_t
);
3211 static void isom_remove_sample_pool( isom_sample_pool_t
*pool
);
3213 static void isom_remove_trak( isom_trak_entry_t
*trak
)
3217 isom_remove_tkhd( trak
->tkhd
);
3218 isom_remove_tapt( trak
->tapt
);
3219 isom_remove_edts( trak
->edts
);
3220 isom_remove_tref( trak
->tref
);
3221 isom_remove_mdia( trak
->mdia
);
3222 isom_remove_udta( trak
->udta
);
3223 isom_remove_meta( trak
->meta
);
3226 isom_remove_sample_pool( trak
->cache
->chunk
.pool
);
3227 lsmash_remove_list( trak
->cache
->roll
.pool
, NULL
);
3228 if( trak
->cache
->rap
)
3229 free( trak
->cache
->rap
);
3230 free( trak
->cache
);
3232 free( trak
); /* Note: the list that contains this trak still has the address of the entry. */
3235 static void isom_remove_iods( isom_iods_t
*iods
)
3239 mp4sys_remove_ObjectDescriptor( iods
->OD
);
3240 isom_remove_box( iods
, isom_moov_t
);
3243 static void isom_remove_mehd( isom_mehd_t
*mehd
)
3247 isom_remove_box( mehd
, isom_mvex_t
);
3250 static void isom_remove_mvex( isom_mvex_t
*mvex
)
3254 isom_remove_mehd( mvex
->mehd
);
3255 lsmash_remove_list( mvex
->trex_list
, NULL
);
3256 isom_remove_box( mvex
, isom_moov_t
);
3259 static void isom_remove_moov( lsmash_root_t
*root
)
3261 if( !root
|| !root
->moov
)
3263 isom_moov_t
*moov
= root
->moov
;
3266 isom_remove_iods( moov
->iods
);
3267 lsmash_remove_list( moov
->trak_list
, isom_remove_trak
);
3268 isom_remove_udta( moov
->udta
);
3269 isom_remove_meta( moov
->meta
);
3270 isom_remove_mvex( moov
->mvex
);
3275 static void isom_remove_mfhd( isom_mfhd_t
*mfhd
)
3279 isom_remove_box( mfhd
, isom_moof_entry_t
);
3282 static void isom_remove_tfhd( isom_tfhd_t
*tfhd
)
3286 isom_remove_box( tfhd
, isom_traf_entry_t
);
3289 static void isom_remove_trun( isom_trun_entry_t
*trun
)
3293 lsmash_remove_list( trun
->optional
, NULL
);
3294 free( trun
); /* Note: the list that contains this trun still has the address of the entry. */
3297 static void isom_remove_traf( isom_traf_entry_t
*traf
)
3301 isom_remove_tfhd( traf
->tfhd
);
3302 lsmash_remove_list( traf
->trun_list
, isom_remove_trun
);
3303 free( traf
); /* Note: the list that contains this traf still has the address of the entry. */
3306 static void isom_remove_moof( isom_moof_entry_t
*moof
)
3310 isom_remove_mfhd( moof
->mfhd
);
3311 lsmash_remove_list( moof
->traf_list
, isom_remove_traf
);
3315 static void isom_remove_mdat( isom_mdat_t
*mdat
)
3319 isom_remove_box( mdat
, lsmash_root_t
);
3322 static void isom_remove_free( isom_free_t
*skip
)
3328 lsmash_root_t
*root
= (lsmash_root_t
*)skip
->parent
;
3333 static void isom_remove_tfra( isom_tfra_entry_t
*tfra
)
3337 lsmash_remove_list( tfra
->list
, NULL
);
3341 static void isom_remove_mfro( isom_mfro_t
*mfro
)
3345 isom_remove_box( mfro
, isom_mfra_t
);
3348 static void isom_remove_mfra( isom_mfra_t
*mfra
)
3352 lsmash_remove_list( mfra
->tfra_list
, isom_remove_tfra
);
3353 isom_remove_mfro( mfra
->mfro
);
3354 isom_remove_box( mfra
, lsmash_root_t
);
3358 static int isom_write_tkhd( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3360 isom_tkhd_t
*tkhd
= trak
->tkhd
;
3363 isom_bs_put_box_common( bs
, tkhd
);
3366 lsmash_bs_put_be64( bs
, tkhd
->creation_time
);
3367 lsmash_bs_put_be64( bs
, tkhd
->modification_time
);
3368 lsmash_bs_put_be32( bs
, tkhd
->track_ID
);
3369 lsmash_bs_put_be32( bs
, tkhd
->reserved1
);
3370 lsmash_bs_put_be64( bs
, tkhd
->duration
);
3374 lsmash_bs_put_be32( bs
, (uint32_t)tkhd
->creation_time
);
3375 lsmash_bs_put_be32( bs
, (uint32_t)tkhd
->modification_time
);
3376 lsmash_bs_put_be32( bs
, tkhd
->track_ID
);
3377 lsmash_bs_put_be32( bs
, tkhd
->reserved1
);
3378 lsmash_bs_put_be32( bs
, (uint32_t)tkhd
->duration
);
3380 lsmash_bs_put_be32( bs
, tkhd
->reserved2
[0] );
3381 lsmash_bs_put_be32( bs
, tkhd
->reserved2
[1] );
3382 lsmash_bs_put_be16( bs
, tkhd
->layer
);
3383 lsmash_bs_put_be16( bs
, tkhd
->alternate_group
);
3384 lsmash_bs_put_be16( bs
, tkhd
->volume
);
3385 lsmash_bs_put_be16( bs
, tkhd
->reserved3
);
3386 for( uint32_t i
= 0; i
< 9; i
++ )
3387 lsmash_bs_put_be32( bs
, tkhd
->matrix
[i
] );
3388 lsmash_bs_put_be32( bs
, tkhd
->width
);
3389 lsmash_bs_put_be32( bs
, tkhd
->height
);
3390 return lsmash_bs_write_data( bs
);
3393 static int isom_write_clef( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3395 isom_clef_t
*clef
= trak
->tapt
->clef
;
3398 isom_bs_put_box_common( bs
, clef
);
3399 lsmash_bs_put_be32( bs
, clef
->width
);
3400 lsmash_bs_put_be32( bs
, clef
->height
);
3401 return lsmash_bs_write_data( bs
);
3404 static int isom_write_prof( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3406 isom_prof_t
*prof
= trak
->tapt
->prof
;
3409 isom_bs_put_box_common( bs
, prof
);
3410 lsmash_bs_put_be32( bs
, prof
->width
);
3411 lsmash_bs_put_be32( bs
, prof
->height
);
3412 return lsmash_bs_write_data( bs
);
3415 static int isom_write_enof( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3417 isom_enof_t
*enof
= trak
->tapt
->enof
;
3420 isom_bs_put_box_common( bs
, enof
);
3421 lsmash_bs_put_be32( bs
, enof
->width
);
3422 lsmash_bs_put_be32( bs
, enof
->height
);
3423 return lsmash_bs_write_data( bs
);
3426 static int isom_write_tapt( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3428 isom_tapt_t
*tapt
= trak
->tapt
;
3431 isom_bs_put_box_common( bs
, tapt
);
3432 if( lsmash_bs_write_data( bs
) )
3434 if( isom_write_clef( bs
, trak
)
3435 || isom_write_prof( bs
, trak
)
3436 || isom_write_enof( bs
, trak
) )
3441 static int isom_write_elst( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3443 isom_elst_t
*elst
= trak
->edts
->elst
;
3446 if( !elst
->list
->entry_count
)
3448 if( elst
->root
->fragment
&& elst
->root
->bs
->stream
!= stdout
)
3449 elst
->pos
= elst
->root
->bs
->written
; /* Remember to rewrite entries. */
3450 isom_bs_put_box_common( bs
, elst
);
3451 lsmash_bs_put_be32( bs
, elst
->list
->entry_count
);
3452 for( lsmash_entry_t
*entry
= elst
->list
->head
; entry
; entry
= entry
->next
)
3454 isom_elst_entry_t
*data
= (isom_elst_entry_t
*)entry
->data
;
3459 lsmash_bs_put_be64( bs
, data
->segment_duration
);
3460 lsmash_bs_put_be64( bs
, data
->media_time
);
3464 lsmash_bs_put_be32( bs
, (uint32_t)data
->segment_duration
);
3465 lsmash_bs_put_be32( bs
, (uint32_t)data
->media_time
);
3467 lsmash_bs_put_be32( bs
, data
->media_rate
);
3469 return lsmash_bs_write_data( bs
);
3472 static int isom_write_edts( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3474 isom_edts_t
*edts
= trak
->edts
;
3477 isom_bs_put_box_common( bs
, edts
);
3478 if( lsmash_bs_write_data( bs
) )
3480 return isom_write_elst( bs
, trak
);
3483 static int isom_write_tref( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3485 isom_tref_t
*tref
= trak
->tref
;
3488 isom_bs_put_box_common( bs
, tref
);
3489 if( tref
->ref_list
)
3490 for( lsmash_entry_t
*entry
= tref
->ref_list
->head
; entry
; entry
= entry
->next
)
3492 isom_tref_type_t
*ref
= (isom_tref_type_t
*)entry
->data
;
3495 isom_bs_put_box_common( bs
, ref
);
3496 for( uint32_t i
= 0; i
< ref
->ref_count
; i
++ )
3497 lsmash_bs_put_be32( bs
, ref
->track_ID
[i
] );
3499 return lsmash_bs_write_data( bs
);
3502 static int isom_write_mdhd( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3504 isom_mdhd_t
*mdhd
= trak
->mdia
->mdhd
;
3507 isom_bs_put_box_common( bs
, mdhd
);
3510 lsmash_bs_put_be64( bs
, mdhd
->creation_time
);
3511 lsmash_bs_put_be64( bs
, mdhd
->modification_time
);
3512 lsmash_bs_put_be32( bs
, mdhd
->timescale
);
3513 lsmash_bs_put_be64( bs
, mdhd
->duration
);
3517 lsmash_bs_put_be32( bs
, (uint32_t)mdhd
->creation_time
);
3518 lsmash_bs_put_be32( bs
, (uint32_t)mdhd
->modification_time
);
3519 lsmash_bs_put_be32( bs
, mdhd
->timescale
);
3520 lsmash_bs_put_be32( bs
, (uint32_t)mdhd
->duration
);
3522 lsmash_bs_put_be16( bs
, mdhd
->language
);
3523 lsmash_bs_put_be16( bs
, mdhd
->quality
);
3524 return lsmash_bs_write_data( bs
);
3527 static int isom_write_hdlr( lsmash_bs_t
*bs
, isom_hdlr_t
*hdlr
, uint32_t parent_type
)
3530 return parent_type
== ISOM_BOX_TYPE_MINF
? 0 : -1;
3531 isom_bs_put_box_common( bs
, hdlr
);
3532 lsmash_bs_put_be32( bs
, hdlr
->componentType
);
3533 lsmash_bs_put_be32( bs
, hdlr
->componentSubtype
);
3534 lsmash_bs_put_be32( bs
, hdlr
->componentManufacturer
);
3535 lsmash_bs_put_be32( bs
, hdlr
->componentFlags
);
3536 lsmash_bs_put_be32( bs
, hdlr
->componentFlagsMask
);
3537 lsmash_bs_put_bytes( bs
, hdlr
->componentName
, hdlr
->componentName_length
);
3538 return lsmash_bs_write_data( bs
);
3541 static int isom_write_vmhd( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3543 isom_vmhd_t
*vmhd
= trak
->mdia
->minf
->vmhd
;
3546 isom_bs_put_box_common( bs
, vmhd
);
3547 lsmash_bs_put_be16( bs
, vmhd
->graphicsmode
);
3548 for( uint32_t i
= 0; i
< 3; i
++ )
3549 lsmash_bs_put_be16( bs
, vmhd
->opcolor
[i
] );
3550 return lsmash_bs_write_data( bs
);
3553 static int isom_write_smhd( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3555 isom_smhd_t
*smhd
= trak
->mdia
->minf
->smhd
;
3558 isom_bs_put_box_common( bs
, smhd
);
3559 lsmash_bs_put_be16( bs
, smhd
->balance
);
3560 lsmash_bs_put_be16( bs
, smhd
->reserved
);
3561 return lsmash_bs_write_data( bs
);
3564 static int isom_write_hmhd( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3566 isom_hmhd_t
*hmhd
= trak
->mdia
->minf
->hmhd
;
3569 isom_bs_put_box_common( bs
, hmhd
);
3570 lsmash_bs_put_be16( bs
, hmhd
->maxPDUsize
);
3571 lsmash_bs_put_be16( bs
, hmhd
->avgPDUsize
);
3572 lsmash_bs_put_be32( bs
, hmhd
->maxbitrate
);
3573 lsmash_bs_put_be32( bs
, hmhd
->avgbitrate
);
3574 lsmash_bs_put_be32( bs
, hmhd
->reserved
);
3575 return lsmash_bs_write_data( bs
);
3578 static int isom_write_nmhd( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3580 isom_nmhd_t
*nmhd
= trak
->mdia
->minf
->nmhd
;
3583 isom_bs_put_box_common( bs
, nmhd
);
3584 return lsmash_bs_write_data( bs
);
3587 static int isom_write_gmin( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3589 isom_gmin_t
*gmin
= trak
->mdia
->minf
->gmhd
->gmin
;
3592 isom_bs_put_box_common( bs
, gmin
);
3593 lsmash_bs_put_be16( bs
, gmin
->graphicsmode
);
3594 for( uint32_t i
= 0; i
< 3; i
++ )
3595 lsmash_bs_put_be16( bs
, gmin
->opcolor
[i
] );
3596 lsmash_bs_put_be16( bs
, gmin
->balance
);
3597 lsmash_bs_put_be16( bs
, gmin
->reserved
);
3598 return lsmash_bs_write_data( bs
);
3601 static int isom_write_text( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3603 isom_text_t
*text
= trak
->mdia
->minf
->gmhd
->text
;
3606 isom_bs_put_box_common( bs
, text
);
3607 for( uint32_t i
= 0; i
< 9; i
++ )
3608 lsmash_bs_put_be32( bs
, text
->matrix
[i
] );
3609 return lsmash_bs_write_data( bs
);
3612 static int isom_write_gmhd( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
3614 isom_gmhd_t
*gmhd
= trak
->mdia
->minf
->gmhd
;
3617 isom_bs_put_box_common( bs
, gmhd
);
3618 if( isom_write_gmin( bs
, trak
) ||
3619 isom_write_text( bs
, trak
) )
3624 static int isom_write_dref( lsmash_bs_t
*bs
, isom_dref_t
*dref
)
3626 if( !dref
|| !dref
->list
)
3628 isom_bs_put_box_common( bs
, dref
);
3629 lsmash_bs_put_be32( bs
, dref
->list
->entry_count
);
3630 for( lsmash_entry_t
*entry
= dref
->list
->head
; entry
; entry
= entry
->next
)
3632 isom_dref_entry_t
*data
= (isom_dref_entry_t
*)entry
->data
;
3635 isom_bs_put_box_common( bs
, data
);
3636 if( data
->type
== ISOM_BOX_TYPE_URN
)
3637 lsmash_bs_put_bytes( bs
, data
->name
, data
->name_length
);
3638 lsmash_bs_put_bytes( bs
, data
->location
, data
->location_length
);
3640 return lsmash_bs_write_data( bs
);
3643 static int isom_write_dinf( lsmash_bs_t
*bs
, isom_dinf_t
*dinf
, uint32_t parent_type
)
3646 return parent_type
== ISOM_BOX_TYPE_MINF
? -1 : 0;
3647 isom_bs_put_box_common( bs
, dinf
);
3648 if( lsmash_bs_write_data( bs
) )
3650 return isom_write_dref( bs
, dinf
->dref
);
3653 static int isom_write_pasp( lsmash_bs_t
*bs
, isom_pasp_t
*pasp
)
3657 isom_bs_put_box_common( bs
, pasp
);
3658 lsmash_bs_put_be32( bs
, pasp
->hSpacing
);
3659 lsmash_bs_put_be32( bs
, pasp
->vSpacing
);
3660 return lsmash_bs_write_data( bs
);
3663 static int isom_write_clap( lsmash_bs_t
*bs
, isom_clap_t
*clap
)
3667 isom_bs_put_box_common( bs
, clap
);
3668 lsmash_bs_put_be32( bs
, clap
->cleanApertureWidthN
);
3669 lsmash_bs_put_be32( bs
, clap
->cleanApertureWidthD
);
3670 lsmash_bs_put_be32( bs
, clap
->cleanApertureHeightN
);
3671 lsmash_bs_put_be32( bs
, clap
->cleanApertureHeightD
);
3672 lsmash_bs_put_be32( bs
, clap
->horizOffN
);
3673 lsmash_bs_put_be32( bs
, clap
->horizOffD
);
3674 lsmash_bs_put_be32( bs
, clap
->vertOffN
);
3675 lsmash_bs_put_be32( bs
, clap
->vertOffD
);
3676 return lsmash_bs_write_data( bs
);
3679 static int isom_write_colr( lsmash_bs_t
*bs
, isom_colr_t
*colr
)
3681 if( !colr
|| colr
->color_parameter_type
== QT_COLOR_PARAMETER_TYPE_PROF
)
3683 isom_bs_put_box_common( bs
, colr
);
3684 lsmash_bs_put_be32( bs
, colr
->color_parameter_type
);
3685 lsmash_bs_put_be16( bs
, colr
->primaries_index
);
3686 lsmash_bs_put_be16( bs
, colr
->transfer_function_index
);
3687 lsmash_bs_put_be16( bs
, colr
->matrix_index
);
3688 return lsmash_bs_write_data( bs
);
3691 static int isom_write_stsl( lsmash_bs_t
*bs
, isom_stsl_t
*stsl
)
3695 isom_bs_put_box_common( bs
, stsl
);
3696 lsmash_bs_put_byte( bs
, stsl
->constraint_flag
);
3697 lsmash_bs_put_byte( bs
, stsl
->scale_method
);
3698 lsmash_bs_put_be16( bs
, stsl
->display_center_x
);
3699 lsmash_bs_put_be16( bs
, stsl
->display_center_y
);
3700 return lsmash_bs_write_data( bs
);
3703 static int isom_write_esds( lsmash_bs_t
*bs
, isom_esds_t
*esds
)
3707 isom_bs_put_box_common( bs
, esds
);
3708 return mp4sys_write_ES_Descriptor( bs
, esds
->ES
);
3711 static int isom_put_ps_entries( lsmash_bs_t
*bs
, lsmash_entry_list_t
*list
)
3713 for( lsmash_entry_t
*entry
= list
->head
; entry
; entry
= entry
->next
)
3715 isom_avcC_ps_entry_t
*data
= (isom_avcC_ps_entry_t
*)entry
->data
;
3718 lsmash_bs_put_be16( bs
, data
->parameterSetLength
);
3719 lsmash_bs_put_bytes( bs
, data
->parameterSetNALUnit
, data
->parameterSetLength
);
3724 static int isom_write_avcC( lsmash_bs_t
*bs
, isom_avcC_t
*avcC
)
3728 if( !avcC
->sequenceParameterSets
|| !avcC
->pictureParameterSets
)
3730 isom_bs_put_box_common( bs
, avcC
);
3731 lsmash_bs_put_byte( bs
, avcC
->configurationVersion
);
3732 lsmash_bs_put_byte( bs
, avcC
->AVCProfileIndication
);
3733 lsmash_bs_put_byte( bs
, avcC
->profile_compatibility
);
3734 lsmash_bs_put_byte( bs
, avcC
->AVCLevelIndication
);
3735 lsmash_bs_put_byte( bs
, avcC
->lengthSizeMinusOne
| 0xfc ); /* upper 6-bits are reserved as 111111b */
3736 lsmash_bs_put_byte( bs
, avcC
->numOfSequenceParameterSets
| 0xe0 ); /* upper 3-bits are reserved as 111b */
3737 if( isom_put_ps_entries( bs
, avcC
->sequenceParameterSets
) )
3739 lsmash_bs_put_byte( bs
, avcC
->numOfPictureParameterSets
);
3740 if( isom_put_ps_entries( bs
, avcC
->pictureParameterSets
) )
3742 if( ISOM_REQUIRES_AVCC_EXTENSION( avcC
->AVCProfileIndication
) )
3744 lsmash_bs_put_byte( bs
, avcC
->chroma_format
| 0xfc ); /* upper 6-bits are reserved as 111111b */
3745 lsmash_bs_put_byte( bs
, avcC
->bit_depth_luma_minus8
| 0xf8 ); /* upper 5-bits are reserved as 11111b */
3746 lsmash_bs_put_byte( bs
, avcC
->bit_depth_chroma_minus8
| 0xf8 ); /* upper 5-bits are reserved as 11111b */
3747 lsmash_bs_put_byte( bs
, avcC
->numOfSequenceParameterSetExt
);
3748 if( isom_put_ps_entries( bs
, avcC
->sequenceParameterSetExt
) )
3751 return lsmash_bs_write_data( bs
);
3754 static int isom_write_btrt( lsmash_bs_t
*bs
, isom_btrt_t
*btrt
)
3758 isom_bs_put_box_common( bs
, btrt
);
3759 lsmash_bs_put_be32( bs
, btrt
->bufferSizeDB
);
3760 lsmash_bs_put_be32( bs
, btrt
->maxBitrate
);
3761 lsmash_bs_put_be32( bs
, btrt
->avgBitrate
);
3762 return lsmash_bs_write_data( bs
);
3765 static int isom_write_visual_extensions( lsmash_bs_t
*bs
, isom_visual_entry_t
*visual
)
3769 if( isom_write_clap( bs
, visual
->clap
)
3770 || isom_write_pasp( bs
, visual
->pasp
)
3771 || isom_write_colr( bs
, visual
->colr
)
3772 || isom_write_stsl( bs
, visual
->stsl
)
3773 || isom_write_esds( bs
, visual
->esds
)
3774 || isom_write_avcC( bs
, visual
->avcC
)
3775 || isom_write_btrt( bs
, visual
->btrt
) )
3780 static int isom_write_frma( lsmash_bs_t
*bs
, isom_frma_t
*frma
)
3784 isom_bs_put_box_common( bs
, frma
);
3785 lsmash_bs_put_be32( bs
, frma
->data_format
);
3786 return lsmash_bs_write_data( bs
);
3789 static int isom_write_enda( lsmash_bs_t
*bs
, isom_enda_t
*enda
)
3793 isom_bs_put_box_common( bs
, enda
);
3794 lsmash_bs_put_be16( bs
, enda
->littleEndian
);
3795 return lsmash_bs_write_data( bs
);
3798 static int isom_write_mp4a( lsmash_bs_t
*bs
, isom_mp4a_t
*mp4a
)
3802 isom_bs_put_box_common( bs
, mp4a
);
3803 lsmash_bs_put_be32( bs
, mp4a
->unknown
);
3804 return lsmash_bs_write_data( bs
);
3807 static int isom_write_terminator( lsmash_bs_t
*bs
, isom_terminator_t
*terminator
)
3811 isom_bs_put_box_common( bs
, terminator
);
3812 return lsmash_bs_write_data( bs
);
3815 static int isom_write_wave( lsmash_bs_t
*bs
, isom_wave_t
*wave
)
3819 isom_bs_put_box_common( bs
, wave
);
3820 if( lsmash_bs_write_data( bs
) )
3822 if( isom_write_frma( bs
, wave
->frma
)
3823 || isom_write_enda( bs
, wave
->enda
)
3824 || isom_write_mp4a( bs
, wave
->mp4a
) )
3826 lsmash_bs_put_bytes( bs
, wave
->exdata
, wave
->exdata_length
);
3827 if( lsmash_bs_write_data( bs
) )
3829 if( isom_write_esds( bs
, wave
->esds
) )
3831 return isom_write_terminator( bs
, wave
->terminator
);
3834 static int isom_write_chan( lsmash_bs_t
*bs
, isom_chan_t
*chan
)
3838 isom_bs_put_box_common( bs
, chan
);
3839 lsmash_bs_put_be32( bs
, chan
->channelLayoutTag
);
3840 lsmash_bs_put_be32( bs
, chan
->channelBitmap
);
3841 lsmash_bs_put_be32( bs
, chan
->numberChannelDescriptions
);
3842 if( chan
->channelDescriptions
)
3843 for( uint32_t i
= 0; i
< chan
->numberChannelDescriptions
; i
++ )
3845 isom_channel_description_t
*channelDescriptions
= (isom_channel_description_t
*)(&chan
->channelDescriptions
[i
]);
3846 if( !channelDescriptions
)
3848 lsmash_bs_put_be32( bs
, channelDescriptions
->channelLabel
);
3849 lsmash_bs_put_be32( bs
, channelDescriptions
->channelFlags
);
3850 lsmash_bs_put_be32( bs
, channelDescriptions
->coordinates
[0] );
3851 lsmash_bs_put_be32( bs
, channelDescriptions
->coordinates
[1] );
3852 lsmash_bs_put_be32( bs
, channelDescriptions
->coordinates
[2] );
3854 return lsmash_bs_write_data( bs
);
3857 static int isom_write_audio_extensions( lsmash_bs_t
*bs
, isom_audio_entry_t
*audio
)
3861 if( isom_write_esds( bs
, audio
->esds
)
3862 || isom_write_wave( bs
, audio
->wave
)
3863 || isom_write_chan( bs
, audio
->chan
) )
3868 static int isom_write_visual_entry( lsmash_bs_t
*bs
, lsmash_entry_t
*entry
)
3870 isom_visual_entry_t
*data
= (isom_visual_entry_t
*)entry
->data
;
3873 isom_bs_put_box_common( bs
, data
);
3874 lsmash_bs_put_bytes( bs
, data
->reserved
, 6 );
3875 lsmash_bs_put_be16( bs
, data
->data_reference_index
);
3876 lsmash_bs_put_be16( bs
, data
->version
);
3877 lsmash_bs_put_be16( bs
, data
->revision_level
);
3878 lsmash_bs_put_be32( bs
, data
->vendor
);
3879 lsmash_bs_put_be32( bs
, data
->temporalQuality
);
3880 lsmash_bs_put_be32( bs
, data
->spatialQuality
);
3881 lsmash_bs_put_be16( bs
, data
->width
);
3882 lsmash_bs_put_be16( bs
, data
->height
);
3883 lsmash_bs_put_be32( bs
, data
->horizresolution
);
3884 lsmash_bs_put_be32( bs
, data
->vertresolution
);
3885 lsmash_bs_put_be32( bs
, data
->dataSize
);
3886 lsmash_bs_put_be16( bs
, data
->frame_count
);
3887 lsmash_bs_put_bytes( bs
, data
->compressorname
, 32 );
3888 lsmash_bs_put_be16( bs
, data
->depth
);
3889 lsmash_bs_put_be16( bs
, data
->color_table_ID
);
3890 if( lsmash_bs_write_data( bs
) )
3892 return isom_write_visual_extensions( bs
, data
);
3895 static int isom_write_audio_entry( lsmash_bs_t
*bs
, lsmash_entry_t
*entry
)
3897 isom_audio_entry_t
*data
= (isom_audio_entry_t
*)entry
->data
;
3900 isom_bs_put_box_common( bs
, data
);
3901 lsmash_bs_put_bytes( bs
, data
->reserved
, 6 );
3902 lsmash_bs_put_be16( bs
, data
->data_reference_index
);
3903 lsmash_bs_put_be16( bs
, data
->version
);
3904 lsmash_bs_put_be16( bs
, data
->revision_level
);
3905 lsmash_bs_put_be32( bs
, data
->vendor
);
3906 lsmash_bs_put_be16( bs
, data
->channelcount
);
3907 lsmash_bs_put_be16( bs
, data
->samplesize
);
3908 lsmash_bs_put_be16( bs
, data
->compression_ID
);
3909 lsmash_bs_put_be16( bs
, data
->packet_size
);
3910 lsmash_bs_put_be32( bs
, data
->samplerate
);
3911 if( data
->version
== 1 )
3913 lsmash_bs_put_be32( bs
, data
->samplesPerPacket
);
3914 lsmash_bs_put_be32( bs
, data
->bytesPerPacket
);
3915 lsmash_bs_put_be32( bs
, data
->bytesPerFrame
);
3916 lsmash_bs_put_be32( bs
, data
->bytesPerSample
);
3918 else if( data
->version
== 2 )
3920 lsmash_bs_put_be32( bs
, data
->sizeOfStructOnly
);
3921 lsmash_bs_put_be64( bs
, data
->audioSampleRate
);
3922 lsmash_bs_put_be32( bs
, data
->numAudioChannels
);
3923 lsmash_bs_put_be32( bs
, data
->always7F000000
);
3924 lsmash_bs_put_be32( bs
, data
->constBitsPerChannel
);
3925 lsmash_bs_put_be32( bs
, data
->formatSpecificFlags
);
3926 lsmash_bs_put_be32( bs
, data
->constBytesPerAudioPacket
);
3927 lsmash_bs_put_be32( bs
, data
->constLPCMFramesPerAudioPacket
);
3929 lsmash_bs_put_bytes( bs
, data
->exdata
, data
->exdata_length
);
3930 if( lsmash_bs_write_data( bs
) )
3932 return isom_write_audio_extensions( bs
, data
);
3936 static int isom_write_hint_entry( lsmash_bs_t
*bs
, lsmash_entry_t
*entry
)
3938 isom_hint_entry_t
*data
= (isom_hint_entry_t
*)entry
->data
;
3941 isom_bs_put_box_common( bs
, data
);
3942 lsmash_bs_put_bytes( bs
, data
->reserved
, 6 );
3943 lsmash_bs_put_be16( bs
, data
->data_reference_index
);
3944 if( data
->data
&& data
->data_length
)
3945 lsmash_bs_put_bytes( bs
, data
->data
, data
->data_length
);
3946 return lsmash_bs_write_data( bs
);
3949 static int isom_write_metadata_entry( lsmash_bs_t
*bs
, lsmash_entry_t
*entry
)
3951 isom_metadata_entry_t
*data
= (isom_metadata_entry_t
*)entry
->data
;
3954 isom_bs_put_box_common( bs
, data
);
3955 lsmash_bs_put_bytes( bs
, data
->reserved
, 6 );
3956 lsmash_bs_put_be16( bs
, data
->data_reference_index
);
3957 return lsmash_bs_write_data( bs
);
3961 static int isom_write_text_entry( lsmash_bs_t
*bs
, lsmash_entry_t
*entry
)
3963 isom_text_entry_t
*data
= (isom_text_entry_t
*)entry
->data
;
3966 isom_bs_put_box_common( bs
, data
);
3967 lsmash_bs_put_bytes( bs
, data
->reserved
, 6 );
3968 lsmash_bs_put_be16( bs
, data
->data_reference_index
);
3969 lsmash_bs_put_be32( bs
, data
->displayFlags
);
3970 lsmash_bs_put_be32( bs
, data
->textJustification
);
3971 for( uint32_t i
= 0; i
< 3; i
++ )
3972 lsmash_bs_put_be16( bs
, data
->bgColor
[i
] );
3973 lsmash_bs_put_be16( bs
, data
->top
);
3974 lsmash_bs_put_be16( bs
, data
->left
);
3975 lsmash_bs_put_be16( bs
, data
->bottom
);
3976 lsmash_bs_put_be16( bs
, data
->right
);
3977 lsmash_bs_put_be32( bs
, data
->scrpStartChar
);
3978 lsmash_bs_put_be16( bs
, data
->scrpHeight
);
3979 lsmash_bs_put_be16( bs
, data
->scrpAscent
);
3980 lsmash_bs_put_be16( bs
, data
->scrpFont
);
3981 lsmash_bs_put_be16( bs
, data
->scrpFace
);
3982 lsmash_bs_put_be16( bs
, data
->scrpSize
);
3983 for( uint32_t i
= 0; i
< 3; i
++ )
3984 lsmash_bs_put_be16( bs
, data
->scrpColor
[i
] );
3985 lsmash_bs_put_byte( bs
, data
->font_name_length
);
3986 if( data
->font_name
&& data
->font_name_length
)
3987 lsmash_bs_put_bytes( bs
, data
->font_name
, data
->font_name_length
);
3988 return lsmash_bs_write_data( bs
);
3991 static int isom_put_ftab( lsmash_bs_t
*bs
, isom_ftab_t
*ftab
)
3993 if( !ftab
|| !ftab
->list
)
3995 isom_bs_put_box_common( bs
, ftab
);
3996 lsmash_bs_put_be16( bs
, ftab
->list
->entry_count
);
3997 for( lsmash_entry_t
*entry
= ftab
->list
->head
; entry
; entry
= entry
->next
)
3999 isom_font_record_t
*data
= (isom_font_record_t
*)entry
->data
;
4002 lsmash_bs_put_be16( bs
, data
->font_ID
);
4003 lsmash_bs_put_byte( bs
, data
->font_name_length
);
4004 if( data
->font_name
&& data
->font_name_length
)
4005 lsmash_bs_put_bytes( bs
, data
->font_name
, data
->font_name_length
);
4010 static int isom_write_tx3g_entry( lsmash_bs_t
*bs
, lsmash_entry_t
*entry
)
4012 isom_tx3g_entry_t
*data
= (isom_tx3g_entry_t
*)entry
->data
;
4015 isom_bs_put_box_common( bs
, data
);
4016 lsmash_bs_put_bytes( bs
, data
->reserved
, 6 );
4017 lsmash_bs_put_be16( bs
, data
->data_reference_index
);
4018 lsmash_bs_put_be32( bs
, data
->displayFlags
);
4019 lsmash_bs_put_byte( bs
, data
->horizontal_justification
);
4020 lsmash_bs_put_byte( bs
, data
->vertical_justification
);
4021 for( uint32_t i
= 0; i
< 4; i
++ )
4022 lsmash_bs_put_byte( bs
, data
->background_color_rgba
[i
] );
4023 lsmash_bs_put_be16( bs
, data
->top
);
4024 lsmash_bs_put_be16( bs
, data
->left
);
4025 lsmash_bs_put_be16( bs
, data
->bottom
);
4026 lsmash_bs_put_be16( bs
, data
->right
);
4027 lsmash_bs_put_be16( bs
, data
->startChar
);
4028 lsmash_bs_put_be16( bs
, data
->endChar
);
4029 lsmash_bs_put_be16( bs
, data
->font_ID
);
4030 lsmash_bs_put_byte( bs
, data
->face_style_flags
);
4031 lsmash_bs_put_byte( bs
, data
->font_size
);
4032 for( uint32_t i
= 0; i
< 4; i
++ )
4033 lsmash_bs_put_byte( bs
, data
->text_color_rgba
[i
] );
4034 isom_put_ftab( bs
, data
->ftab
);
4035 return lsmash_bs_write_data( bs
);
4038 static int isom_write_stsd( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4040 isom_stsd_t
*stsd
= trak
->mdia
->minf
->stbl
->stsd
;
4041 if( !stsd
|| !stsd
->list
|| !stsd
->list
->head
)
4043 isom_bs_put_box_common( bs
, stsd
);
4044 lsmash_bs_put_be32( bs
, stsd
->list
->entry_count
);
4046 for( lsmash_entry_t
*entry
= stsd
->list
->head
; entry
; entry
= entry
->next
)
4048 isom_sample_entry_t
*sample
= (isom_sample_entry_t
*)entry
->data
;
4051 switch( sample
->type
)
4053 case ISOM_CODEC_TYPE_AVC1_VIDEO
:
4054 #ifdef LSMASH_DEMUXER_ENABLED
4055 case ISOM_CODEC_TYPE_MP4V_VIDEO
:
4058 case ISOM_CODEC_TYPE_AVC2_VIDEO
:
4059 case ISOM_CODEC_TYPE_AVCP_VIDEO
:
4060 case ISOM_CODEC_TYPE_SVC1_VIDEO
:
4061 case ISOM_CODEC_TYPE_MVC1_VIDEO
:
4062 case ISOM_CODEC_TYPE_MVC2_VIDEO
:
4063 case ISOM_CODEC_TYPE_DRAC_VIDEO
:
4064 case ISOM_CODEC_TYPE_ENCV_VIDEO
:
4065 case ISOM_CODEC_TYPE_MJP2_VIDEO
:
4066 case ISOM_CODEC_TYPE_S263_VIDEO
:
4067 case ISOM_CODEC_TYPE_VC_1_VIDEO
:
4069 ret
= isom_write_visual_entry( bs
, entry
);
4071 case ISOM_CODEC_TYPE_MP4A_AUDIO
:
4072 case ISOM_CODEC_TYPE_AC_3_AUDIO
:
4073 case ISOM_CODEC_TYPE_ALAC_AUDIO
:
4074 case ISOM_CODEC_TYPE_SAMR_AUDIO
:
4075 case ISOM_CODEC_TYPE_SAWB_AUDIO
:
4076 case QT_CODEC_TYPE_23NI_AUDIO
:
4077 case QT_CODEC_TYPE_NONE_AUDIO
:
4078 case QT_CODEC_TYPE_LPCM_AUDIO
:
4079 case QT_CODEC_TYPE_RAW_AUDIO
:
4080 case QT_CODEC_TYPE_SOWT_AUDIO
:
4081 case QT_CODEC_TYPE_TWOS_AUDIO
:
4082 case QT_CODEC_TYPE_FL32_AUDIO
:
4083 case QT_CODEC_TYPE_FL64_AUDIO
:
4084 case QT_CODEC_TYPE_IN24_AUDIO
:
4085 case QT_CODEC_TYPE_IN32_AUDIO
:
4086 case QT_CODEC_TYPE_NOT_SPECIFIED
:
4087 #ifdef LSMASH_DEMUXER_ENABLED
4088 case ISOM_CODEC_TYPE_EC_3_AUDIO
:
4091 case ISOM_CODEC_TYPE_DRA1_AUDIO
:
4092 case ISOM_CODEC_TYPE_DTSC_AUDIO
:
4093 case ISOM_CODEC_TYPE_DTSH_AUDIO
:
4094 case ISOM_CODEC_TYPE_DTSL_AUDIO
:
4095 case ISOM_CODEC_TYPE_ENCA_AUDIO
:
4096 case ISOM_CODEC_TYPE_G719_AUDIO
:
4097 case ISOM_CODEC_TYPE_G726_AUDIO
:
4098 case ISOM_CODEC_TYPE_M4AE_AUDIO
:
4099 case ISOM_CODEC_TYPE_MLPA_AUDIO
:
4100 case ISOM_CODEC_TYPE_RAW_AUDIO
:
4101 case ISOM_CODEC_TYPE_SAWP_AUDIO
:
4102 case ISOM_CODEC_TYPE_SEVC_AUDIO
:
4103 case ISOM_CODEC_TYPE_SQCP_AUDIO
:
4104 case ISOM_CODEC_TYPE_SSMV_AUDIO
:
4105 case ISOM_CODEC_TYPE_TWOS_AUDIO
:
4107 ret
= isom_write_audio_entry( bs
, entry
);
4110 case ISOM_CODEC_TYPE_FDP_HINT
:
4111 case ISOM_CODEC_TYPE_M2TS_HINT
:
4112 case ISOM_CODEC_TYPE_PM2T_HINT
:
4113 case ISOM_CODEC_TYPE_PRTP_HINT
:
4114 case ISOM_CODEC_TYPE_RM2T_HINT
:
4115 case ISOM_CODEC_TYPE_RRTP_HINT
:
4116 case ISOM_CODEC_TYPE_RSRP_HINT
:
4117 case ISOM_CODEC_TYPE_RTP_HINT
:
4118 case ISOM_CODEC_TYPE_SM2T_HINT
:
4119 case ISOM_CODEC_TYPE_SRTP_HINT
:
4120 ret
= isom_write_hint_entry( bs
, entry
);
4122 case ISOM_CODEC_TYPE_IXSE_META
:
4123 case ISOM_CODEC_TYPE_METT_META
:
4124 case ISOM_CODEC_TYPE_METX_META
:
4125 case ISOM_CODEC_TYPE_MLIX_META
:
4126 case ISOM_CODEC_TYPE_OKSD_META
:
4127 case ISOM_CODEC_TYPE_SVCM_META
:
4128 case ISOM_CODEC_TYPE_TEXT_META
:
4129 case ISOM_CODEC_TYPE_URIM_META
:
4130 case ISOM_CODEC_TYPE_XML_META
:
4131 ret
= isom_write_metadata_entry( bs
, entry
);
4134 case ISOM_CODEC_TYPE_TX3G_TEXT
:
4135 ret
= isom_write_tx3g_entry( bs
, entry
);
4137 case QT_CODEC_TYPE_TEXT_TEXT
:
4138 ret
= isom_write_text_entry( bs
, entry
);
4149 static int isom_write_stts( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4151 isom_stts_t
*stts
= trak
->mdia
->minf
->stbl
->stts
;
4152 if( !stts
|| !stts
->list
)
4154 isom_bs_put_box_common( bs
, stts
);
4155 lsmash_bs_put_be32( bs
, stts
->list
->entry_count
);
4156 for( lsmash_entry_t
*entry
= stts
->list
->head
; entry
; entry
= entry
->next
)
4158 isom_stts_entry_t
*data
= (isom_stts_entry_t
*)entry
->data
;
4161 lsmash_bs_put_be32( bs
, data
->sample_count
);
4162 lsmash_bs_put_be32( bs
, data
->sample_delta
);
4164 return lsmash_bs_write_data( bs
);
4167 static int isom_write_ctts( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4169 isom_ctts_t
*ctts
= trak
->mdia
->minf
->stbl
->ctts
;
4174 isom_bs_put_box_common( bs
, ctts
);
4175 lsmash_bs_put_be32( bs
, ctts
->list
->entry_count
);
4176 for( lsmash_entry_t
*entry
= ctts
->list
->head
; entry
; entry
= entry
->next
)
4178 isom_ctts_entry_t
*data
= (isom_ctts_entry_t
*)entry
->data
;
4181 lsmash_bs_put_be32( bs
, data
->sample_count
);
4182 lsmash_bs_put_be32( bs
, data
->sample_offset
);
4184 return lsmash_bs_write_data( bs
);
4187 static int isom_write_cslg( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4189 isom_cslg_t
*cslg
= trak
->mdia
->minf
->stbl
->cslg
;
4192 isom_bs_put_box_common( bs
, cslg
);
4193 lsmash_bs_put_be32( bs
, cslg
->compositionToDTSShift
);
4194 lsmash_bs_put_be32( bs
, cslg
->leastDecodeToDisplayDelta
);
4195 lsmash_bs_put_be32( bs
, cslg
->greatestDecodeToDisplayDelta
);
4196 lsmash_bs_put_be32( bs
, cslg
->compositionStartTime
);
4197 lsmash_bs_put_be32( bs
, cslg
->compositionEndTime
);
4198 return lsmash_bs_write_data( bs
);
4201 static int isom_write_stsz( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4203 isom_stsz_t
*stsz
= trak
->mdia
->minf
->stbl
->stsz
;
4206 isom_bs_put_box_common( bs
, stsz
);
4207 lsmash_bs_put_be32( bs
, stsz
->sample_size
);
4208 lsmash_bs_put_be32( bs
, stsz
->sample_count
);
4209 if( stsz
->sample_size
== 0 && stsz
->list
)
4210 for( lsmash_entry_t
*entry
= stsz
->list
->head
; entry
; entry
= entry
->next
)
4212 isom_stsz_entry_t
*data
= (isom_stsz_entry_t
*)entry
->data
;
4215 lsmash_bs_put_be32( bs
, data
->entry_size
);
4217 return lsmash_bs_write_data( bs
);
4220 static int isom_write_stss( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4222 isom_stss_t
*stss
= trak
->mdia
->minf
->stbl
->stss
;
4224 return 0; /* If the sync sample box is not present, every sample is a random access point. */
4227 isom_bs_put_box_common( bs
, stss
);
4228 lsmash_bs_put_be32( bs
, stss
->list
->entry_count
);
4229 for( lsmash_entry_t
*entry
= stss
->list
->head
; entry
; entry
= entry
->next
)
4231 isom_stss_entry_t
*data
= (isom_stss_entry_t
*)entry
->data
;
4234 lsmash_bs_put_be32( bs
, data
->sample_number
);
4236 return lsmash_bs_write_data( bs
);
4239 static int isom_write_stps( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4241 isom_stps_t
*stps
= trak
->mdia
->minf
->stbl
->stps
;
4246 isom_bs_put_box_common( bs
, stps
);
4247 lsmash_bs_put_be32( bs
, stps
->list
->entry_count
);
4248 for( lsmash_entry_t
*entry
= stps
->list
->head
; entry
; entry
= entry
->next
)
4250 isom_stps_entry_t
*data
= (isom_stps_entry_t
*)entry
->data
;
4253 lsmash_bs_put_be32( bs
, data
->sample_number
);
4255 return lsmash_bs_write_data( bs
);
4258 static int isom_write_sdtp( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4260 isom_sdtp_t
*sdtp
= trak
->mdia
->minf
->stbl
->sdtp
;
4265 isom_bs_put_box_common( bs
, sdtp
);
4266 for( lsmash_entry_t
*entry
= sdtp
->list
->head
; entry
; entry
= entry
->next
)
4268 isom_sdtp_entry_t
*data
= (isom_sdtp_entry_t
*)entry
->data
;
4271 uint8_t temp
= (data
->is_leading
<< 6)
4272 | (data
->sample_depends_on
<< 4)
4273 | (data
->sample_is_depended_on
<< 2)
4274 | data
->sample_has_redundancy
;
4275 lsmash_bs_put_byte( bs
, temp
);
4277 return lsmash_bs_write_data( bs
);
4280 static int isom_write_stsc( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4282 isom_stsc_t
*stsc
= trak
->mdia
->minf
->stbl
->stsc
;
4283 if( !stsc
|| !stsc
->list
)
4285 isom_bs_put_box_common( bs
, stsc
);
4286 lsmash_bs_put_be32( bs
, stsc
->list
->entry_count
);
4287 for( lsmash_entry_t
*entry
= stsc
->list
->head
; entry
; entry
= entry
->next
)
4289 isom_stsc_entry_t
*data
= (isom_stsc_entry_t
*)entry
->data
;
4292 lsmash_bs_put_be32( bs
, data
->first_chunk
);
4293 lsmash_bs_put_be32( bs
, data
->samples_per_chunk
);
4294 lsmash_bs_put_be32( bs
, data
->sample_description_index
);
4296 return lsmash_bs_write_data( bs
);
4299 static int isom_write_co64( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4301 isom_stco_t
*co64
= trak
->mdia
->minf
->stbl
->stco
;
4302 if( !co64
|| !co64
->list
)
4304 isom_bs_put_box_common( bs
, co64
);
4305 lsmash_bs_put_be32( bs
, co64
->list
->entry_count
);
4306 for( lsmash_entry_t
*entry
= co64
->list
->head
; entry
; entry
= entry
->next
)
4308 isom_co64_entry_t
*data
= (isom_co64_entry_t
*)entry
->data
;
4311 lsmash_bs_put_be64( bs
, data
->chunk_offset
);
4313 return lsmash_bs_write_data( bs
);
4316 static int isom_write_stco( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4318 isom_stco_t
*stco
= trak
->mdia
->minf
->stbl
->stco
;
4319 if( !stco
|| !stco
->list
)
4321 if( stco
->large_presentation
)
4322 return isom_write_co64( bs
, trak
);
4323 isom_bs_put_box_common( bs
, stco
);
4324 lsmash_bs_put_be32( bs
, stco
->list
->entry_count
);
4325 for( lsmash_entry_t
*entry
= stco
->list
->head
; entry
; entry
= entry
->next
)
4327 isom_stco_entry_t
*data
= (isom_stco_entry_t
*)entry
->data
;
4330 lsmash_bs_put_be32( bs
, data
->chunk_offset
);
4332 return lsmash_bs_write_data( bs
);
4335 static int isom_write_sgpd( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
, uint32_t grouping_number
)
4337 isom_sgpd_entry_t
*sgpd
= (isom_sgpd_entry_t
*)lsmash_get_entry_data( trak
->mdia
->minf
->stbl
->sgpd_list
, grouping_number
);
4338 if( !sgpd
|| !sgpd
->list
)
4340 isom_bs_put_box_common( bs
, sgpd
);
4341 lsmash_bs_put_be32( bs
, sgpd
->grouping_type
);
4342 if( sgpd
->version
== 1 )
4343 lsmash_bs_put_be32( bs
, sgpd
->default_length
);
4344 lsmash_bs_put_be32( bs
, sgpd
->list
->entry_count
);
4345 for( lsmash_entry_t
*entry
= sgpd
->list
->head
; entry
; entry
= entry
->next
)
4349 switch( sgpd
->grouping_type
)
4351 case ISOM_GROUP_TYPE_RAP
:
4353 isom_rap_entry_t
*rap
= (isom_rap_entry_t
*)entry
->data
;
4354 uint8_t temp
= (rap
->num_leading_samples_known
<< 7)
4355 | rap
->num_leading_samples
;
4356 lsmash_bs_put_byte( bs
, temp
);
4359 case ISOM_GROUP_TYPE_ROLL
:
4360 lsmash_bs_put_be16( bs
, ((isom_roll_entry_t
*)entry
->data
)->roll_distance
);
4363 /* We don't consider other grouping types currently. */
4364 // if( sgpd->version == 1 && !sgpd->default_length )
4365 // lsmash_bs_put_be32( bs, ((isom_sgpd_entry_t *)entry->data)->description_length );
4369 return lsmash_bs_write_data( bs
);
4372 static int isom_write_sbgp( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
, uint32_t grouping_number
)
4374 isom_sbgp_entry_t
*sbgp
= (isom_sbgp_entry_t
*)lsmash_get_entry_data( trak
->mdia
->minf
->stbl
->sbgp_list
, grouping_number
);
4375 if( !sbgp
|| !sbgp
->list
)
4377 isom_bs_put_box_common( bs
, sbgp
);
4378 lsmash_bs_put_be32( bs
, sbgp
->grouping_type
);
4379 if( sbgp
->version
== 1 )
4380 lsmash_bs_put_be32( bs
, sbgp
->grouping_type_parameter
);
4381 lsmash_bs_put_be32( bs
, sbgp
->list
->entry_count
);
4382 for( lsmash_entry_t
*entry
= sbgp
->list
->head
; entry
; entry
= entry
->next
)
4384 isom_group_assignment_entry_t
*data
= (isom_group_assignment_entry_t
*)entry
->data
;
4387 lsmash_bs_put_be32( bs
, data
->sample_count
);
4388 lsmash_bs_put_be32( bs
, data
->group_description_index
);
4390 return lsmash_bs_write_data( bs
);
4393 static int isom_write_stbl( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4395 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
4398 isom_bs_put_box_common( bs
, stbl
);
4399 if( lsmash_bs_write_data( bs
) )
4401 if( isom_write_stsd( bs
, trak
)
4402 || isom_write_stts( bs
, trak
)
4403 || isom_write_ctts( bs
, trak
)
4404 || isom_write_cslg( bs
, trak
)
4405 || isom_write_stss( bs
, trak
)
4406 || isom_write_stps( bs
, trak
)
4407 || isom_write_sdtp( bs
, trak
)
4408 || isom_write_stsc( bs
, trak
)
4409 || isom_write_stsz( bs
, trak
)
4410 || isom_write_stco( bs
, trak
) )
4412 if( stbl
->sgpd_list
)
4413 for( uint32_t i
= 1; i
<= stbl
->sgpd_list
->entry_count
; i
++ )
4414 if( isom_write_sgpd( bs
, trak
, i
) )
4416 if( stbl
->sbgp_list
)
4417 for( uint32_t i
= 1; i
<= stbl
->sbgp_list
->entry_count
; i
++ )
4418 if( isom_write_sbgp( bs
, trak
, i
) )
4423 static int isom_write_minf( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4425 isom_minf_t
*minf
= trak
->mdia
->minf
;
4428 isom_bs_put_box_common( bs
, minf
);
4429 if( lsmash_bs_write_data( bs
) )
4431 if( (minf
->vmhd
&& isom_write_vmhd( bs
, trak
))
4432 || (minf
->smhd
&& isom_write_smhd( bs
, trak
))
4433 || (minf
->hmhd
&& isom_write_hmhd( bs
, trak
))
4434 || (minf
->nmhd
&& isom_write_nmhd( bs
, trak
))
4435 || (minf
->gmhd
&& isom_write_gmhd( bs
, trak
)) )
4437 if( isom_write_hdlr( bs
, minf
->hdlr
, minf
->type
)
4438 || isom_write_dinf( bs
, minf
->dinf
, minf
->type
)
4439 || isom_write_stbl( bs
, trak
) )
4444 static int isom_write_mdia( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4446 isom_mdia_t
*mdia
= trak
->mdia
;
4449 isom_bs_put_box_common( bs
, mdia
);
4450 if( lsmash_bs_write_data( bs
) )
4452 if( isom_write_mdhd( bs
, trak
)
4453 || isom_write_hdlr( bs
, mdia
->hdlr
, mdia
->type
)
4454 || isom_write_minf( bs
, trak
) )
4459 static int isom_write_chpl( lsmash_bs_t
*bs
, isom_chpl_t
*chpl
)
4463 if( !chpl
->list
|| chpl
->version
> 1 )
4465 isom_bs_put_box_common( bs
, chpl
);
4466 if( chpl
->version
== 1 )
4468 lsmash_bs_put_byte( bs
, chpl
->unknown
);
4469 lsmash_bs_put_be32( bs
, chpl
->list
->entry_count
);
4471 else /* chpl->version == 0 */
4472 lsmash_bs_put_byte( bs
, (uint8_t)chpl
->list
->entry_count
);
4473 for( lsmash_entry_t
*entry
= chpl
->list
->head
; entry
; entry
= entry
->next
)
4475 isom_chpl_entry_t
*data
= (isom_chpl_entry_t
*)entry
->data
;
4478 lsmash_bs_put_be64( bs
, data
->start_time
);
4479 lsmash_bs_put_byte( bs
, data
->chapter_name_length
);
4480 lsmash_bs_put_bytes( bs
, data
->chapter_name
, data
->chapter_name_length
);
4482 return lsmash_bs_write_data( bs
);
4485 static int isom_write_mean( lsmash_bs_t
*bs
, isom_mean_t
*mean
)
4489 isom_bs_put_box_common( bs
, mean
);
4490 if( mean
->meaning_string
&& mean
->meaning_string_length
)
4491 lsmash_bs_put_bytes( bs
, mean
->meaning_string
, mean
->meaning_string_length
);
4492 return lsmash_bs_write_data( bs
);
4495 static int isom_write_name( lsmash_bs_t
*bs
, isom_name_t
*name
)
4499 isom_bs_put_box_common( bs
, name
);
4500 if( name
->name
&& name
->name_length
)
4501 lsmash_bs_put_bytes( bs
, name
->name
, name
->name_length
);
4502 return lsmash_bs_write_data( bs
);
4505 static int isom_write_data( lsmash_bs_t
*bs
, isom_data_t
*data
)
4507 if( !data
|| data
->size
< 16 )
4509 isom_bs_put_box_common( bs
, data
);
4510 lsmash_bs_put_be16( bs
, data
->reserved
);
4511 lsmash_bs_put_byte( bs
, data
->type_set_identifier
);
4512 lsmash_bs_put_byte( bs
, data
->type_code
);
4513 lsmash_bs_put_be32( bs
, data
->the_locale
);
4514 if( data
->value
&& data
->value_length
)
4515 lsmash_bs_put_bytes( bs
, data
->value
, data
->value_length
);
4516 return lsmash_bs_write_data( bs
);
4519 static int isom_write_metaitem( lsmash_bs_t
*bs
, isom_metaitem_t
*metaitem
)
4523 isom_bs_put_box_common( bs
, metaitem
);
4524 if( lsmash_bs_write_data( bs
) )
4526 if( isom_write_mean( bs
, metaitem
->mean
)
4527 || isom_write_name( bs
, metaitem
->name
)
4528 || isom_write_data( bs
, metaitem
->data
) )
4533 static int isom_write_ilst( lsmash_bs_t
*bs
, isom_ilst_t
*ilst
)
4537 isom_bs_put_box_common( bs
, ilst
);
4538 if( lsmash_bs_write_data( bs
) )
4540 if( ilst
->item_list
)
4541 for( lsmash_entry_t
*entry
= ilst
->item_list
->head
; entry
; entry
= entry
->next
)
4542 if( isom_write_metaitem( bs
, (isom_metaitem_t
*)entry
->data
) )
4547 static int isom_write_meta( lsmash_bs_t
*bs
, isom_meta_t
*meta
)
4551 isom_bs_put_box_common( bs
, meta
);
4552 if( lsmash_bs_write_data( bs
) )
4554 if( isom_write_hdlr( bs
, meta
->hdlr
, meta
->type
)
4555 || isom_write_dinf( bs
, meta
->dinf
, meta
->type
)
4556 || isom_write_ilst( bs
, meta
->ilst
) )
4561 static int isom_write_udta( lsmash_bs_t
*bs
, isom_moov_t
*moov
, isom_trak_entry_t
*trak
)
4563 /* Setting non-NULL pointer to trak means trak->udta data will be written in stream.
4564 * If trak is set by NULL while moov is set by non-NULL pointer, moov->udta data will be written in stream. */
4565 isom_udta_t
*udta
= trak
? trak
->udta
: moov
? moov
->udta
: NULL
;
4568 isom_bs_put_box_common( bs
, udta
);
4569 if( lsmash_bs_write_data( bs
) )
4571 if( moov
&& isom_write_chpl( bs
, udta
->chpl
) )
4573 return isom_write_meta( bs
, udta
->meta
);
4576 static int isom_write_trak( lsmash_bs_t
*bs
, isom_trak_entry_t
*trak
)
4580 isom_bs_put_box_common( bs
, trak
);
4581 if( lsmash_bs_write_data( bs
) )
4583 if( isom_write_tkhd( bs
, trak
)
4584 || isom_write_tapt( bs
, trak
)
4585 || isom_write_edts( bs
, trak
)
4586 || isom_write_tref( bs
, trak
)
4587 || isom_write_mdia( bs
, trak
)
4588 || isom_write_udta( bs
, NULL
, trak
)
4589 || isom_write_meta( bs
, trak
->meta
) )
4594 static int isom_write_iods( lsmash_root_t
*root
)
4596 if( !root
|| !root
->moov
)
4598 if( !root
->moov
->iods
)
4600 isom_iods_t
*iods
= root
->moov
->iods
;
4601 lsmash_bs_t
*bs
= root
->bs
;
4602 isom_bs_put_box_common( bs
, iods
);
4603 return mp4sys_write_ObjectDescriptor( bs
, iods
->OD
);
4606 static int isom_write_mvhd( lsmash_root_t
*root
)
4608 if( !root
|| !root
->moov
|| !root
->moov
->mvhd
)
4610 isom_mvhd_t
*mvhd
= root
->moov
->mvhd
;
4611 lsmash_bs_t
*bs
= root
->bs
;
4612 isom_bs_put_box_common( bs
, mvhd
);
4615 lsmash_bs_put_be64( bs
, mvhd
->creation_time
);
4616 lsmash_bs_put_be64( bs
, mvhd
->modification_time
);
4617 lsmash_bs_put_be32( bs
, mvhd
->timescale
);
4618 lsmash_bs_put_be64( bs
, mvhd
->duration
);
4622 lsmash_bs_put_be32( bs
, (uint32_t)mvhd
->creation_time
);
4623 lsmash_bs_put_be32( bs
, (uint32_t)mvhd
->modification_time
);
4624 lsmash_bs_put_be32( bs
, mvhd
->timescale
);
4625 lsmash_bs_put_be32( bs
, (uint32_t)mvhd
->duration
);
4627 lsmash_bs_put_be32( bs
, mvhd
->rate
);
4628 lsmash_bs_put_be16( bs
, mvhd
->volume
);
4629 lsmash_bs_put_be16( bs
, mvhd
->reserved
);
4630 lsmash_bs_put_be32( bs
, mvhd
->preferredLong
[0] );
4631 lsmash_bs_put_be32( bs
, mvhd
->preferredLong
[1] );
4632 for( int i
= 0; i
< 9; i
++ )
4633 lsmash_bs_put_be32( bs
, mvhd
->matrix
[i
] );
4634 lsmash_bs_put_be32( bs
, mvhd
->previewTime
);
4635 lsmash_bs_put_be32( bs
, mvhd
->previewDuration
);
4636 lsmash_bs_put_be32( bs
, mvhd
->posterTime
);
4637 lsmash_bs_put_be32( bs
, mvhd
->selectionTime
);
4638 lsmash_bs_put_be32( bs
, mvhd
->selectionDuration
);
4639 lsmash_bs_put_be32( bs
, mvhd
->currentTime
);
4640 lsmash_bs_put_be32( bs
, mvhd
->next_track_ID
);
4641 return lsmash_bs_write_data( bs
);
4644 static void isom_bs_put_sample_flags( lsmash_bs_t
*bs
, isom_sample_flags_t
*flags
)
4646 uint32_t temp
= (flags
->reserved
<< 28)
4647 | (flags
->is_leading
<< 26)
4648 | (flags
->sample_depends_on
<< 24)
4649 | (flags
->sample_is_depended_on
<< 22)
4650 | (flags
->sample_has_redundancy
<< 20)
4651 | (flags
->sample_padding_value
<< 17)
4652 | (flags
->sample_is_non_sync_sample
<< 16)
4653 | flags
->sample_degradation_priority
;
4654 lsmash_bs_put_be32( bs
, temp
);
4657 static int isom_write_mehd( lsmash_bs_t
*bs
, isom_mehd_t
*mehd
)
4661 isom_bs_put_box_common( bs
, mehd
);
4662 if( mehd
->version
== 1 )
4663 lsmash_bs_put_be64( bs
, mehd
->fragment_duration
);
4665 lsmash_bs_put_be32( bs
, (uint32_t)mehd
->fragment_duration
);
4666 return lsmash_bs_write_data( bs
);
4669 static int isom_write_trex( lsmash_bs_t
*bs
, isom_trex_entry_t
*trex
)
4673 isom_bs_put_box_common( bs
, trex
);
4674 lsmash_bs_put_be32( bs
, trex
->track_ID
);
4675 lsmash_bs_put_be32( bs
, trex
->default_sample_description_index
);
4676 lsmash_bs_put_be32( bs
, trex
->default_sample_duration
);
4677 lsmash_bs_put_be32( bs
, trex
->default_sample_size
);
4678 isom_bs_put_sample_flags( bs
, &trex
->default_sample_flags
);
4679 return lsmash_bs_write_data( bs
);
4682 static int isom_bs_write_movie_extends_placeholder( lsmash_bs_t
*bs
)
4684 /* The following will be overwritten by Movie Extends Header Box.
4685 * We use version 1 Movie Extends Header Box since it causes extra 4 bytes region
4686 * we cannot replace with empty Free Space Box as we place version 0 one. */
4687 lsmash_bs_put_be32( bs
, ISOM_FULLBOX_COMMON_SIZE
+ 8 );
4688 lsmash_bs_put_be32( bs
, ISOM_BOX_TYPE_FREE
);
4689 lsmash_bs_put_be32( bs
, 0 );
4690 lsmash_bs_put_be64( bs
, 0 );
4691 return lsmash_bs_write_data( bs
);
4694 static int isom_write_mvex( lsmash_bs_t
*bs
, isom_mvex_t
*mvex
)
4698 isom_bs_put_box_common( bs
, mvex
);
4699 if( lsmash_bs_write_data( bs
) )
4701 /* Movie Extends Header Box is not written immediately.
4702 * It's done after finishing all movie fragments. */
4705 if( isom_write_mehd( bs
, mvex
->mehd
) )
4708 else if( bs
->stream
!= stdout
)
4720 |--[mehd] <--- mehd->pos == mvex->placeholder_pos
4722 mvex
->placeholder_pos
= mvex
->root
->bs
->written
;
4723 if( isom_bs_write_movie_extends_placeholder( bs
) )
4726 if( mvex
->trex_list
)
4727 for( lsmash_entry_t
*entry
= mvex
->trex_list
->head
; entry
; entry
= entry
->next
)
4728 if( isom_write_trex( bs
, (isom_trex_entry_t
*)entry
->data
) )
4733 static int isom_write_mfhd( lsmash_bs_t
*bs
, isom_mfhd_t
*mfhd
)
4737 isom_bs_put_box_common( bs
, mfhd
);
4738 lsmash_bs_put_be32( bs
, mfhd
->sequence_number
);
4739 return lsmash_bs_write_data( bs
);
4742 static int isom_write_tfhd( lsmash_bs_t
*bs
, isom_tfhd_t
*tfhd
)
4746 isom_bs_put_box_common( bs
, tfhd
);
4747 lsmash_bs_put_be32( bs
, tfhd
->track_ID
);
4748 if( tfhd
->flags
& ISOM_TF_FLAGS_BASE_DATA_OFFSET_PRESENT
) lsmash_bs_put_be64( bs
, tfhd
->base_data_offset
);
4749 if( tfhd
->flags
& ISOM_TF_FLAGS_SAMPLE_DESCRIPTION_INDEX_PRESENT
) lsmash_bs_put_be32( bs
, tfhd
->sample_description_index
);
4750 if( tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT
) lsmash_bs_put_be32( bs
, tfhd
->default_sample_duration
);
4751 if( tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_SAMPLE_SIZE_PRESENT
) lsmash_bs_put_be32( bs
, tfhd
->default_sample_size
);
4752 if( tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_SAMPLE_FLAGS_PRESENT
) isom_bs_put_sample_flags( bs
, &tfhd
->default_sample_flags
);
4753 return lsmash_bs_write_data( bs
);
4756 static int isom_write_trun( lsmash_bs_t
*bs
, isom_trun_entry_t
*trun
)
4760 isom_bs_put_box_common( bs
, trun
);
4761 lsmash_bs_put_be32( bs
, trun
->sample_count
);
4762 if( trun
->flags
& ISOM_TR_FLAGS_DATA_OFFSET_PRESENT
) lsmash_bs_put_be32( bs
, trun
->data_offset
);
4763 if( trun
->flags
& ISOM_TR_FLAGS_FIRST_SAMPLE_FLAGS_PRESENT
) isom_bs_put_sample_flags( bs
, &trun
->first_sample_flags
);
4764 if( trun
->optional
)
4765 for( lsmash_entry_t
*entry
= trun
->optional
->head
; entry
; entry
= entry
->next
)
4767 isom_trun_optional_row_t
*data
= (isom_trun_optional_row_t
*)entry
->data
;
4770 if( trun
->flags
& ISOM_TR_FLAGS_SAMPLE_DURATION_PRESENT
) lsmash_bs_put_be32( bs
, data
->sample_duration
);
4771 if( trun
->flags
& ISOM_TR_FLAGS_SAMPLE_SIZE_PRESENT
) lsmash_bs_put_be32( bs
, data
->sample_size
);
4772 if( trun
->flags
& ISOM_TR_FLAGS_SAMPLE_FLAGS_PRESENT
) isom_bs_put_sample_flags( bs
, &data
->sample_flags
);
4773 if( trun
->flags
& ISOM_TR_FLAGS_SAMPLE_COMPOSITION_TIME_OFFSET_PRESENT
) lsmash_bs_put_be32( bs
, data
->sample_composition_time_offset
);
4775 return lsmash_bs_write_data( bs
);
4778 static int isom_write_traf( lsmash_bs_t
*bs
, isom_traf_entry_t
*traf
)
4782 isom_bs_put_box_common( bs
, traf
);
4783 if( lsmash_bs_write_data( bs
) )
4785 if( isom_write_tfhd( bs
, traf
->tfhd
) )
4787 if( traf
->trun_list
)
4788 for( lsmash_entry_t
*entry
= traf
->trun_list
->head
; entry
; entry
= entry
->next
)
4789 if( isom_write_trun( bs
, (isom_trun_entry_t
*)entry
->data
) )
4794 static int isom_write_moof( lsmash_bs_t
*bs
, isom_moof_entry_t
*moof
)
4798 isom_bs_put_box_common( bs
, moof
);
4799 if( lsmash_bs_write_data( bs
) )
4801 if( isom_write_mfhd( bs
, moof
->mfhd
) )
4803 if( moof
->traf_list
)
4804 for( lsmash_entry_t
*entry
= moof
->traf_list
->head
; entry
; entry
= entry
->next
)
4805 if( isom_write_traf( bs
, (isom_traf_entry_t
*)entry
->data
) )
4810 static int isom_write_tfra( lsmash_bs_t
*bs
, isom_tfra_entry_t
*tfra
)
4814 isom_bs_put_box_common( bs
, tfra
);
4815 uint32_t temp
= (tfra
->reserved
<< 6)
4816 | (tfra
->length_size_of_traf_num
<< 4)
4817 | (tfra
->length_size_of_trun_num
<< 2)
4818 | tfra
->length_size_of_sample_num
;
4819 lsmash_bs_put_be32( bs
, tfra
->track_ID
);
4820 lsmash_bs_put_be32( bs
, temp
);
4821 lsmash_bs_put_be32( bs
, tfra
->number_of_entry
);
4824 void (*bs_put_funcs
[5])( lsmash_bs_t
*, uint64_t ) =
4826 lsmash_bs_put_byte_from_64
,
4827 lsmash_bs_put_be16_from_64
,
4828 lsmash_bs_put_be24_from_64
,
4829 lsmash_bs_put_be32_from_64
,
4832 void (*bs_put_time
) ( lsmash_bs_t
*, uint64_t ) = bs_put_funcs
[ 3 + (tfra
->version
== 1) ];
4833 void (*bs_put_moof_offset
) ( lsmash_bs_t
*, uint64_t ) = bs_put_funcs
[ 3 + (tfra
->version
== 1) ];
4834 void (*bs_put_traf_number
) ( lsmash_bs_t
*, uint64_t ) = bs_put_funcs
[ tfra
->length_size_of_traf_num
];
4835 void (*bs_put_trun_number
) ( lsmash_bs_t
*, uint64_t ) = bs_put_funcs
[ tfra
->length_size_of_trun_num
];
4836 void (*bs_put_sample_number
)( lsmash_bs_t
*, uint64_t ) = bs_put_funcs
[ tfra
->length_size_of_sample_num
];
4837 for( lsmash_entry_t
*entry
= tfra
->list
->head
; entry
; entry
= entry
->next
)
4839 isom_tfra_location_time_entry_t
*data
= (isom_tfra_location_time_entry_t
*)entry
->data
;
4842 bs_put_time ( bs
, data
->time
);
4843 bs_put_moof_offset ( bs
, data
->moof_offset
);
4844 bs_put_traf_number ( bs
, data
->traf_number
);
4845 bs_put_trun_number ( bs
, data
->trun_number
);
4846 bs_put_sample_number( bs
, data
->sample_number
);
4849 return lsmash_bs_write_data( bs
);
4852 static int isom_write_mfro( lsmash_bs_t
*bs
, isom_mfro_t
*mfro
)
4856 isom_bs_put_box_common( bs
, mfro
);
4857 lsmash_bs_put_be32( bs
, mfro
->length
);
4858 return lsmash_bs_write_data( bs
);
4861 static int isom_write_mfra( lsmash_bs_t
*bs
, isom_mfra_t
*mfra
)
4865 isom_bs_put_box_common( bs
, mfra
);
4866 if( lsmash_bs_write_data( bs
) )
4868 if( mfra
->tfra_list
)
4869 for( lsmash_entry_t
*entry
= mfra
->tfra_list
->head
; entry
; entry
= entry
->next
)
4870 if( isom_write_tfra( bs
, (isom_tfra_entry_t
*)entry
->data
) )
4872 return isom_write_mfro( bs
, mfra
->mfro
);
4875 static int isom_bs_write_largesize_placeholder( lsmash_bs_t
*bs
)
4877 lsmash_bs_put_be32( bs
, ISOM_BASEBOX_COMMON_SIZE
);
4878 lsmash_bs_put_be32( bs
, ISOM_BOX_TYPE_FREE
);
4879 return lsmash_bs_write_data( bs
);
4882 static int isom_write_mdat_header( lsmash_root_t
*root
, uint64_t media_size
)
4884 if( !root
|| !root
->bs
|| !root
->mdat
)
4886 isom_mdat_t
*mdat
= root
->mdat
;
4887 lsmash_bs_t
*bs
= root
->bs
;
4890 mdat
->size
= ISOM_BASEBOX_COMMON_SIZE
+ media_size
;
4891 if( mdat
->size
> UINT32_MAX
)
4892 mdat
->size
+= 8; /* large_size */
4893 isom_bs_put_box_common( bs
, mdat
);
4896 mdat
->placeholder_pos
= lsmash_ftell( bs
->stream
);
4897 if( isom_bs_write_largesize_placeholder( bs
) )
4899 mdat
->size
= ISOM_BASEBOX_COMMON_SIZE
;
4900 isom_bs_put_box_common( bs
, mdat
);
4901 return lsmash_bs_write_data( bs
);
4904 static int isom_write_mdat_size( lsmash_root_t
*root
)
4906 if( !root
|| !root
->bs
|| !root
->bs
->stream
)
4910 isom_mdat_t
*mdat
= root
->mdat
;
4911 uint8_t large_flag
= mdat
->size
> UINT32_MAX
;
4912 lsmash_bs_t
*bs
= root
->bs
;
4913 FILE *stream
= bs
->stream
;
4914 uint64_t current_pos
= lsmash_ftell( stream
);
4917 lsmash_fseek( stream
, mdat
->placeholder_pos
, SEEK_SET
);
4918 lsmash_bs_put_be32( bs
, 1 );
4919 lsmash_bs_put_be32( bs
, ISOM_BOX_TYPE_MDAT
);
4920 lsmash_bs_put_be64( bs
, mdat
->size
+ ISOM_BASEBOX_COMMON_SIZE
);
4924 lsmash_fseek( stream
, mdat
->placeholder_pos
+ ISOM_BASEBOX_COMMON_SIZE
, SEEK_SET
);
4925 lsmash_bs_put_be32( bs
, mdat
->size
);
4926 lsmash_bs_put_be32( bs
, ISOM_BOX_TYPE_MDAT
);
4928 int ret
= lsmash_bs_write_data( bs
);
4929 lsmash_fseek( stream
, current_pos
, SEEK_SET
);
4933 /* We put a placeholder for 64-bit media data if the media_size of the argument is set to 0.
4934 * If a Media Data Box already exists and we don't pick movie fragments structure,
4935 * write the actual size of the current one and start a new one. */
4936 static int isom_new_mdat( lsmash_root_t
*root
, uint64_t media_size
)
4942 /* Write the actual size of the current Media Data Box. */
4943 if( !root
->fragment
&& isom_write_mdat_size( root
) )
4948 isom_create_box( mdat
, root
, ISOM_BOX_TYPE_MDAT
);
4951 /* Start a new Media Data Box. */
4952 return isom_write_mdat_header( root
, media_size
);
4955 int isom_check_compatibility( lsmash_root_t
*root
)
4959 root
->qt_compatible
= 0;
4960 /* Check brand to decide mandatory boxes. */
4961 if( !root
->ftyp
|| !root
->ftyp
->brand_count
)
4963 /* No brand declaration means this file is a MP4 version 1 or QuickTime file format. */
4964 if( root
->moov
&& root
->moov
->iods
)
4966 root
->mp4_version1
= 1;
4967 root
->isom_compatible
= 1;
4970 root
->qt_compatible
= 1;
4973 for( uint32_t i
= 0; i
< root
->ftyp
->brand_count
; i
++ )
4975 switch( root
->ftyp
->compatible_brands
[i
] )
4977 case ISOM_BRAND_TYPE_QT
:
4978 root
->qt_compatible
= 1;
4980 case ISOM_BRAND_TYPE_MP41
:
4981 root
->mp4_version1
= 1;
4983 case ISOM_BRAND_TYPE_MP42
:
4984 root
->mp4_version2
= 1;
4986 case ISOM_BRAND_TYPE_ISOM
:
4987 root
->max_isom_version
= LSMASH_MAX( root
->max_isom_version
, 1 );
4989 case ISOM_BRAND_TYPE_ISO2
:
4990 root
->max_isom_version
= LSMASH_MAX( root
->max_isom_version
, 2 );
4992 case ISOM_BRAND_TYPE_ISO3
:
4993 root
->max_isom_version
= LSMASH_MAX( root
->max_isom_version
, 3 );
4995 case ISOM_BRAND_TYPE_ISO4
:
4996 root
->max_isom_version
= LSMASH_MAX( root
->max_isom_version
, 4 );
4998 case ISOM_BRAND_TYPE_ISO5
:
4999 root
->max_isom_version
= LSMASH_MAX( root
->max_isom_version
, 5 );
5001 case ISOM_BRAND_TYPE_ISO6
:
5002 root
->max_isom_version
= LSMASH_MAX( root
->max_isom_version
, 6 );
5004 case ISOM_BRAND_TYPE_M4A
:
5005 case ISOM_BRAND_TYPE_M4B
:
5006 root
->itunes_audio
= 1;
5007 case ISOM_BRAND_TYPE_M4P
:
5008 case ISOM_BRAND_TYPE_M4V
:
5009 root
->itunes_movie
= 1;
5011 case ISOM_BRAND_TYPE_3GP4
:
5012 root
->max_3gpp_version
= LSMASH_MAX( root
->max_3gpp_version
, 4 );
5014 case ISOM_BRAND_TYPE_3GP5
:
5015 root
->max_3gpp_version
= LSMASH_MAX( root
->max_3gpp_version
, 5 );
5017 case ISOM_BRAND_TYPE_3GE6
:
5018 case ISOM_BRAND_TYPE_3GG6
:
5019 case ISOM_BRAND_TYPE_3GP6
:
5020 case ISOM_BRAND_TYPE_3GR6
:
5021 case ISOM_BRAND_TYPE_3GS6
:
5022 root
->max_3gpp_version
= LSMASH_MAX( root
->max_3gpp_version
, 6 );
5027 switch( root
->ftyp
->compatible_brands
[i
] )
5029 case ISOM_BRAND_TYPE_AVC1
:
5030 case ISOM_BRAND_TYPE_ISO2
:
5031 case ISOM_BRAND_TYPE_ISO3
:
5032 case ISOM_BRAND_TYPE_ISO4
:
5033 case ISOM_BRAND_TYPE_ISO5
:
5034 case ISOM_BRAND_TYPE_ISO6
:
5035 root
->avc_extensions
= 1;
5041 root
->isom_compatible
= !root
->qt_compatible
|| root
->mp4_version1
|| root
->mp4_version2
|| root
->itunes_movie
|| root
->max_3gpp_version
;
5045 static uint32_t isom_get_sample_count( isom_trak_entry_t
*trak
)
5047 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
|| !trak
->mdia
->minf
->stbl
->stsz
)
5049 return trak
->mdia
->minf
->stbl
->stsz
->sample_count
;
5052 static uint64_t isom_get_dts( isom_stts_t
*stts
, uint32_t sample_number
)
5054 if( !stts
|| !stts
->list
)
5058 lsmash_entry_t
*entry
;
5059 isom_stts_entry_t
*data
;
5060 for( entry
= stts
->list
->head
; entry
; entry
= entry
->next
)
5062 data
= (isom_stts_entry_t
*)entry
->data
;
5065 if( i
+ data
->sample_count
> sample_number
)
5067 dts
+= (uint64_t)data
->sample_delta
* data
->sample_count
;
5068 i
+= data
->sample_count
;
5072 dts
+= (uint64_t)data
->sample_delta
* (sample_number
- i
);
5077 static uint64_t isom_get_cts( isom_stts_t
*stts
, isom_ctts_t
*ctts
, uint32_t sample_number
)
5079 if( !stts
|| !stts
->list
)
5082 return isom_get_dts( stts
, sample_number
);
5083 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. */
5084 lsmash_entry_t
*entry
;
5085 isom_ctts_entry_t
*data
;
5086 if( sample_number
== 0 )
5088 for( entry
= ctts
->list
->head
; entry
; entry
= entry
->next
)
5090 data
= (isom_ctts_entry_t
*)entry
->data
;
5093 if( i
+ data
->sample_count
> sample_number
)
5095 i
+= data
->sample_count
;
5099 return isom_get_dts( stts
, sample_number
) + data
->sample_offset
;
5103 static int isom_replace_last_sample_delta( isom_stbl_t
*stbl
, uint32_t sample_delta
)
5105 if( !stbl
|| !stbl
->stts
|| !stbl
->stts
->list
|| !stbl
->stts
->list
->tail
|| !stbl
->stts
->list
->tail
->data
)
5107 isom_stts_entry_t
*last_stts_data
= (isom_stts_entry_t
*)stbl
->stts
->list
->tail
->data
;
5108 if( sample_delta
!= last_stts_data
->sample_delta
)
5110 if( last_stts_data
->sample_count
> 1 )
5112 last_stts_data
->sample_count
-= 1;
5113 if( isom_add_stts_entry( stbl
, sample_delta
) )
5117 last_stts_data
->sample_delta
= sample_delta
;
5122 static int isom_update_mdhd_duration( isom_trak_entry_t
*trak
, uint32_t last_sample_delta
)
5124 if( !trak
|| !trak
->root
|| !trak
->cache
|| !trak
->mdia
|| !trak
->mdia
->mdhd
|| !trak
->mdia
->minf
5125 || !trak
->mdia
->minf
->stbl
|| !trak
->mdia
->minf
->stbl
->stts
|| !trak
->mdia
->minf
->stbl
->stts
->list
)
5127 lsmash_root_t
*root
= trak
->root
;
5128 isom_mdhd_t
*mdhd
= trak
->mdia
->mdhd
;
5129 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
5130 isom_stts_t
*stts
= stbl
->stts
;
5131 isom_ctts_t
*ctts
= stbl
->ctts
;
5132 isom_cslg_t
*cslg
= stbl
->cslg
;
5134 uint32_t sample_count
= isom_get_sample_count( trak
);
5137 /* Return error if non-fragmented movie has no samples. */
5138 if( !root
->fragment
&& !stts
->list
->entry_count
)
5142 /* Now we have at least 1 sample, so do stts_entry. */
5143 lsmash_entry_t
*last_stts
= stts
->list
->tail
;
5144 isom_stts_entry_t
*last_stts_data
= (isom_stts_entry_t
*)last_stts
->data
;
5145 if( sample_count
== 1 )
5146 mdhd
->duration
= last_stts_data
->sample_delta
;
5147 /* Now we have at least 2 samples,
5148 * but dunno whether 1 stts_entry which has 2 samples or 2 stts_entry which has 1 samle each. */
5151 /* use dts instead of cts */
5152 mdhd
->duration
= isom_get_dts( stts
, sample_count
);
5153 if( last_sample_delta
)
5155 mdhd
->duration
+= last_sample_delta
;
5156 if( isom_replace_last_sample_delta( stbl
, last_sample_delta
) )
5159 else if( last_stts_data
->sample_count
> 1 )
5160 mdhd
->duration
+= last_stts_data
->sample_delta
; /* no need to update last_stts_data->sample_delta */
5163 /* Remove the last entry. */
5164 if( lsmash_remove_entry( stts
->list
, stts
->list
->entry_count
, NULL
) )
5166 /* copy the previous sample_delta. */
5167 ++ ((isom_stts_entry_t
*)stts
->list
->tail
->data
)->sample_count
;
5168 mdhd
->duration
+= ((isom_stts_entry_t
*)stts
->list
->tail
->data
)->sample_delta
;
5173 if( !ctts
->list
|| ctts
->list
->entry_count
== 0 )
5176 uint64_t max_cts
= 0, max2_cts
= 0, min_cts
= UINT64_MAX
;
5177 uint32_t max_offset
= 0, min_offset
= UINT32_MAX
;
5178 int32_t ctd_shift
= trak
->cache
->timestamp
.ctd_shift
;
5180 lsmash_entry_t
*stts_entry
= stts
->list
->head
;
5181 lsmash_entry_t
*ctts_entry
= ctts
->list
->head
;
5183 for( uint32_t i
= 0; i
< sample_count
; i
++ )
5185 if( !ctts_entry
|| !stts_entry
)
5187 isom_stts_entry_t
*stts_data
= (isom_stts_entry_t
*)stts_entry
->data
;
5188 isom_ctts_entry_t
*ctts_data
= (isom_ctts_entry_t
*)ctts_entry
->data
;
5189 if( !stts_data
|| !ctts_data
)
5194 /* Anyway, add composition to decode timeline shift for calculating maximum and minimum CTS correctly. */
5195 int32_t sample_offset
= (int32_t)ctts_data
->sample_offset
;
5196 cts
= dts
+ sample_offset
+ ctd_shift
;
5197 max_offset
= LSMASH_MAX( (int32_t)max_offset
, sample_offset
);
5198 min_offset
= LSMASH_MIN( (int32_t)min_offset
, sample_offset
);
5202 cts
= dts
+ ctts_data
->sample_offset
;
5203 max_offset
= LSMASH_MAX( max_offset
, ctts_data
->sample_offset
);
5204 min_offset
= LSMASH_MIN( min_offset
, ctts_data
->sample_offset
);
5206 min_cts
= LSMASH_MIN( min_cts
, cts
);
5212 else if( max2_cts
< cts
)
5214 dts
+= stts_data
->sample_delta
;
5215 /* If finished sample_count of current entry, move to next. */
5216 if( ++j
== ctts_data
->sample_count
)
5218 ctts_entry
= ctts_entry
->next
;
5221 if( ++k
== stts_data
->sample_count
)
5223 stts_entry
= stts_entry
->next
;
5227 dts
-= last_stts_data
->sample_delta
;
5228 if( root
->fragment
)
5229 /* Overall presentation is extended exceeding this initial movie.
5230 * So, any players shall display the movie exceeding the durations
5231 * indicated in Movie Header Box, Track Header Boxes and Media Header Boxes.
5232 * Samples up to the duration indicated in Movie Extends Header Box shall be displayed.
5233 * In the absence of Movie Extends Header Box, all samples shall be displayed. */
5234 mdhd
->duration
+= dts
+ last_sample_delta
;
5237 if( !last_sample_delta
)
5239 /* The spec allows an arbitrary value for the duration of the last sample. So, we pick last-1 sample's. */
5240 last_sample_delta
= max_cts
- max2_cts
;
5242 mdhd
->duration
= max_cts
- min_cts
+ last_sample_delta
;
5243 /* To match dts and media duration, update stts and mdhd relatively. */
5244 if( mdhd
->duration
> dts
)
5245 last_sample_delta
= mdhd
->duration
- dts
;
5247 mdhd
->duration
= dts
+ last_sample_delta
; /* media duration must not less than last dts. */
5249 if( isom_replace_last_sample_delta( stbl
, last_sample_delta
) )
5251 /* Explicit composition information and timeline shifting */
5252 if( cslg
|| root
->qt_compatible
|| root
->max_isom_version
>= 4 )
5256 /* Remove composition to decode timeline shift. */
5257 max_cts
-= ctd_shift
;
5258 max2_cts
-= ctd_shift
;
5259 min_cts
-= ctd_shift
;
5261 int64_t composition_end_time
= max_cts
+ (max_cts
- max2_cts
);
5263 && ((int32_t)min_offset
<= INT32_MAX
) && ((int32_t)max_offset
<= INT32_MAX
)
5264 && ((int64_t)min_cts
<= INT32_MAX
) && (composition_end_time
<= INT32_MAX
) )
5268 if( isom_add_cslg( trak
->mdia
->minf
->stbl
) )
5272 cslg
->compositionToDTSShift
= ctd_shift
;
5273 cslg
->leastDecodeToDisplayDelta
= min_offset
;
5274 cslg
->greatestDecodeToDisplayDelta
= max_offset
;
5275 cslg
->compositionStartTime
= min_cts
;
5276 cslg
->compositionEndTime
= composition_end_time
;
5286 if( mdhd
->duration
> UINT32_MAX
)
5291 static int isom_update_mvhd_duration( isom_moov_t
*moov
)
5293 if( !moov
|| !moov
->mvhd
)
5295 isom_mvhd_t
*mvhd
= moov
->mvhd
;
5297 for( lsmash_entry_t
*entry
= moov
->trak_list
->head
; entry
; entry
= entry
->next
)
5299 /* We pick maximum track duration as movie duration. */
5300 isom_trak_entry_t
*data
= (isom_trak_entry_t
*)entry
->data
;
5301 if( !data
|| !data
->tkhd
)
5303 mvhd
->duration
= entry
!= moov
->trak_list
->head
? LSMASH_MAX( mvhd
->duration
, data
->tkhd
->duration
) : data
->tkhd
->duration
;
5305 if( mvhd
->duration
> UINT32_MAX
)
5310 static int isom_update_tkhd_duration( isom_trak_entry_t
*trak
)
5312 if( !trak
|| !trak
->tkhd
|| !trak
->root
|| !trak
->root
->moov
)
5314 lsmash_root_t
*root
= trak
->root
;
5315 isom_tkhd_t
*tkhd
= trak
->tkhd
;
5317 if( root
->fragment
|| !trak
->edts
|| !trak
->edts
->elst
)
5319 /* If this presentation might be extended or this track doesn't have edit list, calculate track duration from media duration. */
5320 if( !trak
->mdia
|| !trak
->mdia
->mdhd
|| !root
->moov
->mvhd
|| !trak
->mdia
->mdhd
->timescale
)
5322 if( !trak
->mdia
->mdhd
->duration
&& isom_update_mdhd_duration( trak
, 0 ) )
5324 tkhd
->duration
= trak
->mdia
->mdhd
->duration
* ((double)root
->moov
->mvhd
->timescale
/ trak
->mdia
->mdhd
->timescale
);
5328 /* If the presentation won't be extended and this track has any edit, then track duration is just the sum of the segment_duartions. */
5329 for( lsmash_entry_t
*entry
= trak
->edts
->elst
->list
->head
; entry
; entry
= entry
->next
)
5331 isom_elst_entry_t
*data
= (isom_elst_entry_t
*)entry
->data
;
5334 tkhd
->duration
+= data
->segment_duration
;
5337 if( tkhd
->duration
> UINT32_MAX
)
5339 if( !root
->fragment
&& !tkhd
->duration
)
5340 tkhd
->duration
= tkhd
->version
== 1 ? 0xffffffffffffffff : 0xffffffff;
5341 return isom_update_mvhd_duration( root
->moov
);
5344 int lsmash_update_track_duration( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t last_sample_delta
)
5346 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
5349 if( isom_update_mdhd_duration( trak
, last_sample_delta
) )
5351 /* If the presentation won't be extended and this track has any edit, we don't change or update duration in tkhd. */
5352 return (!root
->fragment
&& trak
->edts
&& trak
->edts
->elst
)
5353 ? isom_update_mvhd_duration( root
->moov
) /* Only update movie duration. */
5354 : isom_update_tkhd_duration( trak
); /* Also update movie duration internally. */
5357 int lsmash_set_avc_config( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t entry_number
,
5358 uint8_t configurationVersion
, uint8_t AVCProfileIndication
, uint8_t profile_compatibility
, uint8_t AVCLevelIndication
, uint8_t lengthSizeMinusOne
,
5359 uint8_t chroma_format
, uint8_t bit_depth_luma_minus8
, uint8_t bit_depth_chroma_minus8
)
5361 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
5362 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
|| !trak
->mdia
->minf
->stbl
->stsd
|| !trak
->mdia
->minf
->stbl
->stsd
->list
)
5364 isom_visual_entry_t
*data
= (isom_visual_entry_t
*)lsmash_get_entry_data( trak
->mdia
->minf
->stbl
->stsd
->list
, entry_number
);
5367 isom_avcC_t
*avcC
= (isom_avcC_t
*)data
->avcC
;
5370 avcC
->configurationVersion
= configurationVersion
;
5371 avcC
->AVCProfileIndication
= AVCProfileIndication
;
5372 avcC
->profile_compatibility
= profile_compatibility
;
5373 avcC
->AVCLevelIndication
= AVCLevelIndication
;
5374 avcC
->lengthSizeMinusOne
= lengthSizeMinusOne
;
5375 if( ISOM_REQUIRES_AVCC_EXTENSION( AVCProfileIndication
) )
5377 avcC
->chroma_format
= chroma_format
;
5378 avcC
->bit_depth_luma_minus8
= bit_depth_luma_minus8
;
5379 avcC
->bit_depth_chroma_minus8
= bit_depth_chroma_minus8
;
5384 static int isom_update_bitrate_info( isom_mdia_t
*mdia
)
5386 if( !mdia
|| !mdia
->mdhd
|| !mdia
->minf
|| !mdia
->minf
->stbl
5387 || !mdia
->minf
->stbl
->stsd
|| !mdia
->minf
->stbl
->stsd
->list
5388 || !mdia
->minf
->stbl
->stsz
|| !mdia
->minf
->stbl
->stts
|| !mdia
->minf
->stbl
->stts
->list
)
5390 /* Not supporting multi sample entries yet. */
5391 isom_sample_entry_t
*sample_entry
= (isom_sample_entry_t
*)lsmash_get_entry_data( mdia
->minf
->stbl
->stsd
->list
, 1 );
5394 struct bitrate_info_t
5396 uint32_t bufferSizeDB
;
5397 uint32_t maxBitrate
;
5398 uint32_t avgBitrate
;
5399 } info
= { 0, 0, 0 };
5402 uint32_t time_wnd
= 0;
5403 uint32_t timescale
= mdia
->mdhd
->timescale
;
5405 isom_stsz_t
*stsz
= mdia
->minf
->stbl
->stsz
;
5406 lsmash_entry_t
*stsz_entry
= stsz
->list
? stsz
->list
->head
: NULL
;
5407 lsmash_entry_t
*stts_entry
= mdia
->minf
->stbl
->stts
->list
->head
;
5408 isom_stts_entry_t
*stts_data
= NULL
;
5416 isom_stsz_entry_t
*stsz_data
= (isom_stsz_entry_t
*)stsz_entry
->data
;
5419 size
= stsz_data
->entry_size
;
5420 stsz_entry
= stsz_entry
->next
;
5423 size
= stsz
->sample_size
;
5425 dts
+= stts_data
->sample_delta
;
5426 stts_data
= (isom_stts_entry_t
*)stts_entry
->data
;
5427 if( ++i
== stts_data
->sample_count
)
5429 stts_entry
= stts_entry
->next
;
5432 if( info
.bufferSizeDB
< size
)
5433 info
.bufferSizeDB
= size
;
5434 info
.avgBitrate
+= size
;
5436 if( dts
> time_wnd
+ timescale
)
5438 if( rate
> info
.maxBitrate
)
5439 info
.maxBitrate
= rate
;
5444 double duration
= (double)mdia
->mdhd
->duration
/ timescale
;
5445 info
.avgBitrate
= (uint32_t)(info
.avgBitrate
/ duration
);
5446 if( !info
.maxBitrate
)
5447 info
.maxBitrate
= info
.avgBitrate
;
5449 info
.maxBitrate
*= 8;
5450 info
.avgBitrate
*= 8;
5451 /* set bitrate info */
5452 switch( sample_entry
->type
)
5454 case ISOM_CODEC_TYPE_AVC1_VIDEO
:
5455 case ISOM_CODEC_TYPE_AVC2_VIDEO
:
5456 case ISOM_CODEC_TYPE_AVCP_VIDEO
:
5458 isom_visual_entry_t
*stsd_data
= (isom_visual_entry_t
*)sample_entry
;
5461 isom_btrt_t
*btrt
= stsd_data
->btrt
;
5464 btrt
->bufferSizeDB
= info
.bufferSizeDB
;
5465 btrt
->maxBitrate
= info
.maxBitrate
;
5466 btrt
->avgBitrate
= info
.avgBitrate
;
5470 case ISOM_CODEC_TYPE_MP4V_VIDEO
:
5472 isom_visual_entry_t
*stsd_data
= (isom_visual_entry_t
*)sample_entry
;
5473 if( !stsd_data
|| !stsd_data
->esds
|| !stsd_data
->esds
->ES
)
5475 isom_esds_t
*esds
= stsd_data
->esds
;
5476 /* FIXME: avgBitrate is 0 only if VBR in proper. */
5477 if( mp4sys_update_DecoderConfigDescriptor( esds
->ES
, info
.bufferSizeDB
, info
.maxBitrate
, 0 ) )
5481 case ISOM_CODEC_TYPE_MP4A_AUDIO
:
5483 isom_esds_t
*esds
= NULL
;
5484 if( ((isom_audio_entry_t
*)sample_entry
)->version
)
5486 /* MPEG-4 Audio in QTFF */
5487 isom_audio_entry_t
*stsd_data
= (isom_audio_entry_t
*)sample_entry
;
5488 if( !stsd_data
|| !stsd_data
->wave
|| !stsd_data
->wave
->esds
|| !stsd_data
->wave
->esds
->ES
)
5490 esds
= stsd_data
->wave
->esds
;
5494 isom_audio_entry_t
*stsd_data
= (isom_audio_entry_t
*)sample_entry
;
5495 if( !stsd_data
|| !stsd_data
->esds
|| !stsd_data
->esds
->ES
)
5497 esds
= stsd_data
->esds
;
5499 /* FIXME: avgBitrate is 0 only if VBR in proper. */
5500 if( mp4sys_update_DecoderConfigDescriptor( esds
->ES
, info
.bufferSizeDB
, info
.maxBitrate
, 0 ) )
5504 case ISOM_CODEC_TYPE_ALAC_AUDIO
:
5506 isom_audio_entry_t
*alac
= (isom_audio_entry_t
*)sample_entry
;
5509 if( alac
->exdata_length
< 36 || !alac
->exdata
)
5511 isom_wave_t
*wave
= alac
->wave
;
5512 if( !wave
|| wave
->exdata_length
< 36 || !wave
->exdata
)
5514 break; /* Apparently, average bitrate field is 0. */
5516 uint8_t *exdata
= (uint8_t *)alac
->exdata
+ 28;
5517 exdata
[0] = (info
.avgBitrate
>> 24) & 0xff;
5518 exdata
[1] = (info
.avgBitrate
>> 16) & 0xff;
5519 exdata
[2] = (info
.avgBitrate
>> 8) & 0xff;
5520 exdata
[3] = info
.avgBitrate
& 0xff;
5529 static int isom_check_mandatory_boxes( lsmash_root_t
*root
)
5533 if( !root
->moov
|| !root
->moov
->mvhd
)
5535 if( !root
->moov
->trak_list
)
5537 /* A movie requires at least one track. */
5538 if( !root
->moov
->trak_list
->head
)
5540 for( lsmash_entry_t
*entry
= root
->moov
->trak_list
->head
; entry
; entry
= entry
->next
)
5542 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)entry
->data
;
5546 || !trak
->mdia
->mdhd
5547 || !trak
->mdia
->hdlr
5548 || !trak
->mdia
->minf
5549 || !trak
->mdia
->minf
->dinf
5550 || !trak
->mdia
->minf
->dinf
->dref
5551 || !trak
->mdia
->minf
->stbl
5552 || !trak
->mdia
->minf
->stbl
->stsd
5553 || !trak
->mdia
->minf
->stbl
->stsz
5554 || !trak
->mdia
->minf
->stbl
->stts
5555 || !trak
->mdia
->minf
->stbl
->stsc
5556 || !trak
->mdia
->minf
->stbl
->stco
)
5558 if( root
->qt_compatible
&& !trak
->mdia
->minf
->hdlr
)
5560 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
5561 if( !stbl
->stsd
->list
|| !stbl
->stsd
->list
->head
)
5564 && (!stbl
->stsd
->list
|| !stbl
->stsd
->list
->head
5565 || !stbl
->stts
->list
|| !stbl
->stts
->list
->head
5566 || !stbl
->stsc
->list
|| !stbl
->stsc
->list
->head
5567 || !stbl
->stco
->list
|| !stbl
->stco
->list
->head
) )
5570 if( !root
->fragment
)
5572 if( !root
->moov
->mvex
|| !root
->moov
->mvex
->trex_list
)
5574 for( lsmash_entry_t
*entry
= root
->moov
->mvex
->trex_list
->head
; entry
; entry
= entry
->next
)
5575 if( !entry
->data
) /* trex */
5580 static inline uint64_t isom_get_current_mp4time( void )
5582 return (uint64_t)time( NULL
) + ISOM_MAC_EPOCH_OFFSET
;
5585 static int isom_set_media_creation_time( isom_trak_entry_t
*trak
, uint64_t current_mp4time
)
5587 if( !trak
->mdia
|| !trak
->mdia
->mdhd
)
5589 isom_mdhd_t
*mdhd
= trak
->mdia
->mdhd
;
5590 if( !mdhd
->creation_time
)
5591 mdhd
->creation_time
= mdhd
->modification_time
= current_mp4time
;
5595 static int isom_set_track_creation_time( isom_trak_entry_t
*trak
, uint64_t current_mp4time
)
5597 if( !trak
|| !trak
->tkhd
)
5599 isom_tkhd_t
*tkhd
= trak
->tkhd
;
5600 if( !tkhd
->creation_time
)
5601 tkhd
->creation_time
= tkhd
->modification_time
= current_mp4time
;
5602 if( isom_set_media_creation_time( trak
, current_mp4time
) )
5607 static int isom_set_movie_creation_time( lsmash_root_t
*root
)
5609 if( !root
|| !root
->moov
|| !root
->moov
->mvhd
|| !root
->moov
->trak_list
)
5611 uint64_t current_mp4time
= isom_get_current_mp4time();
5612 for( uint32_t i
= 1; i
<= root
->moov
->trak_list
->entry_count
; i
++ )
5613 if( isom_set_track_creation_time( isom_get_trak( root
, i
), current_mp4time
) )
5615 isom_mvhd_t
*mvhd
= root
->moov
->mvhd
;
5616 if( !mvhd
->creation_time
)
5617 mvhd
->creation_time
= mvhd
->modification_time
= current_mp4time
;
5621 #define CHECK_LARGESIZE( size ) if( (size) > UINT32_MAX ) (size) += 8
5623 static uint64_t isom_update_mvhd_size( isom_mvhd_t
*mvhd
)
5628 if( mvhd
->creation_time
> UINT32_MAX
|| mvhd
->modification_time
> UINT32_MAX
|| mvhd
->duration
> UINT32_MAX
)
5630 mvhd
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 96 + (uint64_t)mvhd
->version
* 12;
5631 CHECK_LARGESIZE( mvhd
->size
);
5635 static uint64_t isom_update_iods_size( isom_iods_t
*iods
)
5637 if( !iods
|| !iods
->OD
)
5639 iods
->size
= ISOM_FULLBOX_COMMON_SIZE
+ mp4sys_update_ObjectDescriptor_size( iods
->OD
);
5640 CHECK_LARGESIZE( iods
->size
);
5644 static uint64_t isom_update_tkhd_size( isom_tkhd_t
*tkhd
)
5649 if( tkhd
->creation_time
> UINT32_MAX
|| tkhd
->modification_time
> UINT32_MAX
|| tkhd
->duration
> UINT32_MAX
)
5651 tkhd
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 80 + (uint64_t)tkhd
->version
* 12;
5652 CHECK_LARGESIZE( tkhd
->size
);
5656 static uint64_t isom_update_clef_size( isom_clef_t
*clef
)
5660 clef
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 8;
5661 CHECK_LARGESIZE( clef
->size
);
5665 static uint64_t isom_update_prof_size( isom_prof_t
*prof
)
5669 prof
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 8;
5670 CHECK_LARGESIZE( prof
->size
);
5674 static uint64_t isom_update_enof_size( isom_enof_t
*enof
)
5678 enof
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 8;
5679 CHECK_LARGESIZE( enof
->size
);
5683 static uint64_t isom_update_tapt_size( isom_tapt_t
*tapt
)
5687 tapt
->size
= ISOM_BASEBOX_COMMON_SIZE
5688 + isom_update_clef_size( tapt
->clef
)
5689 + isom_update_prof_size( tapt
->prof
)
5690 + isom_update_enof_size( tapt
->enof
);
5691 CHECK_LARGESIZE( tapt
->size
);
5695 static uint64_t isom_update_elst_size( isom_elst_t
*elst
)
5697 if( !elst
|| !elst
->list
)
5701 for( lsmash_entry_t
*entry
= elst
->list
->head
; entry
; entry
= entry
->next
, i
++ )
5703 isom_elst_entry_t
*data
= (isom_elst_entry_t
*)entry
->data
;
5704 if( data
->segment_duration
> UINT32_MAX
|| data
->media_time
> INT32_MAX
|| data
->media_time
< INT32_MIN
)
5707 elst
->size
= ISOM_LIST_FULLBOX_COMMON_SIZE
+ (uint64_t)i
* ( elst
->version
? 20 : 12 );
5708 CHECK_LARGESIZE( elst
->size
);
5712 static uint64_t isom_update_edts_size( isom_edts_t
*edts
)
5716 edts
->size
= ISOM_BASEBOX_COMMON_SIZE
+ isom_update_elst_size( edts
->elst
);
5717 CHECK_LARGESIZE( edts
->size
);
5721 static uint64_t isom_update_tref_size( isom_tref_t
*tref
)
5725 tref
->size
= ISOM_BASEBOX_COMMON_SIZE
;
5726 if( tref
->ref_list
)
5727 for( lsmash_entry_t
*entry
= tref
->ref_list
->head
; entry
; entry
= entry
->next
)
5729 isom_tref_type_t
*ref
= (isom_tref_type_t
*)entry
->data
;
5730 ref
->size
= ISOM_BASEBOX_COMMON_SIZE
+ (uint64_t)ref
->ref_count
* 4;
5731 CHECK_LARGESIZE( ref
->size
);
5732 tref
->size
+= ref
->size
;
5734 CHECK_LARGESIZE( tref
->size
);
5738 static uint64_t isom_update_mdhd_size( isom_mdhd_t
*mdhd
)
5743 if( mdhd
->creation_time
> UINT32_MAX
|| mdhd
->modification_time
> UINT32_MAX
|| mdhd
->duration
> UINT32_MAX
)
5745 mdhd
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 20 + (uint64_t)mdhd
->version
* 12;
5746 CHECK_LARGESIZE( mdhd
->size
);
5750 static uint64_t isom_update_hdlr_size( isom_hdlr_t
*hdlr
)
5754 hdlr
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 20 + (uint64_t)hdlr
->componentName_length
;
5755 CHECK_LARGESIZE( hdlr
->size
);
5759 static uint64_t isom_update_dref_entry_size( isom_dref_entry_t
*urln
)
5763 urln
->size
= ISOM_FULLBOX_COMMON_SIZE
+ (uint64_t)urln
->name_length
+ urln
->location_length
;
5764 CHECK_LARGESIZE( urln
->size
);
5768 static uint64_t isom_update_dref_size( isom_dref_t
*dref
)
5770 if( !dref
|| !dref
->list
)
5772 dref
->size
= ISOM_LIST_FULLBOX_COMMON_SIZE
;
5774 for( lsmash_entry_t
*entry
= dref
->list
->head
; entry
; entry
= entry
->next
)
5776 isom_dref_entry_t
*data
= (isom_dref_entry_t
*)entry
->data
;
5777 dref
->size
+= isom_update_dref_entry_size( data
);
5779 CHECK_LARGESIZE( dref
->size
);
5783 static uint64_t isom_update_dinf_size( isom_dinf_t
*dinf
)
5787 dinf
->size
= ISOM_BASEBOX_COMMON_SIZE
+ isom_update_dref_size( dinf
->dref
);
5788 CHECK_LARGESIZE( dinf
->size
);
5792 static uint64_t isom_update_vmhd_size( isom_vmhd_t
*vmhd
)
5796 vmhd
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 8;
5797 CHECK_LARGESIZE( vmhd
->size
);
5801 static uint64_t isom_update_smhd_size( isom_smhd_t
*smhd
)
5805 smhd
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 4;
5806 CHECK_LARGESIZE( smhd
->size
);
5810 static uint64_t isom_update_hmhd_size( isom_hmhd_t
*hmhd
)
5814 hmhd
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 16;
5815 CHECK_LARGESIZE( hmhd
->size
);
5819 static uint64_t isom_update_nmhd_size( isom_nmhd_t
*nmhd
)
5823 nmhd
->size
= ISOM_FULLBOX_COMMON_SIZE
;
5824 CHECK_LARGESIZE( nmhd
->size
);
5828 static uint64_t isom_update_gmin_size( isom_gmin_t
*gmin
)
5832 gmin
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 12;
5833 CHECK_LARGESIZE( gmin
->size
);
5837 static uint64_t isom_update_text_size( isom_text_t
*text
)
5841 text
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 36;
5842 CHECK_LARGESIZE( text
->size
);
5846 static uint64_t isom_update_gmhd_size( isom_gmhd_t
*gmhd
)
5850 gmhd
->size
= ISOM_BASEBOX_COMMON_SIZE
5851 + isom_update_gmin_size( gmhd
->gmin
)
5852 + isom_update_text_size( gmhd
->text
);
5853 CHECK_LARGESIZE( gmhd
->size
);
5857 static uint64_t isom_update_pasp_size( isom_pasp_t
*pasp
)
5861 pasp
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 8;
5862 CHECK_LARGESIZE( pasp
->size
);
5866 static uint64_t isom_update_clap_size( isom_clap_t
*clap
)
5870 clap
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 32;
5871 CHECK_LARGESIZE( clap
->size
);
5875 static uint64_t isom_update_colr_size( isom_colr_t
*colr
)
5877 if( !colr
|| colr
->color_parameter_type
== QT_COLOR_PARAMETER_TYPE_PROF
)
5879 colr
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 10;
5880 CHECK_LARGESIZE( colr
->size
);
5884 static uint64_t isom_update_stsl_size( isom_stsl_t
*stsl
)
5888 stsl
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 6;
5889 CHECK_LARGESIZE( stsl
->size
);
5893 static uint64_t isom_update_esds_size( isom_esds_t
*esds
)
5897 esds
->size
= ISOM_FULLBOX_COMMON_SIZE
+ mp4sys_update_ES_Descriptor_size( esds
->ES
);
5898 CHECK_LARGESIZE( esds
->size
);
5902 static uint64_t isom_update_avcC_size( isom_avcC_t
*avcC
)
5904 if( !avcC
|| !avcC
->sequenceParameterSets
|| !avcC
->pictureParameterSets
)
5906 uint64_t size
= ISOM_BASEBOX_COMMON_SIZE
+ 7;
5907 for( lsmash_entry_t
*entry
= avcC
->sequenceParameterSets
->head
; entry
; entry
= entry
->next
)
5909 isom_avcC_ps_entry_t
*data
= (isom_avcC_ps_entry_t
*)entry
->data
;
5910 size
+= 2 + data
->parameterSetLength
;
5912 for( lsmash_entry_t
*entry
= avcC
->pictureParameterSets
->head
; entry
; entry
= entry
->next
)
5914 isom_avcC_ps_entry_t
*data
= (isom_avcC_ps_entry_t
*)entry
->data
;
5915 size
+= 2 + data
->parameterSetLength
;
5917 if( ISOM_REQUIRES_AVCC_EXTENSION( avcC
->AVCProfileIndication
) )
5920 for( lsmash_entry_t
*entry
= avcC
->sequenceParameterSetExt
->head
; entry
; entry
= entry
->next
)
5922 isom_avcC_ps_entry_t
*data
= (isom_avcC_ps_entry_t
*)entry
->data
;
5923 size
+= 2 + data
->parameterSetLength
;
5927 CHECK_LARGESIZE( avcC
->size
);
5931 static uint64_t isom_update_btrt_size( isom_btrt_t
*btrt
)
5935 btrt
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 12;
5936 CHECK_LARGESIZE( btrt
->size
);
5940 static uint64_t isom_update_visual_entry_size( isom_visual_entry_t
*visual
)
5944 visual
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 78
5945 + isom_update_clap_size( visual
->clap
)
5946 + isom_update_pasp_size( visual
->pasp
)
5947 + isom_update_colr_size( visual
->colr
)
5948 + isom_update_stsl_size( visual
->stsl
)
5949 + isom_update_esds_size( visual
->esds
)
5950 + isom_update_avcC_size( visual
->avcC
)
5951 + isom_update_btrt_size( visual
->btrt
);
5952 CHECK_LARGESIZE( visual
->size
);
5953 return visual
->size
;
5957 static uint64_t isom_update_mp4s_entry_size( isom_mp4s_entry_t
*mp4s
)
5959 if( !mp4s
|| mp4s
->type
!= ISOM_CODEC_TYPE_MP4S_SYSTEM
)
5961 mp4s
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 8 + isom_update_esds_size( mp4s
->esds
);
5962 CHECK_LARGESIZE( mp4s
->size
);
5967 static uint64_t isom_update_frma_size( isom_frma_t
*frma
)
5971 frma
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 4;
5972 CHECK_LARGESIZE( frma
->size
);
5976 static uint64_t isom_update_enda_size( isom_enda_t
*enda
)
5980 enda
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 2;
5981 CHECK_LARGESIZE( enda
->size
);
5985 static uint64_t isom_update_mp4a_size( isom_mp4a_t
*mp4a
)
5989 mp4a
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 4;
5990 CHECK_LARGESIZE( mp4a
->size
);
5994 static uint64_t isom_update_terminator_size( isom_terminator_t
*terminator
)
5998 terminator
->size
= ISOM_BASEBOX_COMMON_SIZE
;
5999 CHECK_LARGESIZE( terminator
->size
);
6000 return terminator
->size
;
6003 static uint64_t isom_update_wave_size( isom_wave_t
*wave
)
6007 wave
->size
= ISOM_BASEBOX_COMMON_SIZE
6008 + isom_update_frma_size( wave
->frma
)
6009 + isom_update_enda_size( wave
->enda
)
6010 + isom_update_mp4a_size( wave
->mp4a
)
6011 + isom_update_esds_size( wave
->esds
)
6012 + isom_update_terminator_size( wave
->terminator
)
6013 + (uint64_t)wave
->exdata_length
;
6014 CHECK_LARGESIZE( wave
->size
);
6018 static uint64_t isom_update_chan_size( isom_chan_t
*chan
)
6022 chan
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 12 + 20 * (uint64_t)chan
->numberChannelDescriptions
;
6023 CHECK_LARGESIZE( chan
->size
);
6027 static uint64_t isom_update_audio_entry_size( isom_audio_entry_t
*audio
)
6031 audio
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 28
6032 + isom_update_esds_size( audio
->esds
)
6033 + isom_update_wave_size( audio
->wave
)
6034 + isom_update_chan_size( audio
->chan
)
6035 + (uint64_t)audio
->exdata_length
;
6036 if( audio
->version
== 1 )
6038 else if( audio
->version
== 2 )
6040 CHECK_LARGESIZE( audio
->size
);
6044 static uint64_t isom_update_text_entry_size( isom_text_entry_t
*text
)
6048 text
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 51 + (uint64_t)text
->font_name_length
;
6049 CHECK_LARGESIZE( text
->size
);
6053 static uint64_t isom_update_ftab_size( isom_ftab_t
*ftab
)
6055 if( !ftab
|| !ftab
->list
)
6057 ftab
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 2;
6058 for( lsmash_entry_t
*entry
= ftab
->list
->head
; entry
; entry
= entry
->next
)
6060 isom_font_record_t
*data
= (isom_font_record_t
*)entry
->data
;
6061 ftab
->size
+= 3 + data
->font_name_length
;
6063 CHECK_LARGESIZE( ftab
->size
);
6067 static uint64_t isom_update_tx3g_entry_size( isom_tx3g_entry_t
*tx3g
)
6071 tx3g
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 38 + isom_update_ftab_size( tx3g
->ftab
);
6072 CHECK_LARGESIZE( tx3g
->size
);
6076 static uint64_t isom_update_stsd_size( isom_stsd_t
*stsd
)
6078 if( !stsd
|| !stsd
->list
)
6080 uint64_t size
= ISOM_LIST_FULLBOX_COMMON_SIZE
;
6081 for( lsmash_entry_t
*entry
= stsd
->list
->head
; entry
; entry
= entry
->next
)
6083 isom_sample_entry_t
*data
= (isom_sample_entry_t
*)entry
->data
;
6084 switch( data
->type
)
6086 case ISOM_CODEC_TYPE_AVC1_VIDEO
:
6087 #ifdef LSMASH_DEMUXER_ENABLED
6088 case ISOM_CODEC_TYPE_MP4V_VIDEO
:
6091 case ISOM_CODEC_TYPE_AVC2_VIDEO
:
6092 case ISOM_CODEC_TYPE_AVCP_VIDEO
:
6093 case ISOM_CODEC_TYPE_SVC1_VIDEO
:
6094 case ISOM_CODEC_TYPE_MVC1_VIDEO
:
6095 case ISOM_CODEC_TYPE_MVC2_VIDEO
:
6096 case ISOM_CODEC_TYPE_DRAC_VIDEO
:
6097 case ISOM_CODEC_TYPE_ENCV_VIDEO
:
6098 case ISOM_CODEC_TYPE_MJP2_VIDEO
:
6099 case ISOM_CODEC_TYPE_S263_VIDEO
:
6100 case ISOM_CODEC_TYPE_VC_1_VIDEO
:
6102 size
+= isom_update_visual_entry_size( (isom_visual_entry_t
*)data
);
6105 case ISOM_CODEC_TYPE_MP4S_SYSTEM
:
6106 size
+= isom_update_mp4s_entry_size( (isom_mp4s_entry_t
*)data
);
6109 case ISOM_CODEC_TYPE_MP4A_AUDIO
:
6110 case ISOM_CODEC_TYPE_AC_3_AUDIO
:
6111 case ISOM_CODEC_TYPE_ALAC_AUDIO
:
6112 case ISOM_CODEC_TYPE_SAMR_AUDIO
:
6113 case ISOM_CODEC_TYPE_SAWB_AUDIO
:
6114 case QT_CODEC_TYPE_23NI_AUDIO
:
6115 case QT_CODEC_TYPE_NONE_AUDIO
:
6116 case QT_CODEC_TYPE_LPCM_AUDIO
:
6117 case QT_CODEC_TYPE_RAW_AUDIO
:
6118 case QT_CODEC_TYPE_SOWT_AUDIO
:
6119 case QT_CODEC_TYPE_TWOS_AUDIO
:
6120 case QT_CODEC_TYPE_FL32_AUDIO
:
6121 case QT_CODEC_TYPE_FL64_AUDIO
:
6122 case QT_CODEC_TYPE_IN24_AUDIO
:
6123 case QT_CODEC_TYPE_IN32_AUDIO
:
6124 case QT_CODEC_TYPE_NOT_SPECIFIED
:
6125 #ifdef LSMASH_DEMUXER_ENABLED
6126 case ISOM_CODEC_TYPE_EC_3_AUDIO
:
6129 case ISOM_CODEC_TYPE_DRA1_AUDIO
:
6130 case ISOM_CODEC_TYPE_DTSC_AUDIO
:
6131 case ISOM_CODEC_TYPE_DTSH_AUDIO
:
6132 case ISOM_CODEC_TYPE_DTSL_AUDIO
:
6133 case ISOM_CODEC_TYPE_ENCA_AUDIO
:
6134 case ISOM_CODEC_TYPE_G719_AUDIO
:
6135 case ISOM_CODEC_TYPE_G726_AUDIO
:
6136 case ISOM_CODEC_TYPE_M4AE_AUDIO
:
6137 case ISOM_CODEC_TYPE_MLPA_AUDIO
:
6138 case ISOM_CODEC_TYPE_RAW_AUDIO
:
6139 case ISOM_CODEC_TYPE_SAWP_AUDIO
:
6140 case ISOM_CODEC_TYPE_SEVC_AUDIO
:
6141 case ISOM_CODEC_TYPE_SQCP_AUDIO
:
6142 case ISOM_CODEC_TYPE_SSMV_AUDIO
:
6143 case ISOM_CODEC_TYPE_TWOS_AUDIO
:
6145 size
+= isom_update_audio_entry_size( (isom_audio_entry_t
*)data
);
6147 case ISOM_CODEC_TYPE_TX3G_TEXT
:
6148 size
+= isom_update_tx3g_entry_size( (isom_tx3g_entry_t
*)data
);
6150 case QT_CODEC_TYPE_TEXT_TEXT
:
6151 size
+= isom_update_text_entry_size( (isom_text_entry_t
*)data
);
6158 CHECK_LARGESIZE( stsd
->size
);
6162 static uint64_t isom_update_stts_size( isom_stts_t
*stts
)
6164 if( !stts
|| !stts
->list
)
6166 stts
->size
= ISOM_LIST_FULLBOX_COMMON_SIZE
+ (uint64_t)stts
->list
->entry_count
* 8;
6167 CHECK_LARGESIZE( stts
->size
);
6171 static uint64_t isom_update_ctts_size( isom_ctts_t
*ctts
)
6173 if( !ctts
|| !ctts
->list
)
6175 ctts
->size
= ISOM_LIST_FULLBOX_COMMON_SIZE
+ (uint64_t)ctts
->list
->entry_count
* 8;
6176 CHECK_LARGESIZE( ctts
->size
);
6180 static uint64_t isom_update_cslg_size( isom_cslg_t
*cslg
)
6184 cslg
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 20;
6185 CHECK_LARGESIZE( cslg
->size
);
6189 static uint64_t isom_update_stsz_size( isom_stsz_t
*stsz
)
6193 stsz
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 8 + ( stsz
->list
? (uint64_t)stsz
->list
->entry_count
* 4 : 0 );
6194 CHECK_LARGESIZE( stsz
->size
);
6198 static uint64_t isom_update_stss_size( isom_stss_t
*stss
)
6200 if( !stss
|| !stss
->list
)
6202 stss
->size
= ISOM_LIST_FULLBOX_COMMON_SIZE
+ (uint64_t)stss
->list
->entry_count
* 4;
6203 CHECK_LARGESIZE( stss
->size
);
6207 static uint64_t isom_update_stps_size( isom_stps_t
*stps
)
6209 if( !stps
|| !stps
->list
)
6211 stps
->size
= ISOM_LIST_FULLBOX_COMMON_SIZE
+ (uint64_t)stps
->list
->entry_count
* 4;
6212 CHECK_LARGESIZE( stps
->size
);
6216 static uint64_t isom_update_sdtp_size( isom_sdtp_t
*sdtp
)
6218 if( !sdtp
|| !sdtp
->list
)
6220 sdtp
->size
= ISOM_FULLBOX_COMMON_SIZE
+ (uint64_t)sdtp
->list
->entry_count
;
6221 CHECK_LARGESIZE( sdtp
->size
);
6225 static uint64_t isom_update_stsc_size( isom_stsc_t
*stsc
)
6227 if( !stsc
|| !stsc
->list
)
6229 stsc
->size
= ISOM_LIST_FULLBOX_COMMON_SIZE
+ (uint64_t)stsc
->list
->entry_count
* 12;
6230 CHECK_LARGESIZE( stsc
->size
);
6234 static uint64_t isom_update_stco_size( isom_stco_t
*stco
)
6236 if( !stco
|| !stco
->list
)
6238 stco
->size
= ISOM_LIST_FULLBOX_COMMON_SIZE
+ (uint64_t)stco
->list
->entry_count
* (stco
->large_presentation
? 8 : 4);
6239 CHECK_LARGESIZE( stco
->size
);
6243 static uint64_t isom_update_sbgp_size( isom_sbgp_entry_t
*sbgp
)
6245 if( !sbgp
|| !sbgp
->list
)
6247 sbgp
->size
= ISOM_LIST_FULLBOX_COMMON_SIZE
+ 4 + (uint64_t)sbgp
->list
->entry_count
* 8;
6248 CHECK_LARGESIZE( sbgp
->size
);
6252 static uint64_t isom_update_sgpd_size( isom_sgpd_entry_t
*sgpd
)
6254 if( !sgpd
|| !sgpd
->list
)
6256 uint64_t size
= ISOM_LIST_FULLBOX_COMMON_SIZE
+ (1 + (sgpd
->version
== 1)) * 4;
6257 size
+= (uint64_t)sgpd
->list
->entry_count
* ((sgpd
->version
== 1) && !sgpd
->default_length
) * 4;
6258 switch( sgpd
->grouping_type
)
6260 case ISOM_GROUP_TYPE_RAP
:
6261 size
+= sgpd
->list
->entry_count
;
6263 case ISOM_GROUP_TYPE_ROLL
:
6264 size
+= (uint64_t)sgpd
->list
->entry_count
* 2;
6267 /* We don't consider other grouping types currently. */
6271 CHECK_LARGESIZE( sgpd
->size
);
6275 static uint64_t isom_update_stbl_size( isom_stbl_t
*stbl
)
6279 stbl
->size
= ISOM_BASEBOX_COMMON_SIZE
6280 + isom_update_stsd_size( stbl
->stsd
)
6281 + isom_update_stts_size( stbl
->stts
)
6282 + isom_update_ctts_size( stbl
->ctts
)
6283 + isom_update_cslg_size( stbl
->cslg
)
6284 + isom_update_stsz_size( stbl
->stsz
)
6285 + isom_update_stss_size( stbl
->stss
)
6286 + isom_update_stps_size( stbl
->stps
)
6287 + isom_update_sdtp_size( stbl
->sdtp
)
6288 + isom_update_stsc_size( stbl
->stsc
)
6289 + isom_update_stco_size( stbl
->stco
);
6290 if( stbl
->sgpd_list
)
6291 for( lsmash_entry_t
*entry
= stbl
->sgpd_list
->head
; entry
; entry
= entry
->next
)
6292 stbl
->size
+= isom_update_sgpd_size( (isom_sgpd_entry_t
*)entry
->data
);
6293 if( stbl
->sbgp_list
)
6294 for( lsmash_entry_t
*entry
= stbl
->sbgp_list
->head
; entry
; entry
= entry
->next
)
6295 stbl
->size
+= isom_update_sbgp_size( (isom_sbgp_entry_t
*)entry
->data
);
6296 CHECK_LARGESIZE( stbl
->size
);
6300 static uint64_t isom_update_minf_size( isom_minf_t
*minf
)
6304 minf
->size
= ISOM_BASEBOX_COMMON_SIZE
6305 + isom_update_vmhd_size( minf
->vmhd
)
6306 + isom_update_smhd_size( minf
->smhd
)
6307 + isom_update_hmhd_size( minf
->hmhd
)
6308 + isom_update_nmhd_size( minf
->nmhd
)
6309 + isom_update_gmhd_size( minf
->gmhd
)
6310 + isom_update_hdlr_size( minf
->hdlr
)
6311 + isom_update_dinf_size( minf
->dinf
)
6312 + isom_update_stbl_size( minf
->stbl
);
6313 CHECK_LARGESIZE( minf
->size
);
6317 static uint64_t isom_update_mdia_size( isom_mdia_t
*mdia
)
6321 mdia
->size
= ISOM_BASEBOX_COMMON_SIZE
6322 + isom_update_mdhd_size( mdia
->mdhd
)
6323 + isom_update_hdlr_size( mdia
->hdlr
)
6324 + isom_update_minf_size( mdia
->minf
);
6325 CHECK_LARGESIZE( mdia
->size
);
6329 static uint64_t isom_update_chpl_size( isom_chpl_t
*chpl
)
6333 chpl
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 4 * (chpl
->version
== 1) + 1;
6334 for( lsmash_entry_t
*entry
= chpl
->list
->head
; entry
; entry
= entry
->next
)
6336 isom_chpl_entry_t
*data
= (isom_chpl_entry_t
*)entry
->data
;
6337 chpl
->size
+= 9 + data
->chapter_name_length
;
6339 CHECK_LARGESIZE( chpl
->size
);
6343 static uint64_t isom_update_mean_size( isom_mean_t
*mean
)
6347 mean
->size
= ISOM_FULLBOX_COMMON_SIZE
+ mean
->meaning_string_length
;
6348 CHECK_LARGESIZE( mean
->size
);
6352 static uint64_t isom_update_name_size( isom_name_t
*name
)
6356 name
->size
= ISOM_FULLBOX_COMMON_SIZE
+ name
->name_length
;
6357 CHECK_LARGESIZE( name
->size
);
6361 static uint64_t isom_update_data_size( isom_data_t
*data
)
6365 data
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 8 + data
->value_length
;
6366 CHECK_LARGESIZE( data
->size
);
6370 static uint64_t isom_update_metaitem_size( isom_metaitem_t
*metaitem
)
6374 metaitem
->size
= ISOM_BASEBOX_COMMON_SIZE
6375 + isom_update_mean_size( metaitem
->mean
)
6376 + isom_update_name_size( metaitem
->name
)
6377 + isom_update_data_size( metaitem
->data
);
6378 CHECK_LARGESIZE( metaitem
->size
);
6379 return metaitem
->size
;
6382 static uint64_t isom_update_ilst_size( isom_ilst_t
*ilst
)
6386 ilst
->size
= ISOM_BASEBOX_COMMON_SIZE
;
6387 for( lsmash_entry_t
*entry
= ilst
->item_list
->head
; entry
; entry
= entry
->next
)
6388 ilst
->size
+= isom_update_metaitem_size( (isom_metaitem_t
*)entry
->data
);
6389 CHECK_LARGESIZE( ilst
->size
);
6393 static uint64_t isom_update_meta_size( isom_meta_t
*meta
)
6397 meta
->size
= ISOM_FULLBOX_COMMON_SIZE
6398 + isom_update_hdlr_size( meta
->hdlr
)
6399 + isom_update_dinf_size( meta
->dinf
)
6400 + isom_update_ilst_size( meta
->ilst
);
6401 CHECK_LARGESIZE( meta
->size
);
6405 static uint64_t isom_update_udta_size( isom_udta_t
*udta_moov
, isom_udta_t
*udta_trak
)
6407 isom_udta_t
*udta
= udta_trak
? udta_trak
: udta_moov
? udta_moov
: NULL
;
6410 udta
->size
= ISOM_BASEBOX_COMMON_SIZE
6411 + ( udta_moov
? isom_update_chpl_size( udta
->chpl
) : 0 )
6412 + isom_update_meta_size( udta
->meta
);
6413 CHECK_LARGESIZE( udta
->size
);
6417 static uint64_t isom_update_trak_entry_size( isom_trak_entry_t
*trak
)
6421 trak
->size
= ISOM_BASEBOX_COMMON_SIZE
6422 + isom_update_tkhd_size( trak
->tkhd
)
6423 + isom_update_tapt_size( trak
->tapt
)
6424 + isom_update_edts_size( trak
->edts
)
6425 + isom_update_tref_size( trak
->tref
)
6426 + isom_update_mdia_size( trak
->mdia
)
6427 + isom_update_udta_size( NULL
, trak
->udta
)
6428 + isom_update_meta_size( trak
->meta
);
6429 CHECK_LARGESIZE( trak
->size
);
6433 static uint64_t isom_update_mehd_size( isom_mehd_t
*mehd
)
6437 if( mehd
->fragment_duration
> UINT32_MAX
)
6439 mehd
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 4 * (1 + (mehd
->version
== 1));
6440 CHECK_LARGESIZE( mehd
->size
);
6444 static uint64_t isom_update_trex_entry_size( isom_trex_entry_t
*trex
)
6448 trex
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 20;
6449 CHECK_LARGESIZE( trex
->size
);
6453 static uint64_t isom_update_mvex_size( isom_mvex_t
*mvex
)
6457 mvex
->size
= ISOM_BASEBOX_COMMON_SIZE
;
6458 if( mvex
->trex_list
)
6459 for( lsmash_entry_t
*entry
= mvex
->trex_list
->head
; entry
; entry
= entry
->next
)
6461 isom_trex_entry_t
*trex
= (isom_trex_entry_t
*)entry
->data
;
6462 mvex
->size
+= isom_update_trex_entry_size( trex
);
6464 if( mvex
->root
->bs
->stream
!= stdout
)
6465 mvex
->size
+= mvex
->mehd
? isom_update_mehd_size( mvex
->mehd
) : 20; /* 20 bytes is of placeholder. */
6466 CHECK_LARGESIZE( mvex
->size
);
6470 static int isom_update_moov_size( isom_moov_t
*moov
)
6474 moov
->size
= ISOM_BASEBOX_COMMON_SIZE
6475 + isom_update_mvhd_size( moov
->mvhd
)
6476 + isom_update_iods_size( moov
->iods
)
6477 + isom_update_udta_size( moov
->udta
, NULL
)
6478 + isom_update_meta_size( moov
->meta
)
6479 + isom_update_mvex_size( moov
->mvex
);
6480 if( moov
->trak_list
)
6481 for( lsmash_entry_t
*entry
= moov
->trak_list
->head
; entry
; entry
= entry
->next
)
6483 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)entry
->data
;
6484 moov
->size
+= isom_update_trak_entry_size( trak
);
6486 CHECK_LARGESIZE( moov
->size
);
6490 static uint64_t isom_update_mfhd_size( isom_mfhd_t
*mfhd
)
6494 mfhd
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 4;
6495 CHECK_LARGESIZE( mfhd
->size
);
6499 static uint64_t isom_update_tfhd_size( isom_tfhd_t
*tfhd
)
6503 tfhd
->size
= ISOM_FULLBOX_COMMON_SIZE
6505 + 8 * !!( tfhd
->flags
& ISOM_TF_FLAGS_BASE_DATA_OFFSET_PRESENT
)
6506 + 4 * !!( tfhd
->flags
& ISOM_TF_FLAGS_SAMPLE_DESCRIPTION_INDEX_PRESENT
)
6507 + 4 * !!( tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT
)
6508 + 4 * !!( tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_SAMPLE_SIZE_PRESENT
)
6509 + 4 * !!( tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_SAMPLE_FLAGS_PRESENT
);
6510 CHECK_LARGESIZE( tfhd
->size
);
6514 static uint64_t isom_update_trun_entry_size( isom_trun_entry_t
*trun
)
6518 trun
->size
= ISOM_FULLBOX_COMMON_SIZE
6520 + 4 * !!( trun
->flags
& ISOM_TR_FLAGS_DATA_OFFSET_PRESENT
)
6521 + 4 * !!( trun
->flags
& ISOM_TR_FLAGS_FIRST_SAMPLE_FLAGS_PRESENT
);
6522 uint64_t row_size
= 4 * !!( trun
->flags
& ISOM_TR_FLAGS_SAMPLE_DURATION_PRESENT
)
6523 + 4 * !!( trun
->flags
& ISOM_TR_FLAGS_SAMPLE_SIZE_PRESENT
)
6524 + 4 * !!( trun
->flags
& ISOM_TR_FLAGS_SAMPLE_FLAGS_PRESENT
)
6525 + 4 * !!( trun
->flags
& ISOM_TR_FLAGS_SAMPLE_COMPOSITION_TIME_OFFSET_PRESENT
);
6526 trun
->size
+= row_size
* trun
->sample_count
;
6527 CHECK_LARGESIZE( trun
->size
);
6531 static uint64_t isom_update_traf_entry_size( isom_traf_entry_t
*traf
)
6535 traf
->size
= ISOM_BASEBOX_COMMON_SIZE
+ isom_update_tfhd_size( traf
->tfhd
);
6536 if( traf
->trun_list
)
6537 for( lsmash_entry_t
*entry
= traf
->trun_list
->head
; entry
; entry
= entry
->next
)
6539 isom_trun_entry_t
*trun
= (isom_trun_entry_t
*)entry
->data
;
6540 traf
->size
+= isom_update_trun_entry_size( trun
);
6542 CHECK_LARGESIZE( traf
->size
);
6546 static int isom_update_moof_entry_size( isom_moof_entry_t
*moof
)
6550 moof
->size
= ISOM_BASEBOX_COMMON_SIZE
+ isom_update_mfhd_size( moof
->mfhd
);
6551 if( moof
->traf_list
)
6552 for( lsmash_entry_t
*entry
= moof
->traf_list
->head
; entry
; entry
= entry
->next
)
6554 isom_traf_entry_t
*traf
= (isom_traf_entry_t
*)entry
->data
;
6555 moof
->size
+= isom_update_traf_entry_size( traf
);
6557 CHECK_LARGESIZE( moof
->size
);
6561 static uint64_t isom_update_tfra_entry_size( isom_tfra_entry_t
*tfra
)
6565 tfra
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 12;
6566 uint32_t entry_size
= 8 * (1 + (tfra
->version
== 1))
6567 + tfra
->length_size_of_traf_num
+ 1
6568 + tfra
->length_size_of_trun_num
+ 1
6569 + tfra
->length_size_of_sample_num
+ 1;
6570 tfra
->size
+= entry_size
* tfra
->number_of_entry
;
6571 CHECK_LARGESIZE( tfra
->size
);
6575 static uint64_t isom_update_mfro_size( isom_mfro_t
*mfro
)
6579 mfro
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 4;
6580 CHECK_LARGESIZE( mfro
->size
);
6584 static int isom_update_mfra_size( isom_mfra_t
*mfra
)
6588 mfra
->size
= ISOM_BASEBOX_COMMON_SIZE
;
6589 if( mfra
->tfra_list
)
6590 for( lsmash_entry_t
*entry
= mfra
->tfra_list
->head
; entry
; entry
= entry
->next
)
6592 isom_tfra_entry_t
*tfra
= (isom_tfra_entry_t
*)entry
->data
;
6593 mfra
->size
+= isom_update_tfra_entry_size( tfra
);
6595 CHECK_LARGESIZE( mfra
->size
);
6598 mfra
->size
+= isom_update_mfro_size( mfra
->mfro
);
6599 mfra
->mfro
->length
= mfra
->size
;
6604 /*******************************
6606 *******************************/
6608 /*---- track manipulators ----*/
6610 void lsmash_delete_track( lsmash_root_t
*root
, uint32_t track_ID
)
6612 if( !root
|| !root
->moov
|| !root
->moov
->trak_list
)
6614 for( lsmash_entry_t
*entry
= root
->moov
->trak_list
->head
; entry
; entry
= entry
->next
)
6616 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)entry
->data
;
6617 if( !trak
|| !trak
->tkhd
)
6619 if( trak
->tkhd
->track_ID
== track_ID
)
6621 lsmash_entry_t
*next
= entry
->next
;
6622 lsmash_entry_t
*prev
= entry
->prev
;
6623 isom_remove_trak( trak
);
6637 uint32_t lsmash_create_track( lsmash_root_t
*root
, lsmash_media_type media_type
)
6639 isom_trak_entry_t
*trak
= isom_add_trak( root
);
6642 if( isom_add_tkhd( trak
, media_type
)
6643 || isom_add_mdia( trak
)
6644 || isom_add_mdhd( trak
->mdia
, root
->qt_compatible
? 0 : ISOM_LANGUAGE_CODE_UNDEFINED
)
6645 || isom_add_minf( trak
->mdia
)
6646 || isom_add_stbl( trak
->mdia
->minf
)
6647 || isom_add_dinf( trak
->mdia
->minf
)
6648 || isom_add_dref( trak
->mdia
->minf
->dinf
)
6649 || isom_add_stsd( trak
->mdia
->minf
->stbl
)
6650 || isom_add_stts( trak
->mdia
->minf
->stbl
)
6651 || isom_add_stsc( trak
->mdia
->minf
->stbl
)
6652 || isom_add_stco( trak
->mdia
->minf
->stbl
)
6653 || isom_add_stsz( trak
->mdia
->minf
->stbl
) )
6655 if( isom_add_hdlr( trak
->mdia
, NULL
, NULL
, media_type
) )
6657 if( root
->qt_compatible
&& isom_add_hdlr( NULL
, NULL
, trak
->mdia
->minf
, QT_REFERENCE_HANDLER_TYPE_URL
) )
6659 switch( media_type
)
6661 case ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK
:
6662 if( isom_add_vmhd( trak
->mdia
->minf
) )
6665 case ISOM_MEDIA_HANDLER_TYPE_AUDIO_TRACK
:
6666 if( isom_add_smhd( trak
->mdia
->minf
) )
6669 case ISOM_MEDIA_HANDLER_TYPE_HINT_TRACK
:
6670 if( isom_add_hmhd( trak
->mdia
->minf
) )
6673 case ISOM_MEDIA_HANDLER_TYPE_TEXT_TRACK
:
6674 if( root
->qt_compatible
|| root
->itunes_audio
)
6676 if( isom_add_gmhd( trak
->mdia
->minf
)
6677 || isom_add_gmin( trak
->mdia
->minf
->gmhd
)
6678 || isom_add_text( trak
->mdia
->minf
->gmhd
) )
6682 return 0; /* We support only reference text media track for chapter yet. */
6685 if( isom_add_nmhd( trak
->mdia
->minf
) )
6689 return trak
->tkhd
->track_ID
;
6692 uint32_t lsmash_get_track_ID( lsmash_root_t
*root
, uint32_t track_number
)
6694 if( !root
|| !root
->moov
)
6696 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)lsmash_get_entry_data( root
->moov
->trak_list
, track_number
);
6697 if( !trak
|| !trak
->tkhd
)
6699 return trak
->tkhd
->track_ID
;
6702 void lsmash_initialize_track_parameters( lsmash_track_parameters_t
*param
)
6704 memset( param
, 0, sizeof(lsmash_track_parameters_t
) );
6705 param
->audio_volume
= 0x0100;
6706 param
->matrix
[0] = 0x00010000;
6707 param
->matrix
[4] = 0x00010000;
6708 param
->matrix
[8] = 0x40000000;
6711 int lsmash_set_track_parameters( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_track_parameters_t
*param
)
6713 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6714 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->hdlr
|| !root
->moov
->mvhd
)
6716 /* Prepare Track Aperture Modes if required. */
6717 if( root
->qt_compatible
&& param
->aperture_modes
)
6719 if( !trak
->tapt
&& isom_add_tapt( trak
) )
6721 isom_tapt_t
*tapt
= trak
->tapt
;
6722 if( (!tapt
->clef
&& isom_add_clef( tapt
))
6723 || (!tapt
->prof
&& isom_add_prof( tapt
))
6724 || (!tapt
->enof
&& isom_add_enof( tapt
)) )
6728 isom_remove_tapt( trak
->tapt
);
6729 /* Set up Track Header. */
6730 uint32_t media_type
= trak
->mdia
->hdlr
->componentSubtype
;
6731 isom_tkhd_t
*tkhd
= trak
->tkhd
;
6732 tkhd
->flags
= param
->mode
;
6733 tkhd
->track_ID
= param
->track_ID
? param
->track_ID
: tkhd
->track_ID
;
6734 tkhd
->duration
= !trak
->edts
|| !trak
->edts
->elst
? param
->duration
: tkhd
->duration
;
6735 tkhd
->alternate_group
= root
->qt_compatible
|| root
->itunes_audio
|| root
->max_3gpp_version
>= 4 ? param
->alternate_group
: 0;
6736 if( root
->qt_compatible
|| root
->itunes_audio
)
6738 tkhd
->layer
= media_type
== ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK
? param
->video_layer
: 0;
6739 tkhd
->volume
= media_type
== ISOM_MEDIA_HANDLER_TYPE_AUDIO_TRACK
? param
->audio_volume
: 0;
6744 tkhd
->volume
= media_type
== ISOM_MEDIA_HANDLER_TYPE_AUDIO_TRACK
? 0x0100 : 0;
6746 for( int i
= 0; i
< 9; i
++ )
6747 tkhd
->matrix
[i
] = media_type
== ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK
? param
->matrix
[i
] : 0;
6748 tkhd
->width
= media_type
== ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK
? param
->display_width
: 0;
6749 tkhd
->height
= media_type
== ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK
? param
->display_height
: 0;
6750 /* Update next_track_ID if needed. */
6751 if( root
->moov
->mvhd
->next_track_ID
<= tkhd
->track_ID
)
6752 root
->moov
->mvhd
->next_track_ID
= tkhd
->track_ID
+ 1;
6756 int lsmash_get_track_parameters( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_track_parameters_t
*param
)
6758 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6761 isom_tkhd_t
*tkhd
= trak
->tkhd
;
6762 param
->mode
= tkhd
->flags
;
6763 param
->track_ID
= tkhd
->track_ID
;
6764 param
->duration
= tkhd
->duration
;
6765 param
->video_layer
= tkhd
->layer
;
6766 param
->alternate_group
= tkhd
->alternate_group
;
6767 param
->audio_volume
= tkhd
->volume
;
6768 for( int i
= 0; i
< 9; i
++ )
6769 param
->matrix
[i
] = tkhd
->matrix
[i
];
6770 param
->display_width
= tkhd
->width
;
6771 param
->display_height
= tkhd
->height
;
6772 param
->aperture_modes
= !!trak
->tapt
;
6776 static int isom_set_media_handler_name( lsmash_root_t
*root
, uint32_t track_ID
, char *handler_name
)
6778 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6779 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->hdlr
)
6781 isom_hdlr_t
*hdlr
= trak
->mdia
->hdlr
;
6782 uint8_t *name
= NULL
;
6783 uint32_t name_length
= strlen( handler_name
) + root
->isom_compatible
+ root
->qt_compatible
;
6784 if( root
->qt_compatible
)
6785 name_length
= LSMASH_MIN( name_length
, 255 );
6786 if( name_length
> hdlr
->componentName_length
&& hdlr
->componentName
)
6787 name
= realloc( hdlr
->componentName
, name_length
);
6788 else if( !hdlr
->componentName
)
6789 name
= malloc( name_length
);
6791 name
= hdlr
->componentName
;
6794 if( root
->qt_compatible
)
6795 name
[0] = name_length
& 0xff;
6796 memcpy( name
+ root
->qt_compatible
, handler_name
, strlen( handler_name
) );
6797 if( root
->isom_compatible
)
6798 name
[name_length
- 1] = 0;
6799 hdlr
->componentName
= name
;
6800 hdlr
->componentName_length
= name_length
;
6804 static int isom_set_data_handler_name( lsmash_root_t
*root
, uint32_t track_ID
, char *handler_name
)
6806 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6807 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->hdlr
)
6809 isom_hdlr_t
*hdlr
= trak
->mdia
->minf
->hdlr
;
6810 uint8_t *name
= NULL
;
6811 uint32_t name_length
= strlen( handler_name
) + root
->isom_compatible
+ root
->qt_compatible
;
6812 if( root
->qt_compatible
)
6813 name_length
= LSMASH_MIN( name_length
, 255 );
6814 if( name_length
> hdlr
->componentName_length
&& hdlr
->componentName
)
6815 name
= realloc( hdlr
->componentName
, name_length
);
6816 else if( !hdlr
->componentName
)
6817 name
= malloc( name_length
);
6819 name
= hdlr
->componentName
;
6822 if( root
->qt_compatible
)
6823 name
[0] = name_length
& 0xff;
6824 memcpy( name
+ root
->qt_compatible
, handler_name
, strlen( handler_name
) );
6825 if( root
->isom_compatible
)
6826 name
[name_length
- 1] = 0;
6827 hdlr
->componentName
= name
;
6828 hdlr
->componentName_length
= name_length
;
6832 uint32_t lsmash_get_media_timescale( lsmash_root_t
*root
, uint32_t track_ID
)
6834 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6835 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->mdhd
)
6837 return trak
->mdia
->mdhd
->timescale
;
6840 uint64_t lsmash_get_media_duration( lsmash_root_t
*root
, uint32_t track_ID
)
6842 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6843 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->mdhd
)
6845 return trak
->mdia
->mdhd
->duration
;
6848 uint64_t lsmash_get_track_duration( lsmash_root_t
*root
, uint32_t track_ID
)
6850 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6851 if( !trak
|| !trak
->tkhd
)
6853 return trak
->tkhd
->duration
;
6856 uint32_t lsmash_get_last_sample_delta( lsmash_root_t
*root
, uint32_t track_ID
)
6858 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6859 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
6860 || !trak
->mdia
->minf
->stbl
->stts
|| !trak
->mdia
->minf
->stbl
->stts
->list
6861 || !trak
->mdia
->minf
->stbl
->stts
->list
->head
|| !trak
->mdia
->minf
->stbl
->stts
->list
->head
->data
)
6863 return ((isom_stts_entry_t
*)trak
->mdia
->minf
->stbl
->stts
->list
->head
->data
)->sample_delta
;
6866 uint32_t lsmash_get_start_time_offset( lsmash_root_t
*root
, uint32_t track_ID
)
6868 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6869 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
6870 || !trak
->mdia
->minf
->stbl
->ctts
|| !trak
->mdia
->minf
->stbl
->ctts
->list
6871 || !trak
->mdia
->minf
->stbl
->ctts
->list
->head
|| !trak
->mdia
->minf
->stbl
->ctts
->list
->head
->data
)
6873 return ((isom_ctts_entry_t
*)trak
->mdia
->minf
->stbl
->ctts
->list
->head
->data
)->sample_offset
;
6876 uint16_t lsmash_pack_iso_language( char *iso_language
)
6878 if( !iso_language
|| strlen( iso_language
) != 3 )
6880 return (uint16_t)LSMASH_PACK_ISO_LANGUAGE( iso_language
[0], iso_language
[1], iso_language
[2] );
6883 static int isom_iso2mac_language( uint16_t ISO_language
, uint16_t *MAC_language
)
6888 for( ; isom_languages
[i
].iso_name
; i
++ )
6889 if( ISO_language
== isom_languages
[i
].iso_name
)
6891 if( !isom_languages
[i
].iso_name
)
6893 *MAC_language
= isom_languages
[i
].mac_value
;
6897 static int isom_mac2iso_language( uint16_t MAC_language
, uint16_t *ISO_language
)
6902 for( ; isom_languages
[i
].iso_name
; i
++ )
6903 if( MAC_language
== isom_languages
[i
].mac_value
)
6905 *ISO_language
= isom_languages
[i
].iso_name
? isom_languages
[i
].iso_name
: ISOM_LANGUAGE_CODE_UNDEFINED
;
6909 static int isom_set_media_language( lsmash_root_t
*root
, uint32_t track_ID
, uint16_t ISO_language
, uint16_t MAC_language
)
6911 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6912 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->mdhd
)
6914 uint16_t language
= 0;
6915 if( root
->isom_compatible
)
6918 language
= ISO_language
;
6919 else if( MAC_language
)
6921 if( isom_mac2iso_language( MAC_language
, &language
) )
6925 language
= ISOM_LANGUAGE_CODE_UNDEFINED
;
6927 else if( root
->qt_compatible
)
6931 if( isom_iso2mac_language( ISO_language
, &language
) )
6935 language
= MAC_language
;
6939 trak
->mdia
->mdhd
->language
= language
;
6943 static int isom_create_grouping( isom_trak_entry_t
*trak
, isom_grouping_type grouping_type
)
6945 lsmash_root_t
*root
= trak
->root
;
6946 switch( grouping_type
)
6948 case ISOM_GROUP_TYPE_RAP
:
6949 assert( root
->max_isom_version
>= 6 );
6951 case ISOM_GROUP_TYPE_ROLL
:
6952 assert( root
->avc_extensions
);
6958 if( !isom_add_sgpd( trak
->mdia
->minf
->stbl
, grouping_type
)
6959 || !isom_add_sbgp( trak
->mdia
->minf
->stbl
, grouping_type
) )
6964 void lsmash_initialize_media_parameters( lsmash_media_parameters_t
*param
)
6966 memset( param
, 0, sizeof(lsmash_media_parameters_t
) );
6967 param
->timescale
= 1;
6970 int lsmash_set_media_parameters( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_media_parameters_t
*param
)
6972 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6973 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->mdhd
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
)
6975 trak
->mdia
->mdhd
->timescale
= param
->timescale
;
6976 if( isom_set_media_language( root
, track_ID
, param
->ISO_language
, param
->MAC_language
) )
6978 if( param
->media_handler_name
6979 && isom_set_media_handler_name( root
, track_ID
, param
->media_handler_name
) )
6981 if( root
->qt_compatible
&& param
->data_handler_name
6982 && isom_set_data_handler_name( root
, track_ID
, param
->data_handler_name
) )
6984 if( root
->avc_extensions
&& param
->roll_grouping
6985 && isom_create_grouping( trak
, ISOM_GROUP_TYPE_ROLL
) )
6987 if( (root
->max_isom_version
>= 6) && param
->rap_grouping
6988 && isom_create_grouping( trak
, ISOM_GROUP_TYPE_RAP
) )
6993 int lsmash_get_media_parameters( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_media_parameters_t
*param
)
6995 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6996 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->mdhd
|| !trak
->mdia
->hdlr
6997 || !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
)
6999 isom_mdhd_t
*mdhd
= trak
->mdia
->mdhd
;
7000 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
7001 isom_sbgp_entry_t
*sbgp
;
7002 isom_sgpd_entry_t
*sgpd
;
7003 param
->timescale
= mdhd
->timescale
;
7004 param
->handler_type
= trak
->mdia
->hdlr
->componentSubtype
;
7005 param
->duration
= mdhd
->duration
;
7006 /* Whether sample grouping present. */
7007 sbgp
= isom_get_sample_to_group( stbl
, ISOM_GROUP_TYPE_ROLL
);
7008 sgpd
= isom_get_sample_group_description( stbl
, ISOM_GROUP_TYPE_ROLL
);
7009 param
->roll_grouping
= sbgp
&& sgpd
;
7010 sbgp
= isom_get_sample_to_group( stbl
, ISOM_GROUP_TYPE_RAP
);
7011 sgpd
= isom_get_sample_group_description( stbl
, ISOM_GROUP_TYPE_RAP
);
7012 param
->rap_grouping
= sbgp
&& sgpd
;
7013 /* Get media language. */
7014 if( mdhd
->language
>= 0x800 )
7016 param
->MAC_language
= 0;
7017 param
->ISO_language
= mdhd
->language
;
7021 param
->MAC_language
= mdhd
->language
;
7022 param
->ISO_language
= 0;
7024 /* Get handler name(s). */
7025 isom_hdlr_t
*hdlr
= trak
->mdia
->hdlr
;
7026 int length
= LSMASH_MIN( 255, hdlr
->componentName_length
);
7029 memcpy( param
->media_handler_name_shadow
, hdlr
->componentName
+ root
->qt_compatible
, length
);
7030 param
->media_handler_name_shadow
[length
- 2 + root
->isom_compatible
+ root
->qt_compatible
] = '\0';
7031 param
->media_handler_name
= param
->media_handler_name_shadow
;
7035 param
->media_handler_name
= NULL
;
7036 memset( param
->media_handler_name_shadow
, 0, sizeof(param
->media_handler_name_shadow
) );
7038 if( trak
->mdia
->minf
->hdlr
)
7040 hdlr
= trak
->mdia
->minf
->hdlr
;
7041 length
= LSMASH_MIN( 255, hdlr
->componentName_length
);
7044 memcpy( param
->data_handler_name_shadow
, hdlr
->componentName
+ root
->qt_compatible
, length
);
7045 param
->data_handler_name_shadow
[length
- 2 + root
->isom_compatible
+ root
->qt_compatible
] = '\0';
7046 param
->data_handler_name
= param
->data_handler_name_shadow
;
7050 param
->data_handler_name
= NULL
;
7051 memset( param
->data_handler_name_shadow
, 0, sizeof(param
->data_handler_name_shadow
) );
7056 param
->data_handler_name
= NULL
;
7057 memset( param
->data_handler_name_shadow
, 0, sizeof(param
->data_handler_name_shadow
) );
7062 /*---- movie manipulators ----*/
7064 lsmash_root_t
*lsmash_open_movie( const char *filename
, lsmash_file_mode mode
)
7066 char open_mode
[4] = { 0 };
7067 if( mode
& LSMASH_FILE_MODE_WRITE
)
7068 memcpy( open_mode
, "w+b", 4 );
7069 #ifdef LSMASH_DEMUXER_ENABLED
7070 else if( mode
& LSMASH_FILE_MODE_READ
)
7071 memcpy( open_mode
, "rb", 3 );
7075 lsmash_root_t
*root
= malloc( sizeof(lsmash_root_t
) );
7078 memset( root
, 0, sizeof(lsmash_root_t
) );
7080 root
->bs
= malloc( sizeof(lsmash_bs_t
) );
7083 memset( root
->bs
, 0, sizeof(lsmash_bs_t
) );
7084 if( !strcmp( filename
, "-" ) )
7086 if( mode
& LSMASH_FILE_MODE_READ
)
7087 root
->bs
->stream
= stdin
;
7088 else if( (mode
& LSMASH_FILE_MODE_WRITE
) && (mode
& LSMASH_FILE_MODE_FRAGMENTED
) )
7089 root
->bs
->stream
= stdout
;
7092 root
->bs
->stream
= fopen( filename
, open_mode
);
7093 if( !root
->bs
->stream
)
7096 if( mode
& LSMASH_FILE_MODE_WRITE
)
7098 if( isom_add_moov( root
) || isom_add_mvhd( root
->moov
) )
7100 root
->qt_compatible
= 1; /* QTFF is default file format. */
7102 #ifdef LSMASH_DEMUXER_ENABLED
7103 if( (mode
& (LSMASH_FILE_MODE_READ
| LSMASH_FILE_MODE_DUMP
)) )
7105 if( isom_read_root( root
) )
7107 root
->max_read_size
= 4 * 1024 * 1024;
7110 if( mode
& LSMASH_FILE_MODE_FRAGMENTED
)
7112 root
->fragment
= malloc( sizeof(isom_fragment_manager_t
) );
7113 if( !root
->fragment
)
7115 memset( root
->fragment
, 0, sizeof(isom_fragment_manager_t
) );
7116 root
->fragment
->pool
= lsmash_create_entry_list();
7117 if( !root
->fragment
->pool
)
7122 lsmash_destroy_root( root
);
7126 static int isom_finish_fragment_movie( lsmash_root_t
*root
);
7128 /* A movie fragment cannot switch a sample description to another.
7129 * So you must call this function before switching sample descriptions. */
7130 int lsmash_create_fragment_movie( lsmash_root_t
*root
)
7132 if( !root
|| !root
->bs
|| !root
->fragment
|| !root
->moov
|| !root
->moov
->trak_list
)
7134 /* Finish the previous movie fragment before starting a new one. */
7135 if( isom_finish_fragment_movie( root
) )
7137 /* We always hold only one movie fragment except for the initial movie (a pair of moov and mdat). */
7138 if( root
->fragment
->movie
&& root
->moof_list
->entry_count
!= 1 )
7140 isom_moof_entry_t
*moof
= isom_add_moof( root
);
7141 if( isom_add_mfhd( moof
) )
7143 root
->fragment
->movie
= moof
;
7144 moof
->mfhd
->sequence_number
= ++ root
->fragment
->fragment_count
;
7145 if( root
->moof_list
->entry_count
== 1 )
7147 /* Remove the previous movie fragment. */
7148 return lsmash_remove_entry( root
->moof_list
, 1, isom_remove_moof
);
7151 static int isom_set_brands( lsmash_root_t
*root
, lsmash_brand_type major_brand
, uint32_t minor_version
, lsmash_brand_type
*brands
, uint32_t brand_count
)
7153 if( brand_count
> 50 )
7154 return -1; /* We support setting brands up to 50. */
7157 /* Absence of File Type Box means this file is a QuickTime or MP4 version 1 format file. */
7160 if( root
->ftyp
->compatible_brands
)
7161 free( root
->ftyp
->compatible_brands
);
7167 if( !root
->ftyp
&& isom_add_ftyp( root
) )
7169 isom_ftyp_t
*ftyp
= root
->ftyp
;
7170 ftyp
->major_brand
= major_brand
;
7171 ftyp
->minor_version
= minor_version
;
7172 lsmash_brand_type
*compatible_brands
;
7173 if( !ftyp
->compatible_brands
)
7174 compatible_brands
= malloc( brand_count
* sizeof(uint32_t) );
7176 compatible_brands
= realloc( ftyp
->compatible_brands
, brand_count
* sizeof(uint32_t) );
7177 if( !compatible_brands
)
7179 ftyp
->compatible_brands
= compatible_brands
;
7180 for( uint32_t i
= 0; i
< brand_count
; i
++ )
7182 ftyp
->compatible_brands
[i
] = brands
[i
];
7185 ftyp
->brand_count
= brand_count
;
7186 return isom_check_compatibility( root
);
7189 void lsmash_initialize_movie_parameters( lsmash_movie_parameters_t
*param
)
7191 memset( param
, 0, sizeof(lsmash_movie_parameters_t
) );
7192 param
->max_chunk_duration
= 0.5;
7193 param
->max_async_tolerance
= 2.0;
7194 param
->max_chunk_size
= 4 * 1024 * 1024;
7195 param
->max_read_size
= 4 * 1024 * 1024;
7196 param
->timescale
= 600;
7197 param
->playback_rate
= 0x00010000;
7198 param
->playback_volume
= 0x0100;
7201 int lsmash_set_movie_parameters( lsmash_root_t
*root
, lsmash_movie_parameters_t
*param
)
7203 if( !root
|| !root
->moov
|| !root
->moov
->mvhd
7204 || isom_set_brands( root
, param
->major_brand
, param
->minor_version
, param
->brands
, param
->number_of_brands
) )
7206 isom_mvhd_t
*mvhd
= root
->moov
->mvhd
;
7207 root
->max_chunk_duration
= param
->max_chunk_duration
;
7208 root
->max_async_tolerance
= LSMASH_MAX( param
->max_async_tolerance
, 2 * param
->max_chunk_duration
);
7209 root
->max_chunk_size
= param
->max_chunk_size
;
7210 root
->max_read_size
= param
->max_read_size
;
7211 mvhd
->timescale
= param
->timescale
;
7212 if( root
->qt_compatible
|| root
->itunes_audio
)
7214 mvhd
->rate
= param
->playback_rate
;
7215 mvhd
->volume
= param
->playback_volume
;
7216 mvhd
->previewTime
= param
->preview_time
;
7217 mvhd
->previewDuration
= param
->preview_duration
;
7218 mvhd
->posterTime
= param
->poster_time
;
7222 mvhd
->rate
= 0x00010000;
7223 mvhd
->volume
= 0x0100;
7224 mvhd
->previewTime
= 0;
7225 mvhd
->previewDuration
= 0;
7226 mvhd
->posterTime
= 0;
7231 int lsmash_get_movie_parameters( lsmash_root_t
*root
, lsmash_movie_parameters_t
*param
)
7233 if( !root
|| !root
->moov
|| !root
->moov
->mvhd
)
7235 isom_mvhd_t
*mvhd
= root
->moov
->mvhd
;
7238 isom_ftyp_t
*ftyp
= root
->ftyp
;
7239 uint32_t brand_count
= LSMASH_MIN( ftyp
->brand_count
, 50 ); /* brands up to 50 */
7240 for( uint32_t i
= 0; i
< brand_count
; i
++ )
7241 param
->brands_shadow
[i
] = ftyp
->compatible_brands
[i
];
7242 param
->major_brand
= ftyp
->major_brand
;
7243 param
->brands
= param
->brands_shadow
;
7244 param
->number_of_brands
= brand_count
;
7245 param
->minor_version
= ftyp
->minor_version
;
7247 param
->max_chunk_duration
= root
->max_chunk_duration
;
7248 param
->max_async_tolerance
= root
->max_async_tolerance
;
7249 param
->max_chunk_size
= root
->max_chunk_size
;
7250 param
->max_read_size
= root
->max_read_size
;
7251 param
->timescale
= mvhd
->timescale
;
7252 param
->duration
= mvhd
->duration
;
7253 param
->playback_rate
= mvhd
->rate
;
7254 param
->playback_volume
= mvhd
->volume
;
7255 param
->preview_time
= mvhd
->previewTime
;
7256 param
->preview_duration
= mvhd
->previewDuration
;
7257 param
->poster_time
= mvhd
->posterTime
;
7258 param
->number_of_tracks
= root
->moov
->trak_list
? root
->moov
->trak_list
->entry_count
: 0;
7262 uint32_t lsmash_get_movie_timescale( lsmash_root_t
*root
)
7264 if( !root
|| !root
->moov
|| !root
->moov
->mvhd
)
7266 return root
->moov
->mvhd
->timescale
;
7269 static int isom_write_ftyp( lsmash_root_t
*root
)
7271 isom_ftyp_t
*ftyp
= root
->ftyp
;
7272 if( !ftyp
|| !ftyp
->brand_count
)
7274 lsmash_bs_t
*bs
= root
->bs
;
7275 isom_bs_put_box_common( bs
, ftyp
);
7276 lsmash_bs_put_be32( bs
, ftyp
->major_brand
);
7277 lsmash_bs_put_be32( bs
, ftyp
->minor_version
);
7278 for( uint32_t i
= 0; i
< ftyp
->brand_count
; i
++ )
7279 lsmash_bs_put_be32( bs
, ftyp
->compatible_brands
[i
] );
7280 if( lsmash_bs_write_data( bs
) )
7282 root
->size
+= ftyp
->size
;
7283 root
->file_type_written
= 1;
7287 static int isom_write_moov( lsmash_root_t
*root
)
7289 if( !root
|| !root
->moov
)
7291 lsmash_bs_t
*bs
= root
->bs
;
7292 isom_moov_t
*moov
= root
->moov
;
7293 isom_bs_put_box_common( bs
, moov
);
7294 if( lsmash_bs_write_data( bs
) )
7296 if( isom_write_mvhd( root
)
7297 || isom_write_iods( root
) )
7299 if( moov
->trak_list
)
7300 for( lsmash_entry_t
*entry
= moov
->trak_list
->head
; entry
; entry
= entry
->next
)
7301 if( isom_write_trak( bs
, (isom_trak_entry_t
*)entry
->data
) )
7303 if( isom_write_udta( bs
, moov
, NULL
)
7304 || isom_write_meta( bs
, moov
->meta
) )
7306 return isom_write_mvex( bs
, moov
->mvex
);
7309 int lsmash_set_free( lsmash_root_t
*root
, uint8_t *data
, uint64_t data_length
)
7311 if( !root
|| !root
->free
|| !data
|| !data_length
)
7313 isom_free_t
*skip
= root
->free
;
7314 uint8_t *tmp
= NULL
;
7316 tmp
= malloc( data_length
);
7317 else if( skip
->length
< data_length
)
7318 tmp
= realloc( skip
->data
, data_length
);
7321 memcpy( tmp
, data
, data_length
);
7323 skip
->length
= data_length
;
7327 int lsmash_add_free( lsmash_root_t
*root
, uint8_t *data
, uint64_t data_length
)
7333 isom_create_box( skip
, root
, ISOM_BOX_TYPE_FREE
);
7336 if( data
&& data_length
)
7337 return lsmash_set_free( root
, data
, data_length
);
7341 int lsmash_write_free( lsmash_root_t
*root
)
7343 if( !root
|| !root
->bs
|| !root
->free
)
7345 isom_free_t
*skip
= root
->free
;
7346 lsmash_bs_t
*bs
= root
->bs
;
7347 skip
->size
= 8 + skip
->length
;
7348 isom_bs_put_box_common( bs
, skip
);
7349 if( skip
->data
&& skip
->length
)
7350 lsmash_bs_put_bytes( bs
, skip
->data
, skip
->length
);
7351 return lsmash_bs_write_data( bs
);
7354 int lsmash_create_object_descriptor( lsmash_root_t
*root
)
7358 /* Return error if this file is not compatible with MP4 file format. */
7359 if( !root
->mp4_version1
&& !root
->mp4_version2
)
7361 return isom_add_iods( root
->moov
);
7364 /*---- finishing functions ----*/
7366 static int isom_set_fragment_overall_duration( lsmash_root_t
*root
)
7368 if( root
->bs
->stream
== stdout
)
7370 isom_mvex_t
*mvex
= root
->moov
->mvex
;
7371 if( isom_add_mehd( mvex
) )
7373 /* Get the longest duration of the tracks. */
7374 uint64_t longest_duration
= 0;
7375 for( lsmash_entry_t
*entry
= root
->moov
->trak_list
->head
; entry
; entry
= entry
->next
)
7377 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)entry
->data
;
7378 if( !trak
|| !trak
->cache
|| !trak
->cache
->fragment
|| !trak
->mdia
|| !trak
->mdia
->mdhd
|| !trak
->mdia
->mdhd
->timescale
)
7381 if( !trak
->edts
|| !trak
->edts
->elst
|| !trak
->edts
->elst
->list
)
7383 duration
= trak
->cache
->fragment
->largest_cts
+ trak
->cache
->fragment
->last_duration
;
7384 duration
= (uint64_t)(((double)duration
/ trak
->mdia
->mdhd
->timescale
) * root
->moov
->mvhd
->timescale
);
7389 for( lsmash_entry_t
*elst_entry
= trak
->edts
->elst
->list
->head
; elst_entry
; elst_entry
= elst_entry
->next
)
7391 isom_elst_entry_t
*data
= (isom_elst_entry_t
*)elst_entry
->data
;
7394 duration
+= data
->segment_duration
;
7397 longest_duration
= LSMASH_MAX( duration
, longest_duration
);
7399 mvex
->mehd
->fragment_duration
= longest_duration
;
7400 mvex
->mehd
->version
= 1;
7401 isom_update_mehd_size( mvex
->mehd
);
7402 /* Write Movie Extends Header Box here. */
7403 lsmash_bs_t
*bs
= root
->bs
;
7404 FILE *stream
= bs
->stream
;
7405 uint64_t current_pos
= lsmash_ftell( stream
);
7406 lsmash_fseek( stream
, mvex
->placeholder_pos
, SEEK_SET
);
7407 int ret
= isom_write_mehd( bs
, mvex
->mehd
);
7409 ret
= lsmash_bs_write_data( bs
);
7410 lsmash_fseek( stream
, current_pos
, SEEK_SET
);
7414 static int isom_write_fragment_random_access_info( lsmash_root_t
*root
)
7416 if( root
->bs
->stream
== stdout
)
7418 if( isom_update_mfra_size( root
->mfra
) )
7420 return isom_write_mfra( root
->bs
, root
->mfra
);
7423 int lsmash_finish_movie( lsmash_root_t
*root
, lsmash_adhoc_remux_t
* remux
)
7425 if( !root
|| !root
->bs
|| !root
->moov
|| !root
->moov
->trak_list
)
7427 if( root
->fragment
)
7429 /* Output the final movie fragment. */
7430 if( isom_finish_fragment_movie( root
) )
7432 /* Write the overall random access information at the tail of the movie. */
7433 if( isom_write_fragment_random_access_info( root
) )
7435 /* Set overall duration of the movie. */
7436 return isom_set_fragment_overall_duration( root
);
7438 isom_moov_t
*moov
= root
->moov
;
7439 for( lsmash_entry_t
*entry
= moov
->trak_list
->head
; entry
; entry
= entry
->next
)
7441 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)entry
->data
;
7442 if( !trak
|| !trak
->cache
|| !trak
->tkhd
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
)
7444 uint32_t track_ID
= trak
->tkhd
->track_ID
;
7445 uint32_t related_track_ID
= trak
->related_track_ID
;
7446 /* Disable the track if the track is a track reference chapter. */
7447 if( trak
->is_chapter
)
7448 trak
->tkhd
->flags
&= ~ISOM_TRACK_ENABLED
;
7449 if( trak
->is_chapter
&& related_track_ID
)
7451 /* In order that the track duration of the chapter track doesn't exceed that of the related track. */
7452 uint64_t track_duration
= LSMASH_MIN( trak
->tkhd
->duration
, lsmash_get_track_duration( root
, related_track_ID
) );
7453 if( lsmash_create_explicit_timeline_map( root
, track_ID
, track_duration
, 0, ISOM_EDIT_MODE_NORMAL
) )
7456 /* Add stss box if any samples aren't sync sample. */
7457 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
7458 if( !trak
->cache
->all_sync
&& !stbl
->stss
&& isom_add_stss( stbl
) )
7460 if( isom_update_bitrate_info( trak
->mdia
) )
7463 if( root
->mp4_version1
== 1 && isom_add_iods( moov
) )
7465 if( isom_check_mandatory_boxes( root
)
7466 || isom_set_movie_creation_time( root
)
7467 || isom_update_moov_size( moov
)
7468 || isom_write_mdat_size( root
) )
7471 lsmash_bs_t
*bs
= root
->bs
;
7472 uint64_t meta_size
= root
->meta
? root
->meta
->size
: 0;
7475 if( isom_write_moov( root
)
7476 || isom_write_meta( bs
, root
->meta
) )
7478 root
->size
+= moov
->size
+ meta_size
;
7482 /* stco->co64 conversion, depending on last chunk's offset */
7483 for( lsmash_entry_t
* entry
= moov
->trak_list
->head
; entry
; )
7485 isom_trak_entry_t
* trak
= (isom_trak_entry_t
*)entry
->data
;
7486 isom_stco_t
* stco
= trak
->mdia
->minf
->stbl
->stco
;
7487 if( !stco
->list
->tail
)
7489 if( stco
->large_presentation
7490 || (((isom_stco_entry_t
*)stco
->list
->tail
->data
)->chunk_offset
+ moov
->size
+ meta_size
) <= UINT32_MAX
)
7492 entry
= entry
->next
;
7493 continue; /* no need to convert stco into co64 */
7495 /* stco->co64 conversion */
7496 if( isom_convert_stco_to_co64( trak
->mdia
->minf
->stbl
)
7497 || isom_update_moov_size( moov
) )
7499 entry
= moov
->trak_list
->head
; /* whenever any conversion, re-check all traks */
7502 /* now the amount of offset is fixed. */
7503 uint64_t mtf_size
= moov
->size
+ meta_size
; /* sum of size of boxes moved to front */
7505 /* buffer size must be at least mtf_size * 2 */
7506 remux
->buffer_size
= LSMASH_MAX( remux
->buffer_size
, mtf_size
* 2 );
7509 if( (buf
[0] = (uint8_t*)malloc( remux
->buffer_size
)) == NULL
)
7510 return -1; /* NOTE: i think we still can fallback to "return isom_write_moov( root );" here. */
7511 uint64_t size
= remux
->buffer_size
/ 2;
7512 buf
[1] = buf
[0] + size
; /* split to 2 buffers */
7514 /* now the amount of offset is fixed. apply that to stco/co64 */
7515 for( lsmash_entry_t
* entry
= moov
->trak_list
->head
; entry
; entry
= entry
->next
)
7517 isom_stco_t
* stco
= ((isom_trak_entry_t
*)entry
->data
)->mdia
->minf
->stbl
->stco
;
7518 if( stco
->large_presentation
)
7519 for( lsmash_entry_t
* co64_entry
= stco
->list
->head
; co64_entry
; co64_entry
= co64_entry
->next
)
7520 ((isom_co64_entry_t
*)co64_entry
->data
)->chunk_offset
+= mtf_size
;
7522 for( lsmash_entry_t
* stco_entry
= stco
->list
->head
; stco_entry
; stco_entry
= stco_entry
->next
)
7523 ((isom_stco_entry_t
*)stco_entry
->data
)->chunk_offset
+= mtf_size
;
7526 FILE *stream
= bs
->stream
;
7527 isom_mdat_t
*mdat
= root
->mdat
;
7528 uint64_t total
= root
->size
+ mtf_size
;
7530 /* backup starting area of mdat and write moov + meta there instead */
7531 if( lsmash_fseek( stream
, mdat
->placeholder_pos
, SEEK_SET
) )
7533 readnum
= fread( buf
[0], 1, size
, stream
);
7534 uint64_t read_pos
= lsmash_ftell( stream
);
7536 /* write moov + meta there instead */
7537 if( lsmash_fseek( stream
, mdat
->placeholder_pos
, SEEK_SET
)
7538 || isom_write_moov( root
)
7539 || isom_write_meta( bs
, root
->meta
) )
7541 uint64_t write_pos
= lsmash_ftell( stream
);
7543 mdat
->placeholder_pos
+= mtf_size
; /* update placeholder */
7547 while( readnum
== size
)
7549 if( lsmash_fseek( stream
, read_pos
, SEEK_SET
) )
7551 readnum
= fread( buf
[buf_switch
], 1, size
, stream
);
7552 read_pos
= lsmash_ftell( stream
);
7556 if( lsmash_fseek( stream
, write_pos
, SEEK_SET
)
7557 || fwrite( buf
[buf_switch
], 1, size
, stream
) != size
)
7559 write_pos
= lsmash_ftell( stream
);
7560 if( remux
->func
) remux
->func( remux
->param
, write_pos
, total
); // FIXME:
7562 if( fwrite( buf
[buf_switch
^0x1], 1, readnum
, stream
) != readnum
)
7564 if( remux
->func
) remux
->func( remux
->param
, total
, total
); // FIXME:
7566 root
->size
+= mtf_size
;
7575 #define GET_MOST_USED( box_name, index, flag_name ) \
7576 if( most_used[index] < stats.flag_name[i] ) \
7578 most_used[index] = stats.flag_name[i]; \
7579 box_name->default_sample_flags.flag_name = i; \
7582 static int isom_create_fragment_overall_default_settings( lsmash_root_t
*root
)
7584 if( isom_add_mvex( root
->moov
) )
7586 for( lsmash_entry_t
*trak_entry
= root
->moov
->trak_list
->head
; trak_entry
; trak_entry
= trak_entry
->next
)
7588 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)trak_entry
->data
;
7589 if( !trak
|| !trak
->cache
|| !trak
->tkhd
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
)
7591 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
7592 if( !stbl
->stts
|| !stbl
->stts
->list
|| !stbl
->stsz
7593 || (stbl
->stts
->list
->tail
&& !stbl
->stts
->list
->tail
->data
)
7594 || (stbl
->stsz
->list
&& stbl
->stsz
->list
->head
&& !stbl
->stsz
->list
->head
->data
) )
7596 isom_trex_entry_t
*trex
= isom_add_trex( root
->moov
->mvex
);
7599 trex
->track_ID
= trak
->tkhd
->track_ID
;
7600 /* Set up defaults. */
7601 trex
->default_sample_description_index
= trak
->cache
->chunk
.sample_description_index
? trak
->cache
->chunk
.sample_description_index
: 1;
7602 trex
->default_sample_duration
= stbl
->stts
->list
->tail
? ((isom_stts_entry_t
*)stbl
->stts
->list
->tail
->data
)->sample_delta
: 1;
7603 trex
->default_sample_size
= !stbl
->stsz
->list
7604 ? stbl
->stsz
->sample_size
: stbl
->stsz
->list
->head
7605 ? ((isom_stsz_entry_t
*)stbl
->stsz
->list
->head
->data
)->entry_size
: 0;
7606 if( stbl
->sdtp
&& stbl
->sdtp
->list
)
7608 struct sample_flags_stats_t
7610 uint32_t is_leading
[4];
7611 uint32_t sample_depends_on
[4];
7612 uint32_t sample_is_depended_on
[4];
7613 uint32_t sample_has_redundancy
[4];
7614 } stats
= { { 0 }, { 0 }, { 0 }, { 0 } };
7615 for( lsmash_entry_t
*sdtp_entry
= stbl
->sdtp
->list
->head
; sdtp_entry
; sdtp_entry
= sdtp_entry
->next
)
7617 isom_sdtp_entry_t
*data
= (isom_sdtp_entry_t
*)sdtp_entry
->data
;
7620 ++ stats
.is_leading
[ data
->is_leading
];
7621 ++ stats
.sample_depends_on
[ data
->sample_depends_on
];
7622 ++ stats
.sample_is_depended_on
[ data
->sample_is_depended_on
];
7623 ++ stats
.sample_has_redundancy
[ data
->sample_has_redundancy
];
7625 uint32_t most_used
[4] = { 0, 0, 0, 0 };
7626 for( int i
= 0; i
< 4; i
++ )
7628 GET_MOST_USED( trex
, 0, is_leading
);
7629 GET_MOST_USED( trex
, 1, sample_depends_on
);
7630 GET_MOST_USED( trex
, 2, sample_is_depended_on
);
7631 GET_MOST_USED( trex
, 3, sample_has_redundancy
);
7634 trex
->default_sample_flags
.sample_is_non_sync_sample
= !trak
->cache
->all_sync
;
7639 static int isom_prepare_random_access_info( lsmash_root_t
*root
)
7641 if( root
->bs
->stream
== stdout
)
7643 if( isom_add_mfra( root
)
7644 || isom_add_mfro( root
->mfra
) )
7649 static int isom_output_fragment_media_data( lsmash_root_t
*root
)
7651 isom_fragment_manager_t
*fragment
= root
->fragment
;
7652 if( !fragment
->pool
->entry_count
)
7654 /* no need to write media data */
7655 lsmash_remove_entries( fragment
->pool
, lsmash_delete_sample
);
7656 fragment
->pool_size
= 0;
7659 /* If there is no available Media Data Box to write samples, add and write a new one. */
7660 if( isom_new_mdat( root
, fragment
->pool_size
) )
7662 /* Write samples in the current movie fragment. */
7663 for( lsmash_entry_t
* entry
= fragment
->pool
->head
; entry
; entry
= entry
->next
)
7665 isom_sample_pool_t
*pool
= (isom_sample_pool_t
*)entry
->data
;
7668 lsmash_bs_put_bytes( root
->bs
, pool
->data
, pool
->size
);
7670 if( lsmash_bs_write_data( root
->bs
) )
7672 root
->size
+= root
->mdat
->size
;
7673 lsmash_remove_entries( fragment
->pool
, isom_remove_sample_pool
);
7674 fragment
->pool_size
= 0;
7678 static int isom_finish_fragment_initial_movie( lsmash_root_t
*root
)
7680 if( !root
->moov
|| !root
->moov
->trak_list
)
7682 isom_moov_t
*moov
= root
->moov
;
7683 for( lsmash_entry_t
*entry
= moov
->trak_list
->head
; entry
; entry
= entry
->next
)
7685 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)entry
->data
;
7686 if( !trak
|| !trak
->cache
|| !trak
->tkhd
|| !trak
->mdia
|| !trak
->mdia
->mdhd
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
)
7688 if( isom_get_sample_count( trak
) )
7690 /* Add stss box if any samples aren't sync sample. */
7691 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
7692 if( !trak
->cache
->all_sync
&& !stbl
->stss
&& isom_add_stss( stbl
) )
7696 trak
->tkhd
->duration
= 0;
7697 if( isom_update_bitrate_info( trak
->mdia
) )
7700 if( root
->mp4_version1
== 1 && isom_add_iods( moov
) )
7702 if( isom_create_fragment_overall_default_settings( root
)
7703 || isom_prepare_random_access_info( root
)
7704 || isom_check_mandatory_boxes( root
)
7705 || isom_set_movie_creation_time( root
)
7706 || isom_update_moov_size( moov
) )
7708 /* stco->co64 conversion, depending on last chunk's offset */
7709 uint64_t meta_size
= root
->meta
? root
->meta
->size
: 0;
7710 for( lsmash_entry_t
* entry
= moov
->trak_list
->head
; entry
; )
7712 isom_trak_entry_t
* trak
= (isom_trak_entry_t
*)entry
->data
;
7713 isom_stco_t
* stco
= trak
->mdia
->minf
->stbl
->stco
;
7714 if( !stco
->list
->tail
/* no samples */
7715 || stco
->large_presentation
7716 || (((isom_stco_entry_t
*)stco
->list
->tail
->data
)->chunk_offset
+ moov
->size
+ meta_size
) <= UINT32_MAX
)
7718 entry
= entry
->next
;
7719 continue; /* no need to convert stco into co64 */
7721 /* stco->co64 conversion */
7722 if( isom_convert_stco_to_co64( trak
->mdia
->minf
->stbl
)
7723 || isom_update_moov_size( moov
) )
7725 entry
= moov
->trak_list
->head
; /* whenever any conversion, re-check all traks */
7727 /* Now, the amount of offset is fixed. Apply that to stco/co64. */
7728 uint64_t preceding_size
= moov
->size
+ meta_size
;
7729 for( lsmash_entry_t
* entry
= moov
->trak_list
->head
; entry
; entry
= entry
->next
)
7731 isom_stco_t
* stco
= ((isom_trak_entry_t
*)entry
->data
)->mdia
->minf
->stbl
->stco
;
7732 if( stco
->large_presentation
)
7733 for( lsmash_entry_t
* co64_entry
= stco
->list
->head
; co64_entry
; co64_entry
= co64_entry
->next
)
7734 ((isom_co64_entry_t
*)co64_entry
->data
)->chunk_offset
+= preceding_size
;
7736 for( lsmash_entry_t
* stco_entry
= stco
->list
->head
; stco_entry
; stco_entry
= stco_entry
->next
)
7737 ((isom_stco_entry_t
*)stco_entry
->data
)->chunk_offset
+= preceding_size
;
7739 /* Write File Type Box here if it was not written yet. */
7740 if( !root
->file_type_written
&& isom_write_ftyp( root
) )
7742 /* Write Movie Box. */
7743 if( isom_write_moov( root
)
7744 || isom_write_meta( root
->bs
, root
->meta
) )
7746 root
->size
+= preceding_size
;
7747 /* Output samples. */
7748 return isom_output_fragment_media_data( root
);
7751 static int isom_finish_fragment_movie( lsmash_root_t
*root
)
7753 if( !root
->moov
|| !root
->moov
->trak_list
|| !root
->fragment
|| !root
->fragment
->pool
)
7755 isom_moof_entry_t
*moof
= root
->fragment
->movie
;
7757 return isom_finish_fragment_initial_movie( root
);
7758 /* Calculate appropriate default_sample_flags of each Track Fragment Header Box.
7759 * And check whether that default_sample_flags is useful or not. */
7760 for( lsmash_entry_t
*entry
= moof
->traf_list
->head
; entry
; entry
= entry
->next
)
7762 isom_traf_entry_t
*traf
= (isom_traf_entry_t
*)entry
->data
;
7763 if( !traf
|| !traf
->tfhd
|| !traf
->root
|| !traf
->root
->moov
|| !traf
->root
->moov
->mvex
)
7765 isom_tfhd_t
*tfhd
= traf
->tfhd
;
7766 isom_trex_entry_t
*trex
= isom_get_trex( root
->moov
->mvex
, tfhd
->track_ID
);
7769 struct sample_flags_stats_t
7771 uint32_t is_leading
[4];
7772 uint32_t sample_depends_on
[4];
7773 uint32_t sample_is_depended_on
[4];
7774 uint32_t sample_has_redundancy
[4];
7775 uint32_t sample_is_non_sync_sample
[2];
7776 } stats
= { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } };
7777 for( lsmash_entry_t
*trun_entry
= traf
->trun_list
->head
; trun_entry
; trun_entry
= trun_entry
->next
)
7779 isom_trun_entry_t
*trun
= (isom_trun_entry_t
*)trun_entry
->data
;
7780 if( !trun
|| !trun
->sample_count
)
7782 isom_sample_flags_t
*sample_flags
;
7783 if( trun
->flags
& ISOM_TR_FLAGS_SAMPLE_FLAGS_PRESENT
)
7785 if( !trun
->optional
)
7787 for( lsmash_entry_t
*optional_entry
= trun
->optional
->head
; optional_entry
; optional_entry
= optional_entry
->next
)
7789 isom_trun_optional_row_t
*row
= (isom_trun_optional_row_t
*)optional_entry
->data
;
7792 sample_flags
= &row
->sample_flags
;
7793 ++ stats
.is_leading
[ sample_flags
->is_leading
];
7794 ++ stats
.sample_depends_on
[ sample_flags
->sample_depends_on
];
7795 ++ stats
.sample_is_depended_on
[ sample_flags
->sample_is_depended_on
];
7796 ++ stats
.sample_has_redundancy
[ sample_flags
->sample_has_redundancy
];
7797 ++ stats
.sample_is_non_sync_sample
[ sample_flags
->sample_is_non_sync_sample
];
7802 sample_flags
= &tfhd
->default_sample_flags
;
7803 stats
.is_leading
[ sample_flags
->is_leading
] += trun
->sample_count
;
7804 stats
.sample_depends_on
[ sample_flags
->sample_depends_on
] += trun
->sample_count
;
7805 stats
.sample_is_depended_on
[ sample_flags
->sample_is_depended_on
] += trun
->sample_count
;
7806 stats
.sample_has_redundancy
[ sample_flags
->sample_has_redundancy
] += trun
->sample_count
;
7807 stats
.sample_is_non_sync_sample
[ sample_flags
->sample_is_non_sync_sample
] += trun
->sample_count
;
7810 uint32_t most_used
[5] = { 0, 0, 0, 0, 0 };
7811 for( int i
= 0; i
< 4; i
++ )
7813 GET_MOST_USED( tfhd
, 0, is_leading
);
7814 GET_MOST_USED( tfhd
, 1, sample_depends_on
);
7815 GET_MOST_USED( tfhd
, 2, sample_is_depended_on
);
7816 GET_MOST_USED( tfhd
, 3, sample_has_redundancy
);
7818 GET_MOST_USED( tfhd
, 4, sample_is_non_sync_sample
);
7820 int useful_default_sample_duration
= 0;
7821 int useful_default_sample_size
= 0;
7822 for( lsmash_entry_t
*trun_entry
= traf
->trun_list
->head
; trun_entry
; trun_entry
= trun_entry
->next
)
7824 isom_trun_entry_t
*trun
= (isom_trun_entry_t
*)trun_entry
->data
;
7825 if( !(trun
->flags
& ISOM_TR_FLAGS_SAMPLE_DURATION_PRESENT
) )
7826 useful_default_sample_duration
= 1;
7827 if( !(trun
->flags
& ISOM_TR_FLAGS_SAMPLE_SIZE_PRESENT
) )
7828 useful_default_sample_size
= 1;
7829 int useful_first_sample_flags
= 1;
7830 int useful_default_sample_flags
= 1;
7831 if( trun
->sample_count
== 1 )
7833 /* It is enough to check only if first_sample_flags equals default_sample_flags or not.
7834 * If it is equal, just use default_sample_flags.
7835 * If not, just use first_sample_flags of this run. */
7836 if( !memcmp( &trun
->first_sample_flags
, &tfhd
->default_sample_flags
, sizeof(isom_sample_flags_t
) ) )
7837 useful_first_sample_flags
= 0;
7839 else if( trun
->optional
&& trun
->optional
->head
)
7841 lsmash_entry_t
*optional_entry
= trun
->optional
->head
->next
;
7842 isom_trun_optional_row_t
*row
= (isom_trun_optional_row_t
*)optional_entry
->data
;
7843 isom_sample_flags_t representative_sample_flags
= row
->sample_flags
;
7844 if( memcmp( &tfhd
->default_sample_flags
, &representative_sample_flags
, sizeof(isom_sample_flags_t
) ) )
7845 useful_default_sample_flags
= 0;
7846 if( !memcmp( &trun
->first_sample_flags
, &representative_sample_flags
, sizeof(isom_sample_flags_t
) ) )
7847 useful_first_sample_flags
= 0;
7848 if( useful_default_sample_flags
)
7849 for( optional_entry
= optional_entry
->next
; optional_entry
; optional_entry
= optional_entry
->next
)
7851 row
= (isom_trun_optional_row_t
*)optional_entry
->data
;
7852 if( memcmp( &representative_sample_flags
, &row
->sample_flags
, sizeof(isom_sample_flags_t
) ) )
7854 useful_default_sample_flags
= 0;
7859 if( useful_default_sample_flags
)
7861 tfhd
->flags
|= ISOM_TF_FLAGS_DEFAULT_SAMPLE_FLAGS_PRESENT
;
7862 trun
->flags
&= ~ISOM_TR_FLAGS_SAMPLE_FLAGS_PRESENT
;
7866 useful_first_sample_flags
= 0;
7867 trun
->flags
|= ISOM_TR_FLAGS_SAMPLE_FLAGS_PRESENT
;
7869 if( useful_first_sample_flags
)
7870 trun
->flags
|= ISOM_TR_FLAGS_FIRST_SAMPLE_FLAGS_PRESENT
;
7872 if( useful_default_sample_duration
&& tfhd
->default_sample_duration
!= trex
->default_sample_duration
)
7873 tfhd
->flags
|= ISOM_TF_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT
;
7875 tfhd
->default_sample_duration
= trex
->default_sample_duration
; /* This might be redundant, but is to be more natural. */
7876 if( useful_default_sample_size
&& tfhd
->default_sample_size
!= trex
->default_sample_size
)
7877 tfhd
->flags
|= ISOM_TF_FLAGS_DEFAULT_SAMPLE_SIZE_PRESENT
;
7879 tfhd
->default_sample_size
= trex
->default_sample_size
; /* This might be redundant, but is to be more natural. */
7880 if( !(tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_SAMPLE_FLAGS_PRESENT
) )
7881 tfhd
->default_sample_flags
= trex
->default_sample_flags
; /* This might be redundant, but is to be more natural. */
7882 else if( !memcmp( &tfhd
->default_sample_flags
, &trex
->default_sample_flags
, sizeof(isom_sample_flags_t
) ) )
7883 tfhd
->flags
&= ~ISOM_TF_FLAGS_DEFAULT_SAMPLE_FLAGS_PRESENT
;
7885 /* When using for live streaming, setting explicit base_data_offset is not preferable.
7886 * However, it's OK because we haven't supported this yet.
7887 * Implicit base_data_offsets that originate in the first byte of each Movie Fragment Box will be implemented
7888 * by the feature of ISO Base Media File Format version 5 or later.
7889 * Media Data Box starts immediately after Movie Fragment Box. */
7890 for( lsmash_entry_t
*entry
= moof
->traf_list
->head
; entry
; entry
= entry
->next
)
7892 isom_traf_entry_t
*traf
= (isom_traf_entry_t
*)entry
->data
;
7893 traf
->tfhd
->flags
|= ISOM_TF_FLAGS_BASE_DATA_OFFSET_PRESENT
;
7895 /* Consider the update of tf_flags here. */
7896 if( isom_update_moof_entry_size( moof
) )
7898 /* Now, we can calculate offsets in the current movie fragment, so do it. */
7899 for( lsmash_entry_t
*entry
= moof
->traf_list
->head
; entry
; entry
= entry
->next
)
7901 isom_traf_entry_t
*traf
= (isom_traf_entry_t
*)entry
->data
;
7902 traf
->tfhd
->base_data_offset
= root
->size
+ moof
->size
+ ISOM_BASEBOX_COMMON_SIZE
;
7904 if( isom_write_moof( root
->bs
, moof
) )
7906 root
->size
+= moof
->size
;
7907 /* Output samples. */
7908 return isom_output_fragment_media_data( root
);
7911 #undef GET_MOST_USED
7913 static isom_trun_optional_row_t
*isom_request_trun_optional_row( isom_trun_entry_t
*trun
, isom_tfhd_t
*tfhd
, uint32_t sample_number
)
7915 isom_trun_optional_row_t
*row
= NULL
;
7916 if( !trun
->optional
)
7918 trun
->optional
= lsmash_create_entry_list();
7919 if( !trun
->optional
)
7922 if( trun
->optional
->entry_count
< sample_number
)
7924 while( trun
->optional
->entry_count
< sample_number
)
7926 row
= malloc( sizeof(isom_trun_optional_row_t
) );
7929 /* Copy from default. */
7930 row
->sample_duration
= tfhd
->default_sample_duration
;
7931 row
->sample_size
= tfhd
->default_sample_size
;
7932 row
->sample_flags
= tfhd
->default_sample_flags
;
7933 row
->sample_composition_time_offset
= 0;
7934 if( lsmash_add_entry( trun
->optional
, row
) )
7943 for( lsmash_entry_t
*entry
= trun
->optional
->head
; entry
; entry
= entry
->next
)
7945 row
= (isom_trun_optional_row_t
*)entry
->data
;
7948 if( ++i
== sample_number
)
7954 int lsmash_create_fragment_empty_duration( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t duration
)
7956 if( !root
|| !root
->fragment
|| !root
->fragment
->movie
|| !root
->moov
)
7958 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
7959 if( !trak
|| !trak
->tkhd
)
7961 isom_trex_entry_t
*trex
= isom_get_trex( root
->moov
->mvex
, track_ID
);
7964 isom_moof_entry_t
*moof
= root
->fragment
->movie
;
7965 isom_traf_entry_t
*traf
= isom_get_traf( moof
, track_ID
);
7968 traf
= isom_add_traf( root
, moof
);
7969 if( isom_add_tfhd( traf
) )
7971 isom_tfhd_t
*tfhd
= traf
->tfhd
;
7972 tfhd
->flags
= ISOM_TF_FLAGS_DURATION_IS_EMPTY
; /* no samples for this track fragment yet */
7973 tfhd
->track_ID
= trak
->tkhd
->track_ID
;
7974 tfhd
->default_sample_duration
= duration
;
7975 if( duration
!= trex
->default_sample_duration
)
7976 tfhd
->flags
|= ISOM_TF_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT
;
7977 traf
->cache
= trak
->cache
;
7978 traf
->cache
->fragment
->traf_number
= moof
->traf_list
->entry_count
;
7979 traf
->cache
->fragment
->last_duration
+= duration
; /* The duration of the last sample includes this empty-duration. */
7983 static int isom_set_fragment_last_duration( isom_traf_entry_t
*traf
, uint32_t last_duration
)
7985 isom_tfhd_t
*tfhd
= traf
->tfhd
;
7986 if( !traf
->trun_list
|| !traf
->trun_list
->tail
|| !traf
->trun_list
->tail
->data
)
7988 /* There are no track runs in this track fragment, so it is a empty-duration. */
7989 isom_trex_entry_t
*trex
= isom_get_trex( traf
->root
->moov
->mvex
, tfhd
->track_ID
);
7992 tfhd
->flags
|= ISOM_TF_FLAGS_DURATION_IS_EMPTY
;
7993 if( last_duration
!= trex
->default_sample_duration
)
7994 tfhd
->flags
|= ISOM_TF_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT
;
7995 tfhd
->default_sample_duration
= last_duration
;
7996 traf
->cache
->fragment
->last_duration
= last_duration
;
7999 /* Update the last sample_duration if needed. */
8000 isom_trun_entry_t
*trun
= (isom_trun_entry_t
*)traf
->trun_list
->tail
->data
;
8001 if( trun
->sample_count
== 1 && traf
->trun_list
->entry_count
== 1 )
8003 isom_trex_entry_t
*trex
= isom_get_trex( traf
->root
->moov
->mvex
, tfhd
->track_ID
);
8006 if( last_duration
!= trex
->default_sample_duration
)
8007 tfhd
->flags
|= ISOM_TF_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT
;
8008 tfhd
->default_sample_duration
= last_duration
;
8010 else if( last_duration
!= tfhd
->default_sample_duration
)
8011 trun
->flags
|= ISOM_TR_FLAGS_SAMPLE_DURATION_PRESENT
;
8014 isom_trun_optional_row_t
*row
= isom_request_trun_optional_row( trun
, tfhd
, trun
->sample_count
);
8017 row
->sample_duration
= last_duration
;
8019 traf
->cache
->fragment
->last_duration
= last_duration
;
8023 int lsmash_set_last_sample_delta( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t sample_delta
)
8025 if( !root
|| !track_ID
)
8027 if( root
->fragment
&& root
->fragment
->movie
)
8029 isom_traf_entry_t
*traf
= isom_get_traf( root
->fragment
->movie
, track_ID
);
8030 if( !traf
|| !traf
->cache
|| !traf
->tfhd
|| !traf
->trun_list
)
8032 return isom_set_fragment_last_duration( traf
, sample_delta
);
8034 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
8035 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->mdhd
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
8036 || !trak
->mdia
->minf
->stbl
->stsz
|| !trak
->mdia
->minf
->stbl
->stts
|| !trak
->mdia
->minf
->stbl
->stts
->list
)
8038 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
8039 isom_stts_t
*stts
= stbl
->stts
;
8040 uint32_t sample_count
= isom_get_sample_count( trak
);
8041 if( !stts
->list
->tail
)
8044 return 0; /* no samples */
8045 if( sample_count
> 1 )
8046 return -1; /* irregular sample_count */
8047 if( isom_add_stts_entry( stbl
, sample_delta
) )
8049 return lsmash_update_track_duration( root
, track_ID
, 0 );
8052 for( lsmash_entry_t
*entry
= stts
->list
->head
; entry
; entry
= entry
->next
)
8053 i
+= ((isom_stts_entry_t
*)entry
->data
)->sample_count
;
8054 if( sample_count
< i
)
8056 isom_stts_entry_t
*last_stts_data
= (isom_stts_entry_t
*)stts
->list
->tail
->data
;
8057 if( !last_stts_data
)
8059 if( sample_count
> i
)
8061 if( sample_count
- i
> 1 )
8063 /* Add a sample_delta. */
8064 if( sample_delta
== last_stts_data
->sample_delta
)
8065 ++ last_stts_data
->sample_count
;
8066 else if( isom_add_stts_entry( stbl
, sample_delta
) )
8069 else if( sample_count
== i
&& isom_replace_last_sample_delta( stbl
, sample_delta
) )
8071 return lsmash_update_track_duration( root
, track_ID
, sample_delta
);
8074 void lsmash_discard_boxes( lsmash_root_t
*root
)
8078 isom_remove_ftyp( root
->ftyp
);
8079 isom_remove_moov( root
);
8080 lsmash_remove_list( root
->moof_list
, isom_remove_moof
);
8081 isom_remove_mdat( root
->mdat
);
8082 isom_remove_free( root
->free
);
8083 isom_remove_meta( root
->meta
);
8084 isom_remove_mfra( root
->mfra
);
8087 root
->moof_list
= NULL
;
8093 void lsmash_destroy_root( lsmash_root_t
*root
)
8097 #ifdef LSMASH_DEMUXER_ENABLED
8098 isom_remove_print_funcs( root
);
8099 isom_remove_timelines( root
);
8101 lsmash_discard_boxes( root
);
8104 if( root
->bs
->stream
)
8105 fclose( root
->bs
->stream
);
8106 if( root
->bs
->data
)
8107 free( root
->bs
->data
);
8110 if( root
->fragment
)
8112 lsmash_remove_list( root
->fragment
->pool
, lsmash_delete_sample
);
8113 free( root
->fragment
);
8118 /*---- timeline manipulator ----*/
8120 int lsmash_modify_explicit_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
)
8122 if( !segment_duration
|| media_time
< -1 )
8124 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
8125 if( !trak
|| !trak
->edts
|| !trak
->edts
->elst
|| !trak
->edts
->elst
->list
)
8127 isom_elst_t
*elst
= trak
->edts
->elst
;
8128 isom_elst_entry_t
*data
= (isom_elst_entry_t
*)lsmash_get_entry_data( elst
->list
, entry_number
);
8131 data
->segment_duration
= segment_duration
;
8132 data
->media_time
= media_time
;
8133 data
->media_rate
= media_rate
;
8134 if( !elst
->pos
|| !root
->fragment
|| root
->bs
->stream
== stdout
)
8135 return isom_update_tkhd_duration( trak
);
8136 /* Rewrite the specified entry.
8137 * Note: we don't update the version of the Edit List Box. */
8138 lsmash_bs_t
*bs
= root
->bs
;
8139 FILE *stream
= bs
->stream
;
8140 uint64_t current_pos
= lsmash_ftell( stream
);
8141 uint64_t entry_pos
= elst
->pos
+ ISOM_LIST_FULLBOX_COMMON_SIZE
+ ((uint64_t)entry_number
- 1) * (elst
->version
== 1 ? 20 : 12);
8142 lsmash_fseek( stream
, entry_pos
, SEEK_SET
);
8145 lsmash_bs_put_be64( bs
, data
->segment_duration
);
8146 lsmash_bs_put_be64( bs
, data
->media_time
);
8150 lsmash_bs_put_be32( bs
, (uint32_t)data
->segment_duration
);
8151 lsmash_bs_put_be32( bs
, (uint32_t)data
->media_time
);
8153 lsmash_bs_put_be32( bs
, data
->media_rate
);
8154 int ret
= lsmash_bs_write_data( bs
);
8155 lsmash_fseek( stream
, current_pos
, SEEK_SET
);
8159 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
)
8161 if( media_time
< -1 )
8163 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
8164 if( !trak
|| !trak
->tkhd
)
8166 segment_duration
= (segment_duration
|| root
->fragment
) ? segment_duration
8167 : trak
->tkhd
->duration
? trak
->tkhd
->duration
8168 : isom_update_tkhd_duration( trak
) ? 0
8169 : trak
->tkhd
->duration
;
8170 if( isom_add_edts( trak
)
8171 || isom_add_elst( trak
->edts
)
8172 || isom_add_elst_entry( trak
->edts
->elst
, segment_duration
, media_time
, media_rate
) )
8174 return isom_update_tkhd_duration( trak
);
8177 /*---- create / modification time fields manipulators ----*/
8179 int lsmash_update_media_modification_time( lsmash_root_t
*root
, uint32_t track_ID
)
8181 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
8182 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->mdhd
)
8184 isom_mdhd_t
*mdhd
= trak
->mdia
->mdhd
;
8185 mdhd
->modification_time
= isom_get_current_mp4time();
8186 /* overwrite strange creation_time */
8187 if( mdhd
->creation_time
> mdhd
->modification_time
)
8188 mdhd
->creation_time
= mdhd
->modification_time
;
8192 int lsmash_update_track_modification_time( lsmash_root_t
*root
, uint32_t track_ID
)
8194 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
8195 if( !trak
|| !trak
->tkhd
)
8197 isom_tkhd_t
*tkhd
= trak
->tkhd
;
8198 tkhd
->modification_time
= isom_get_current_mp4time();
8199 /* overwrite strange creation_time */
8200 if( tkhd
->creation_time
> tkhd
->modification_time
)
8201 tkhd
->creation_time
= tkhd
->modification_time
;
8205 int lsmash_update_movie_modification_time( lsmash_root_t
*root
)
8207 if( !root
|| !root
->moov
|| !root
->moov
->mvhd
)
8209 isom_mvhd_t
*mvhd
= root
->moov
->mvhd
;
8210 mvhd
->modification_time
= isom_get_current_mp4time();
8211 /* overwrite strange creation_time */
8212 if( mvhd
->creation_time
> mvhd
->modification_time
)
8213 mvhd
->creation_time
= mvhd
->modification_time
;
8217 /*---- sample manipulators ----*/
8218 lsmash_sample_t
*lsmash_create_sample( uint32_t size
)
8220 lsmash_sample_t
*sample
= malloc( sizeof(lsmash_sample_t
) );
8223 memset( sample
, 0, sizeof(lsmash_sample_t
) );
8226 sample
->data
= malloc( size
);
8232 sample
->length
= size
;
8236 int lsmash_sample_alloc( lsmash_sample_t
*sample
, uint32_t size
)
8243 free( sample
->data
);
8244 sample
->data
= NULL
;
8248 if( size
== sample
->length
)
8252 data
= malloc( size
);
8254 data
= realloc( sample
->data
, size
);
8257 sample
->data
= data
;
8258 sample
->length
= size
;
8262 void lsmash_delete_sample( lsmash_sample_t
*sample
)
8267 free( sample
->data
);
8271 isom_sample_pool_t
*isom_create_sample_pool( uint64_t size
)
8273 isom_sample_pool_t
*pool
= malloc( sizeof(isom_sample_pool_t
) );
8276 memset( pool
, 0, sizeof(isom_sample_pool_t
) );
8279 pool
->data
= malloc( size
);
8289 static void isom_remove_sample_pool( isom_sample_pool_t
*pool
)
8298 static uint32_t isom_add_size( isom_trak_entry_t
*trak
, uint32_t sample_size
)
8300 if( isom_add_stsz_entry( trak
->mdia
->minf
->stbl
, sample_size
) )
8302 return isom_get_sample_count( trak
);
8305 static uint32_t isom_add_dts( isom_stbl_t
*stbl
, isom_timestamp_t
*cache
, uint64_t dts
)
8307 isom_stts_t
*stts
= stbl
->stts
;
8308 if( !stts
->list
->entry_count
)
8310 if( isom_add_stts_entry( stbl
, dts
) )
8315 if( dts
<= cache
->dts
)
8317 uint32_t sample_delta
= dts
- cache
->dts
;
8318 isom_stts_entry_t
*data
= (isom_stts_entry_t
*)stts
->list
->tail
->data
;
8319 if( data
->sample_delta
== sample_delta
)
8320 ++ data
->sample_count
;
8321 else if( isom_add_stts_entry( stbl
, sample_delta
) )
8324 return sample_delta
;
8327 static int isom_add_cts( isom_stbl_t
*stbl
, isom_timestamp_t
*cache
, uint64_t cts
)
8329 isom_ctts_t
*ctts
= stbl
->ctts
;
8332 if( cts
== cache
->dts
)
8337 /* Add ctts box and the first ctts entry. */
8338 if( isom_add_ctts( stbl
) || isom_add_ctts_entry( stbl
, 0 ) )
8341 isom_ctts_entry_t
*data
= (isom_ctts_entry_t
*)ctts
->list
->head
->data
;
8342 uint32_t sample_count
= stbl
->stsz
->sample_count
;
8343 if( sample_count
!= 1 )
8345 data
->sample_count
= sample_count
- 1;
8346 if( isom_add_ctts_entry( stbl
, cts
- cache
->dts
) )
8350 data
->sample_offset
= cts
;
8356 isom_ctts_entry_t
*data
= (isom_ctts_entry_t
*)ctts
->list
->tail
->data
;
8357 uint32_t sample_offset
= cts
- cache
->dts
;
8358 if( data
->sample_offset
== sample_offset
)
8359 ++ data
->sample_count
;
8360 else if( isom_add_ctts_entry( stbl
, sample_offset
) )
8366 static int isom_add_timestamp( isom_trak_entry_t
*trak
, uint64_t dts
, uint64_t cts
)
8368 if( !trak
->cache
|| !trak
->mdia
->minf
->stbl
->stts
|| !trak
->mdia
->minf
->stbl
->stts
->list
)
8370 lsmash_root_t
*root
= trak
->root
;
8371 if( root
->isom_compatible
&& root
->qt_compatible
&& (cts
- dts
) > INT32_MAX
)
8372 return -1; /* sample_offset is not compatible. */
8373 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
8374 isom_timestamp_t
*ts_cache
= &trak
->cache
->timestamp
;
8375 uint32_t sample_count
= isom_get_sample_count( trak
);
8376 uint32_t sample_delta
= sample_count
> 1 ? isom_add_dts( stbl
, ts_cache
, dts
) : 0;
8377 if( sample_count
> 1 && !sample_delta
)
8379 if( isom_add_cts( stbl
, ts_cache
, cts
) )
8381 if( (cts
+ ts_cache
->ctd_shift
) < dts
)
8383 if( (root
->max_isom_version
< 4 && !root
->qt_compatible
) /* Negative sample offset is not supported. */
8384 || (root
->max_isom_version
>= 4 && trak
->root
->qt_compatible
) /* ctts version 1 is not defined in QTFF. */
8385 || root
->fragment
/* Composition time offset is positive. */
8386 || ((dts
- cts
) > INT32_MAX
) ) /* Overflow */
8388 ts_cache
->ctd_shift
= dts
- cts
;
8389 if( !stbl
->ctts
->version
&& !trak
->root
->qt_compatible
)
8390 stbl
->ctts
->version
= 1;
8392 if( trak
->cache
->fragment
)
8394 isom_fragment_t
*fragment_cache
= trak
->cache
->fragment
;
8395 fragment_cache
->last_duration
= sample_delta
;
8396 fragment_cache
->largest_cts
= LSMASH_MAX( ts_cache
->cts
, fragment_cache
->largest_cts
);
8401 static int isom_add_sync_point( isom_trak_entry_t
*trak
, uint32_t sample_number
, lsmash_sample_property_t
*prop
)
8403 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
8404 isom_cache_t
*cache
= trak
->cache
;
8405 if( prop
->random_access_type
!= ISOM_SAMPLE_RANDOM_ACCESS_TYPE_SYNC
) /* no null check for prop */
8407 if( !cache
->all_sync
)
8409 if( !stbl
->stss
&& isom_add_stss( stbl
) )
8411 if( isom_add_stss_entry( stbl
, 1 ) ) /* Declare here the first sample is a sync sample. */
8413 cache
->all_sync
= 0;
8416 if( cache
->all_sync
) /* We don't need stss box if all samples are sync sample. */
8420 if( isom_get_sample_count( trak
) == 1 )
8422 cache
->all_sync
= 1; /* Also the first sample is a sync sample. */
8425 if( isom_add_stss( stbl
) )
8428 return isom_add_stss_entry( stbl
, sample_number
);
8431 static int isom_add_partial_sync( isom_trak_entry_t
*trak
, uint32_t sample_number
, lsmash_sample_property_t
*prop
)
8433 if( !trak
->root
->qt_compatible
)
8435 if( prop
->random_access_type
!= QT_SAMPLE_RANDOM_ACCESS_TYPE_PARTIAL_SYNC
8436 && !(prop
->random_access_type
== ISOM_SAMPLE_RANDOM_ACCESS_TYPE_RECOVERY
&& prop
->recovery
.identifier
== prop
->recovery
.complete
) )
8438 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
8439 if( !stbl
->stps
&& isom_add_stps( stbl
) )
8441 return isom_add_stps_entry( stbl
, sample_number
);
8444 static int isom_add_dependency_type( isom_trak_entry_t
*trak
, lsmash_sample_property_t
*prop
)
8446 if( !trak
->root
->qt_compatible
&& !trak
->root
->avc_extensions
)
8448 uint8_t avc_extensions
= trak
->root
->avc_extensions
;
8449 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
8451 return isom_add_sdtp_entry( stbl
, prop
, avc_extensions
);
8452 if( !prop
->allow_earlier
&& !prop
->leading
&& !prop
->independent
&& !prop
->disposable
&& !prop
->redundant
) /* no null check for prop */
8454 if( isom_add_sdtp( stbl
) )
8456 uint32_t count
= isom_get_sample_count( trak
);
8457 /* fill past samples with ISOM_SAMPLE_*_UNKNOWN */
8458 lsmash_sample_property_t null_prop
= { 0 };
8459 for( uint32_t i
= 1; i
< count
; i
++ )
8460 if( isom_add_sdtp_entry( stbl
, &null_prop
, avc_extensions
) )
8462 return isom_add_sdtp_entry( stbl
, prop
, avc_extensions
);
8465 static int isom_group_random_access( isom_trak_entry_t
*trak
, lsmash_sample_property_t
*prop
)
8467 if( trak
->root
->max_isom_version
< 6 )
8469 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
8470 isom_sbgp_entry_t
*sbgp
= isom_get_sample_to_group( stbl
, ISOM_GROUP_TYPE_RAP
);
8471 isom_sgpd_entry_t
*sgpd
= isom_get_sample_group_description( stbl
, ISOM_GROUP_TYPE_RAP
);
8472 if( !sbgp
|| !sgpd
)
8474 uint8_t is_rap
= prop
->random_access_type
== ISOM_SAMPLE_RANDOM_ACCESS_TYPE_CLOSED_RAP
8475 || prop
->random_access_type
== ISOM_SAMPLE_RANDOM_ACCESS_TYPE_OPEN_RAP
8476 || prop
->random_access_type
== ISOM_SAMPLE_RANDOM_ACCESS_TYPE_UNKNOWN_RAP
8477 || (prop
->random_access_type
== ISOM_SAMPLE_RANDOM_ACCESS_TYPE_RECOVERY
&& prop
->recovery
.identifier
== prop
->recovery
.complete
);
8478 isom_rap_group_t
*group
= trak
->cache
->rap
;
8481 /* This sample is the first sample, create a grouping cache. */
8482 assert( isom_get_sample_count( trak
) == 1 );
8483 group
= malloc( sizeof(isom_rap_group_t
) );
8488 group
->random_access
= isom_add_rap_group_entry( sgpd
);
8489 group
->assignment
= isom_add_group_assignment_entry( sbgp
, 1, sgpd
->list
->entry_count
);
8493 /* The first sample is not always random access point. */
8494 group
->random_access
= NULL
;
8495 group
->assignment
= isom_add_group_assignment_entry( sbgp
, 1, 0 );
8497 if( !group
->assignment
)
8502 /* No need checking if group->assignment exists from here. */
8503 group
->is_prev_rap
= is_rap
;
8504 trak
->cache
->rap
= group
;
8507 if( group
->is_prev_rap
)
8509 /* OK. here, the previous sample is a menber of 'rap '. */
8512 /* This sample isn't a member of 'rap ' and the previous sample is.
8513 * So we create a new group and set 0 on its group_description_index. */
8514 group
->assignment
= isom_add_group_assignment_entry( sbgp
, 1, 0 );
8515 if( !group
->assignment
)
8521 else if( prop
->random_access_type
!= ISOM_SAMPLE_RANDOM_ACCESS_TYPE_CLOSED_RAP
)
8523 /* Create a new group since there is the possibility the next sample is a leading sample.
8524 * This sample is a member of 'rap ', so we set appropriate value on its group_description_index. */
8525 if( group
->random_access
)
8526 group
->random_access
->num_leading_samples_known
= 1;
8527 group
->random_access
= isom_add_rap_group_entry( sgpd
);
8528 group
->assignment
= isom_add_group_assignment_entry( sbgp
, 1, sgpd
->list
->entry_count
);
8529 if( !group
->assignment
)
8535 else /* The previous and current sample are a member of 'rap ', and the next sample must not be a leading sample. */
8536 ++ group
->assignment
->sample_count
;
8540 /* This sample is a member of 'rap ' and the previous sample isn't.
8541 * So we create a new group and set appropriate value on its group_description_index. */
8542 if( group
->random_access
)
8543 group
->random_access
->num_leading_samples_known
= 1;
8544 group
->random_access
= isom_add_rap_group_entry( sgpd
);
8545 group
->assignment
= isom_add_group_assignment_entry( sbgp
, 1, sgpd
->list
->entry_count
);
8546 if( !group
->assignment
)
8552 else /* The previous and current sample aren't a member of 'rap '. */
8553 ++ group
->assignment
->sample_count
;
8554 /* Obtain the property of the latest random access point group. */
8555 if( !is_rap
&& group
->random_access
)
8557 if( prop
->leading
== ISOM_SAMPLE_LEADING_UNKNOWN
)
8559 /* We can no longer know num_leading_samples in this group. */
8560 group
->random_access
->num_leading_samples_known
= 0;
8561 group
->random_access
= NULL
;
8565 if( prop
->leading
== ISOM_SAMPLE_IS_UNDECODABLE_LEADING
|| prop
->leading
== ISOM_SAMPLE_IS_DECODABLE_LEADING
)
8566 ++ group
->random_access
->num_leading_samples
;
8569 /* no more consecutive leading samples in this group */
8570 group
->random_access
->num_leading_samples_known
= 1;
8571 group
->random_access
= NULL
;
8575 group
->is_prev_rap
= is_rap
;
8579 static int isom_group_roll_recovery( isom_trak_entry_t
*trak
, lsmash_sample_property_t
*prop
)
8581 if( !trak
->root
->avc_extensions
)
8583 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
8584 isom_sbgp_entry_t
*sbgp
= isom_get_sample_to_group( stbl
, ISOM_GROUP_TYPE_ROLL
);
8585 isom_sgpd_entry_t
*sgpd
= isom_get_sample_group_description( stbl
, ISOM_GROUP_TYPE_ROLL
);
8586 if( !sbgp
|| !sgpd
)
8588 lsmash_entry_list_t
*pool
= trak
->cache
->roll
.pool
;
8591 pool
= lsmash_create_entry_list();
8594 trak
->cache
->roll
.pool
= pool
;
8596 isom_roll_group_t
*group
= (isom_roll_group_t
*)lsmash_get_entry_data( pool
, pool
->entry_count
);
8597 uint32_t sample_count
= isom_get_sample_count( trak
);
8598 if( !group
|| prop
->random_access_type
== ISOM_SAMPLE_RANDOM_ACCESS_TYPE_RECOVERY
)
8601 group
->delimited
= 1;
8603 assert( sample_count
== 1 );
8604 /* Create a new group. This group is not 'roll' yet, so we set 0 on its group_description_index. */
8605 group
= malloc( sizeof(isom_roll_group_t
) );
8608 memset( group
, 0, sizeof(isom_roll_group_t
) );
8609 group
->first_sample
= sample_count
;
8610 group
->recovery_point
= prop
->recovery
.complete
;
8611 group
->assignment
= isom_add_group_assignment_entry( sbgp
, 1, 0 );
8612 if( !group
->assignment
|| lsmash_add_entry( pool
, group
) )
8619 ++ group
->assignment
->sample_count
;
8620 /* If encountered a sync sample, all recoveries are completed here. */
8621 if( prop
->random_access_type
== ISOM_SAMPLE_RANDOM_ACCESS_TYPE_CLOSED_RAP
)
8623 for( lsmash_entry_t
*entry
= pool
->head
; entry
; entry
= entry
->next
)
8625 group
= (isom_roll_group_t
*)entry
->data
;
8628 group
->described
= 1;
8632 for( lsmash_entry_t
*entry
= pool
->head
; entry
; entry
= entry
->next
)
8634 group
= (isom_roll_group_t
*)entry
->data
;
8637 if( group
->described
)
8639 if( prop
->recovery
.identifier
== group
->recovery_point
)
8641 group
->described
= 1;
8642 int16_t distance
= sample_count
- group
->first_sample
;
8643 /* Add a roll recovery entry only when roll_distance isn't zero since roll_distance = 0 must not be used. */
8646 /* Now, this group is a 'roll'. */
8647 if( !isom_add_roll_group_entry( sgpd
, distance
) )
8649 group
->assignment
->group_description_index
= sgpd
->list
->entry_count
;
8650 /* All groups before the current group are described. */
8651 lsmash_entry_t
*current
= entry
;
8652 for( entry
= pool
->head
; entry
!= current
; entry
= entry
->next
)
8654 group
= (isom_roll_group_t
*)entry
->data
;
8657 group
->described
= 1;
8660 break; /* Avoid evaluating groups, in the pool, having the same identifier for recovery point again. */
8663 /* Remove pooled caches that has become unnecessary. */
8664 for( lsmash_entry_t
*entry
= pool
->head
; entry
; entry
= pool
->head
)
8666 group
= (isom_roll_group_t
*)entry
->data
;
8669 if( !group
->delimited
|| !group
->described
)
8671 if( lsmash_remove_entry_direct( pool
, entry
, NULL
) )
8677 /* returns 1 if pooled samples must be flushed. */
8678 /* FIXME: I wonder if this function should have a extra argument which indicates force_to_flush_cached_chunk.
8679 see lsmash_append_sample for detail. */
8680 static int isom_add_chunk( isom_trak_entry_t
*trak
, lsmash_sample_t
*sample
)
8682 if( !trak
->root
|| !trak
->cache
|| !trak
->mdia
->mdhd
|| !trak
->mdia
->mdhd
->timescale
8683 || !trak
->mdia
->minf
->stbl
->stsc
|| !trak
->mdia
->minf
->stbl
->stsc
->list
)
8685 lsmash_root_t
*root
= trak
->root
;
8686 isom_chunk_t
*current
= &trak
->cache
->chunk
;
8687 if( !current
->pool
)
8689 /* Very initial settings, just once per track */
8690 current
->pool
= isom_create_sample_pool( 0 );
8691 if( !current
->pool
)
8694 if( !current
->pool
->sample_count
)
8696 /* Cannot decide whether we should flush the current sample or not here yet. */
8697 ++ current
->chunk_number
;
8698 current
->sample_description_index
= sample
->index
;
8699 current
->first_dts
= sample
->dts
;
8702 if( sample
->dts
< current
->first_dts
)
8703 return -1; /* easy error check. */
8704 if( (root
->max_chunk_duration
>= ((double)(sample
->dts
- current
->first_dts
) / trak
->mdia
->mdhd
->timescale
))
8705 && (root
->max_chunk_size
>= current
->pool
->size
+ sample
->length
)
8706 && (current
->sample_description_index
== sample
->index
) )
8707 return 0; /* No need to flush current cached chunk, the current sample must be put into that. */
8708 /* NOTE: chunk relative stuff must be pushed into root after a chunk is fully determined with its contents. */
8709 /* now current cached chunk is fixed, actually add chunk relative properties to root accordingly. */
8710 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
8711 lsmash_entry_t
*last_stsc_entry
= stbl
->stsc
->list
->tail
;
8712 /* Create a new chunk sequence in this track if needed. */
8713 if( (!last_stsc_entry
|| current
->pool
->sample_count
!= ((isom_stsc_entry_t
*)last_stsc_entry
->data
)->samples_per_chunk
)
8714 && isom_add_stsc_entry( stbl
, current
->chunk_number
, current
->pool
->sample_count
, current
->sample_description_index
) )
8716 /* Add a new chunk offset in this track. */
8717 uint64_t offset
= root
->size
;
8718 if( root
->fragment
)
8719 offset
+= ISOM_BASEBOX_COMMON_SIZE
+ root
->fragment
->pool_size
;
8720 if( isom_add_stco_entry( stbl
, offset
) )
8722 /* update cache information */
8723 ++ current
->chunk_number
;
8724 /* re-initialize cache, using the current sample */
8725 current
->sample_description_index
= sample
->index
;
8726 current
->first_dts
= sample
->dts
;
8727 /* current->pool must be flushed in isom_append_sample_internal() */
8731 static int isom_write_pooled_samples( lsmash_root_t
*root
, isom_sample_pool_t
*pool
)
8733 if( !root
|| !root
->mdat
|| !root
->bs
|| !root
->bs
->stream
)
8735 lsmash_bs_put_bytes( root
->bs
, pool
->data
, pool
->size
);
8736 if( lsmash_bs_write_data( root
->bs
) )
8738 root
->mdat
->size
+= pool
->size
;
8739 root
->size
+= pool
->size
;
8740 pool
->sample_count
= 0;
8745 static int isom_update_sample_tables( isom_trak_entry_t
*trak
, lsmash_sample_t
*sample
)
8747 /* Add a sample_size and increment sample_count. */
8748 uint32_t sample_count
= isom_add_size( trak
, sample
->length
);
8751 /* Add a decoding timestamp and a composition timestamp. */
8752 if( isom_add_timestamp( trak
, sample
->dts
, sample
->cts
) )
8754 /* Add a sync point if needed. */
8755 if( isom_add_sync_point( trak
, sample_count
, &sample
->prop
) )
8757 /* Add a partial sync point if needed. */
8758 if( isom_add_partial_sync( trak
, sample_count
, &sample
->prop
) )
8760 /* Add leading, independent, disposable and redundant information if needed. */
8761 if( isom_add_dependency_type( trak
, &sample
->prop
) )
8763 /* Group samples into random access point type if needed. */
8764 if( isom_group_random_access( trak
, &sample
->prop
) )
8766 /* Group samples into random access recovery point type if needed. */
8767 if( isom_group_roll_recovery( trak
, &sample
->prop
) )
8769 /* Add a chunk if needed. */
8770 return isom_add_chunk( trak
, sample
);
8773 static int isom_append_fragment_track_run( lsmash_root_t
*root
, isom_chunk_t
*chunk
)
8775 if( !chunk
->pool
|| !chunk
->pool
->size
)
8777 isom_fragment_manager_t
*fragment
= root
->fragment
;
8778 /* Move data in the pool of the current track fragment to the pool of the current movie fragment.
8779 * Empty the pool of current track. We don't delete data of samples here. */
8780 if( lsmash_add_entry( fragment
->pool
, chunk
->pool
) )
8782 fragment
->pool
->entry_count
+= chunk
->pool
->sample_count
;
8783 fragment
->pool_size
+= chunk
->pool
->size
;
8784 chunk
->pool
= isom_create_sample_pool( chunk
->pool
->size
);
8785 return chunk
->pool
? 0 : -1;
8788 static int isom_output_cached_chunk( isom_trak_entry_t
*trak
)
8790 lsmash_root_t
*root
= trak
->root
;
8791 isom_chunk_t
*chunk
= &trak
->cache
->chunk
;
8792 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
8793 lsmash_entry_t
*last_stsc_entry
= stbl
->stsc
->list
->tail
;
8794 /* Create a new chunk sequence in this track if needed. */
8795 if( (!last_stsc_entry
|| chunk
->pool
->sample_count
!= ((isom_stsc_entry_t
*)last_stsc_entry
->data
)->samples_per_chunk
)
8796 && isom_add_stsc_entry( stbl
, chunk
->chunk_number
, chunk
->pool
->sample_count
, chunk
->sample_description_index
) )
8798 if( root
->fragment
)
8800 /* Add a new chunk offset in this track. */
8801 if( isom_add_stco_entry( stbl
, root
->size
+ ISOM_BASEBOX_COMMON_SIZE
+ root
->fragment
->pool_size
) )
8803 return isom_append_fragment_track_run( root
, chunk
);
8805 /* Add a new chunk offset in this track. */
8806 if( isom_add_stco_entry( stbl
, root
->size
) )
8808 /* Output pooled samples in this track. */
8809 return isom_write_pooled_samples( root
, chunk
->pool
);
8812 static int isom_pool_sample( isom_sample_pool_t
*pool
, lsmash_sample_t
*sample
)
8814 uint64_t pool_size
= pool
->size
+ sample
->length
;
8815 if( pool
->alloc
< pool_size
)
8818 uint64_t alloc
= pool_size
+ (1<<16);
8820 data
= malloc( alloc
);
8822 data
= realloc( pool
->data
, alloc
);
8826 pool
->alloc
= alloc
;
8828 memcpy( pool
->data
+ pool
->size
, sample
->data
, sample
->length
);
8829 pool
->size
= pool_size
;
8830 pool
->sample_count
+= 1;
8831 lsmash_delete_sample( sample
);
8835 static int isom_append_sample_internal( isom_trak_entry_t
*trak
, lsmash_sample_t
*sample
)
8837 int flush
= isom_update_sample_tables( trak
, sample
);
8840 /* flush == 1 means pooled samples must be flushed. */
8841 lsmash_root_t
*root
= trak
->root
;
8842 isom_sample_pool_t
*current_pool
= trak
->cache
->chunk
.pool
;
8843 if( flush
== 1 && isom_write_pooled_samples( root
, current_pool
) )
8845 /* Arbitration system between tracks with extremely scattering dts.
8846 * Here, we check whether asynchronization between the tracks exceeds the tolerance.
8847 * If a track has too old "first DTS" in its cached chunk than current sample's DTS, then its pooled samples must be flushed.
8848 * We don't consider presentation of media since any edit can pick an arbitrary portion of media in track.
8849 * Note: you needn't read this loop until you grasp the basic handling of chunks. */
8850 double tolerance
= root
->max_async_tolerance
;
8851 for( lsmash_entry_t
*entry
= root
->moov
->trak_list
->head
; entry
; entry
= entry
->next
)
8853 isom_trak_entry_t
*other
= (isom_trak_entry_t
*)entry
->data
;
8856 if( !other
|| !other
->cache
|| !other
->mdia
|| !other
->mdia
->mdhd
|| !other
->mdia
->mdhd
->timescale
8857 || !other
->mdia
->minf
|| !other
->mdia
->minf
->stbl
|| !other
->mdia
->minf
->stbl
->stsc
|| !other
->mdia
->minf
->stbl
->stsc
->list
)
8859 isom_chunk_t
*chunk
= &other
->cache
->chunk
;
8860 if( !chunk
->pool
|| !chunk
->pool
->sample_count
)
8862 double diff
= ((double)sample
->dts
/ trak
->mdia
->mdhd
->timescale
)
8863 - ((double)chunk
->first_dts
/ other
->mdia
->mdhd
->timescale
);
8864 if( diff
> tolerance
&& isom_output_cached_chunk( other
) )
8866 /* Note: we don't flush the cached chunk in the current track and the current sample here
8867 * even if the conditional expression of '-diff > tolerance' meets.
8868 * That's useless because appending a sample to another track would be a good equivalent.
8869 * It's even harmful because it causes excess chunk division by calling
8870 * isom_output_cached_chunk() which always generates a new chunk.
8871 * Anyway some excess chunk division will be there, but rather less without it.
8872 * To completely avoid this, we need to observe at least whether the current sample will be placed
8873 * right next to the previous chunk of the same track or not. */
8875 /* anyway the current sample must be pooled. */
8876 return isom_pool_sample( current_pool
, sample
);
8879 static int isom_append_sample( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_sample_t
*sample
)
8881 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
8882 if( !trak
|| !trak
->root
|| !trak
->cache
|| !trak
->mdia
8883 || !trak
->mdia
->mdhd
|| !trak
->mdia
->mdhd
->timescale
8884 || !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
8885 || !trak
->mdia
->minf
->stbl
->stsd
|| !trak
->mdia
->minf
->stbl
->stsd
->list
8886 || !trak
->mdia
->minf
->stbl
->stsc
|| !trak
->mdia
->minf
->stbl
->stsc
->list
)
8888 /* If there is no available Media Data Box to write samples, add and write a new one before any chunk offset is decided. */
8891 if( isom_new_mdat( root
, 0 ) )
8893 /* Add the size of the Media Data Box and the placeholder. */
8894 root
->size
+= 2 * ISOM_BASEBOX_COMMON_SIZE
;
8896 isom_sample_entry_t
*sample_entry
= (isom_sample_entry_t
*)lsmash_get_entry_data( trak
->mdia
->minf
->stbl
->stsd
->list
, sample
->index
);
8899 if( isom_is_lpcm_audio( sample_entry
->type
) )
8901 uint32_t frame_size
= ((isom_audio_entry_t
*)sample_entry
)->constBytesPerAudioPacket
;
8902 if( sample
->length
== frame_size
)
8903 return isom_append_sample_internal( trak
, sample
);
8904 else if( sample
->length
< frame_size
)
8906 /* Append samples splitted into each LPCMFrame. */
8907 uint64_t dts
= sample
->dts
;
8908 uint64_t cts
= sample
->cts
;
8909 for( uint32_t offset
= 0; offset
< sample
->length
; offset
+= frame_size
)
8911 lsmash_sample_t
*lpcm_sample
= lsmash_create_sample( frame_size
);
8914 memcpy( lpcm_sample
->data
, sample
->data
+ offset
, frame_size
);
8915 lpcm_sample
->dts
= dts
++;
8916 lpcm_sample
->cts
= cts
++;
8917 lpcm_sample
->prop
= sample
->prop
;
8918 lpcm_sample
->index
= sample
->index
;
8919 if( isom_append_sample_internal( trak
, lpcm_sample
) )
8921 lsmash_delete_sample( lpcm_sample
);
8925 lsmash_delete_sample( sample
);
8928 return isom_append_sample_internal( trak
, sample
);
8931 static int isom_output_cache( isom_trak_entry_t
*trak
)
8933 if( trak
->cache
->chunk
.pool
&& trak
->cache
->chunk
.pool
->sample_count
8934 && isom_output_cached_chunk( trak
) )
8936 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
8937 if( !stbl
->sgpd_list
)
8939 for( lsmash_entry_t
*entry
= stbl
->sgpd_list
->head
; entry
; entry
= entry
->next
)
8941 isom_sgpd_entry_t
*sgpd
= (isom_sgpd_entry_t
*)entry
->data
;
8944 switch( sgpd
->grouping_type
)
8946 case ISOM_GROUP_TYPE_RAP
:
8948 isom_rap_group_t
*group
= trak
->cache
->rap
;
8951 if( trak
->root
->fragment
)
8956 if( !group
->random_access
)
8958 group
->random_access
->num_leading_samples_known
= 1;
8961 case ISOM_GROUP_TYPE_ROLL
:
8962 if( !trak
->cache
->roll
.pool
)
8964 if( trak
->root
->fragment
)
8969 for( lsmash_entry_t
*roll_entry
= trak
->cache
->roll
.pool
->head
; roll_entry
; roll_entry
= roll_entry
->next
)
8971 isom_roll_group_t
*group
= (isom_roll_group_t
*)roll_entry
->data
;
8974 group
->described
= 1;
8984 static int isom_flush_fragment_pooled_samples( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t last_sample_duration
)
8986 isom_traf_entry_t
*traf
= isom_get_traf( root
->fragment
->movie
, track_ID
);
8988 return 0; /* no samples */
8989 if( !traf
->cache
|| !traf
->cache
->fragment
)
8991 if( traf
->trun_list
&& traf
->trun_list
->entry_count
&& traf
->trun_list
->tail
&& traf
->trun_list
->tail
->data
)
8993 /* Media Data Box preceded by Movie Fragment Box could change base_data_offsets in each track fragments later.
8994 * We can't consider this here because the length of Movie Fragment Box is unknown at this step yet. */
8995 isom_trun_entry_t
*trun
= (isom_trun_entry_t
*)traf
->trun_list
->tail
->data
;
8996 if( root
->fragment
->pool_size
)
8997 trun
->flags
|= ISOM_TR_FLAGS_DATA_OFFSET_PRESENT
;
8998 trun
->data_offset
= root
->fragment
->pool_size
;
9000 if( isom_append_fragment_track_run( root
, &traf
->cache
->chunk
) )
9002 return isom_set_fragment_last_duration( traf
, last_sample_duration
);
9005 int lsmash_flush_pooled_samples( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t last_sample_delta
)
9009 if( root
->fragment
&& root
->fragment
->movie
)
9010 return isom_flush_fragment_pooled_samples( root
, track_ID
, last_sample_delta
);
9011 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
9012 if( !trak
|| !trak
->cache
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
9013 || !trak
->mdia
->minf
->stbl
->stsc
|| !trak
->mdia
->minf
->stbl
->stsc
->list
)
9015 if( isom_output_cache( trak
) )
9017 return lsmash_set_last_sample_delta( root
, track_ID
, last_sample_delta
);
9020 /* This function doesn't update sample_duration of the last sample in the previous movie fragment.
9021 * Instead of this, isom_finish_movie_fragment undertakes this task. */
9022 static int isom_update_fragment_previous_sample_duration( isom_traf_entry_t
*traf
, isom_trex_entry_t
*trex
, uint32_t duration
)
9024 isom_tfhd_t
*tfhd
= traf
->tfhd
;
9025 isom_trun_entry_t
*trun
= (isom_trun_entry_t
*)traf
->trun_list
->tail
->data
;
9026 int previous_run_has_previous_sample
= 0;
9027 if( trun
->sample_count
== 1 )
9029 if( traf
->trun_list
->entry_count
== 1 )
9030 return 0; /* The previous track run belongs to the previous movie fragment if it exists. */
9031 if( !traf
->trun_list
->tail
->prev
|| !traf
->trun_list
->tail
->prev
->data
)
9033 /* OK. The previous sample exists in the previous track run in the same track fragment. */
9034 trun
= (isom_trun_entry_t
*)traf
->trun_list
->tail
->prev
->data
;
9035 previous_run_has_previous_sample
= 1;
9037 /* Update default_sample_duration of the Track Fragment Header Box
9038 * if this duration is what the first sample in the current track fragment owns. */
9039 if( (trun
->sample_count
== 2 && traf
->trun_list
->entry_count
== 1)
9040 || (trun
->sample_count
== 1 && traf
->trun_list
->entry_count
== 2) )
9042 if( duration
!= trex
->default_sample_duration
)
9043 tfhd
->flags
|= ISOM_TF_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT
;
9044 tfhd
->default_sample_duration
= duration
;
9046 /* Update the previous sample_duration if needed. */
9047 if( duration
!= tfhd
->default_sample_duration
)
9048 trun
->flags
|= ISOM_TR_FLAGS_SAMPLE_DURATION_PRESENT
;
9051 uint32_t sample_number
= trun
->sample_count
- !previous_run_has_previous_sample
;
9052 isom_trun_optional_row_t
*row
= isom_request_trun_optional_row( trun
, tfhd
, sample_number
);
9055 row
->sample_duration
= duration
;
9057 traf
->cache
->fragment
->last_duration
= duration
;
9061 static isom_sample_flags_t
isom_generate_fragment_sample_flags( lsmash_sample_t
*sample
)
9063 isom_sample_flags_t flags
;
9065 flags
.is_leading
= sample
->prop
.leading
& 0x3;
9066 flags
.sample_depends_on
= sample
->prop
.independent
& 0x3;
9067 flags
.sample_is_depended_on
= sample
->prop
.disposable
& 0x3;
9068 flags
.sample_has_redundancy
= sample
->prop
.redundant
& 0x3;
9069 flags
.sample_padding_value
= 0;
9070 flags
.sample_is_non_sync_sample
= sample
->prop
.random_access_type
!= ISOM_SAMPLE_RANDOM_ACCESS_TYPE_SYNC
;
9071 flags
.sample_degradation_priority
= 0;
9075 static int isom_update_fragment_sample_tables( isom_traf_entry_t
*traf
, lsmash_sample_t
*sample
)
9077 isom_tfhd_t
*tfhd
= traf
->tfhd
;
9078 isom_trex_entry_t
*trex
= isom_get_trex( traf
->root
->moov
->mvex
, tfhd
->track_ID
);
9081 lsmash_root_t
*root
= traf
->root
;
9082 isom_cache_t
*cache
= traf
->cache
;
9083 isom_chunk_t
*current
= &cache
->chunk
;
9084 /* Create a new track run if the duration exceeds max_chunk_duration.
9085 * Old one will be appended to the pool of this movie fragment. */
9086 int delimit
= (root
->max_chunk_duration
< ((double)(sample
->dts
- current
->first_dts
) / lsmash_get_media_timescale( root
, tfhd
->track_ID
)))
9087 || (root
->max_chunk_size
< (current
->pool
->size
+ sample
->length
));
9088 isom_trun_entry_t
*trun
= NULL
;
9089 if( !traf
->trun_list
|| !traf
->trun_list
->entry_count
|| delimit
)
9091 if( delimit
&& traf
->trun_list
&& traf
->trun_list
->entry_count
&& traf
->trun_list
->tail
&& traf
->trun_list
->tail
->data
)
9093 /* Media Data Box preceded by Movie Fragment Box could change base data offsets in each track fragments later.
9094 * We can't consider this here because the length of Movie Fragment Box is unknown at this step yet. */
9095 trun
= (isom_trun_entry_t
*)traf
->trun_list
->tail
->data
;
9096 if( root
->fragment
->pool_size
)
9097 trun
->flags
|= ISOM_TR_FLAGS_DATA_OFFSET_PRESENT
;
9098 trun
->data_offset
= root
->fragment
->pool_size
;
9100 trun
= isom_add_trun( traf
);
9103 if( !current
->pool
)
9105 /* Very initial settings, just once per track */
9106 current
->pool
= isom_create_sample_pool( 0 );
9107 if( !current
->pool
)
9113 if( !traf
->trun_list
->tail
|| !traf
->trun_list
->tail
->data
)
9115 trun
= (isom_trun_entry_t
*)traf
->trun_list
->tail
->data
;
9117 uint32_t sample_composition_time_offset
= sample
->cts
- sample
->dts
;
9118 isom_sample_flags_t sample_flags
= isom_generate_fragment_sample_flags( sample
);
9119 if( ++trun
->sample_count
== 1 )
9121 if( traf
->trun_list
->entry_count
== 1 )
9123 /* This track fragment isn't empty-duration-fragment any more. */
9124 tfhd
->flags
&= ~ISOM_TF_FLAGS_DURATION_IS_EMPTY
;
9125 /* Set up sample_description_index in this track fragment. */
9126 if( sample
->index
!= trex
->default_sample_description_index
)
9127 tfhd
->flags
|= ISOM_TF_FLAGS_SAMPLE_DESCRIPTION_INDEX_PRESENT
;
9128 tfhd
->sample_description_index
= current
->sample_description_index
= sample
->index
;
9129 /* Set up default_sample_size used in this track fragment. */
9130 tfhd
->default_sample_size
= sample
->length
;
9131 /* Set up default_sample_flags used in this track fragment.
9132 * Note: we decide an appropriate default value at the end of this movie fragment. */
9133 tfhd
->default_sample_flags
= sample_flags
;
9134 /* Set up random access information if this sample is random accessible sample.
9135 * We inform only the first sample in each movie fragment. */
9136 if( root
->bs
->stream
!= stdout
&& sample
->prop
.random_access_type
)
9138 isom_tfra_entry_t
*tfra
= isom_get_tfra( root
->mfra
, tfhd
->track_ID
);
9141 tfra
= isom_add_tfra( root
->mfra
);
9144 tfra
->track_ID
= tfhd
->track_ID
;
9148 tfra
->list
= lsmash_create_entry_list();
9152 isom_tfra_location_time_entry_t
*rap
= malloc( sizeof(isom_tfra_location_time_entry_t
) );
9155 rap
->time
= sample
->cts
; /* If this is wrong, blame vague descriptions of 'presentation time' in the spec. */
9156 rap
->moof_offset
= root
->size
; /* We place Movie Fragment Box in the head of each movie fragment. */
9157 rap
->traf_number
= cache
->fragment
->traf_number
;
9158 rap
->trun_number
= traf
->trun_list
->entry_count
;
9159 rap
->sample_number
= trun
->sample_count
;
9160 if( lsmash_add_entry( tfra
->list
, rap
) )
9162 tfra
->number_of_entry
= tfra
->list
->entry_count
;
9164 for( length
= 1; rap
->traf_number
>> (length
* 8); length
++ );
9165 tfra
->length_size_of_traf_num
= LSMASH_MAX( length
- 1, tfra
->length_size_of_traf_num
);
9166 for( length
= 1; rap
->traf_number
>> (length
* 8); length
++ );
9167 tfra
->length_size_of_trun_num
= LSMASH_MAX( length
- 1, tfra
->length_size_of_trun_num
);
9168 for( length
= 1; rap
->sample_number
>> (length
* 8); length
++ );
9169 tfra
->length_size_of_sample_num
= LSMASH_MAX( length
- 1, tfra
->length_size_of_sample_num
);
9172 trun
->first_sample_flags
= sample_flags
;
9173 current
->first_dts
= sample
->dts
;
9175 /* Update the optional rows in the current track run except for sample_duration if needed. */
9176 if( sample
->length
!= tfhd
->default_sample_size
)
9177 trun
->flags
|= ISOM_TR_FLAGS_SAMPLE_SIZE_PRESENT
;
9178 if( memcmp( &sample_flags
, &tfhd
->default_sample_flags
, sizeof(isom_sample_flags_t
) ) )
9179 trun
->flags
|= ISOM_TR_FLAGS_SAMPLE_FLAGS_PRESENT
;
9180 if( sample_composition_time_offset
)
9181 trun
->flags
|= ISOM_TR_FLAGS_SAMPLE_COMPOSITION_TIME_OFFSET_PRESENT
;
9184 isom_trun_optional_row_t
*row
= isom_request_trun_optional_row( trun
, tfhd
, trun
->sample_count
);
9187 row
->sample_size
= sample
->length
;
9188 row
->sample_flags
= sample_flags
;
9189 row
->sample_composition_time_offset
= sample_composition_time_offset
;
9191 /* Set up the previous sample_duration if this sample is not the first sample in the overall movie. */
9192 if( cache
->fragment
->has_samples
)
9194 /* Note: when using for live streaming, it is not good idea to return error (-1) by sample->dts < prev_dts
9195 * since that's trivial for such semi-permanent presentation. */
9196 uint64_t prev_dts
= cache
->timestamp
.dts
;
9197 if( sample
->dts
<= prev_dts
|| sample
->dts
> prev_dts
+ UINT32_MAX
)
9199 uint32_t sample_duration
= sample
->dts
- prev_dts
;
9200 if( isom_update_fragment_previous_sample_duration( traf
, trex
, sample_duration
) )
9203 cache
->timestamp
.dts
= sample
->dts
;
9204 cache
->fragment
->largest_cts
= LSMASH_MAX( sample
->cts
, cache
->fragment
->largest_cts
);
9208 static int isom_append_fragment_sample_internal_initial( isom_trak_entry_t
*trak
, lsmash_sample_t
*sample
)
9211 /* Update the sample tables of this track fragment.
9212 * If a new chunk was created, append the previous one to the pool of this movie fragment. */
9213 delimit
= isom_update_sample_tables( trak
, sample
);
9216 else if( delimit
== 1 )
9217 isom_append_fragment_track_run( trak
->root
, &trak
->cache
->chunk
);
9218 /* Add a new sample into the pool of this track fragment. */
9219 if( isom_pool_sample( trak
->cache
->chunk
.pool
, sample
) )
9221 trak
->cache
->fragment
->has_samples
= 1;
9225 static int isom_append_fragment_sample_internal( isom_traf_entry_t
*traf
, lsmash_sample_t
*sample
)
9228 /* Update the sample tables of this track fragment.
9229 * If a new track run was created, append the previous one to the pool of this movie fragment. */
9230 delimit
= isom_update_fragment_sample_tables( traf
, sample
);
9233 else if( delimit
== 1 )
9234 isom_append_fragment_track_run( traf
->root
, &traf
->cache
->chunk
);
9235 /* Add a new sample into the pool of this track fragment. */
9236 if( isom_pool_sample( traf
->cache
->chunk
.pool
, sample
) )
9238 traf
->cache
->fragment
->has_samples
= 1;
9242 static int isom_append_fragment_sample( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_sample_t
*sample
)
9244 isom_fragment_manager_t
*fragment
= root
->fragment
;
9245 if( !fragment
|| !fragment
->pool
)
9247 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
9248 if( !trak
|| !trak
->root
|| !trak
->cache
|| !trak
->cache
->fragment
|| !trak
->tkhd
|| !trak
->mdia
9249 || !trak
->mdia
->mdhd
|| !trak
->mdia
->mdhd
->timescale
9250 || !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
9251 || !trak
->mdia
->minf
->stbl
->stsd
|| !trak
->mdia
->minf
->stbl
->stsd
->list
9252 || !trak
->mdia
->minf
->stbl
->stsc
|| !trak
->mdia
->minf
->stbl
->stsc
->list
)
9254 int (*append_sample_func
)( void *, lsmash_sample_t
* ) = NULL
;
9255 void *track_fragment
= NULL
;
9256 if( !fragment
->movie
)
9258 append_sample_func
= (int (*)( void *, lsmash_sample_t
* ))isom_append_fragment_sample_internal_initial
;
9259 track_fragment
= trak
;
9263 isom_traf_entry_t
*traf
= isom_get_traf( fragment
->movie
, track_ID
);
9266 traf
= isom_add_traf( root
, fragment
->movie
);
9267 if( isom_add_tfhd( traf
) )
9269 traf
->tfhd
->flags
= ISOM_TF_FLAGS_DURATION_IS_EMPTY
; /* no samples for this track fragment yet */
9270 traf
->tfhd
->track_ID
= trak
->tkhd
->track_ID
;
9271 traf
->cache
= trak
->cache
;
9272 traf
->cache
->fragment
->traf_number
= fragment
->movie
->traf_list
->entry_count
;
9274 else if( !traf
->root
|| !traf
->root
->moov
|| !traf
->root
->moov
->mvex
|| !traf
->cache
|| !traf
->tfhd
)
9276 append_sample_func
= (int (*)( void *, lsmash_sample_t
* ))isom_append_fragment_sample_internal
;
9277 track_fragment
= traf
;
9279 isom_sample_entry_t
*sample_entry
= (isom_sample_entry_t
*)lsmash_get_entry_data( trak
->mdia
->minf
->stbl
->stsd
->list
, sample
->index
);
9282 if( isom_is_lpcm_audio( sample_entry
->type
) )
9284 uint32_t frame_size
= ((isom_audio_entry_t
*)sample_entry
)->constBytesPerAudioPacket
;
9285 if( sample
->length
== frame_size
)
9286 return append_sample_func( track_fragment
, sample
);
9287 else if( sample
->length
< frame_size
)
9289 /* Append samples splitted into each LPCMFrame. */
9290 uint64_t dts
= sample
->dts
;
9291 uint64_t cts
= sample
->cts
;
9292 for( uint32_t offset
= 0; offset
< sample
->length
; offset
+= frame_size
)
9294 lsmash_sample_t
*lpcm_sample
= lsmash_create_sample( frame_size
);
9297 memcpy( lpcm_sample
->data
, sample
->data
+ offset
, frame_size
);
9298 lpcm_sample
->dts
= dts
++;
9299 lpcm_sample
->cts
= cts
++;
9300 lpcm_sample
->prop
= sample
->prop
;
9301 lpcm_sample
->index
= sample
->index
;
9302 if( append_sample_func( track_fragment
, lpcm_sample
) )
9304 lsmash_delete_sample( lpcm_sample
);
9308 lsmash_delete_sample( sample
);
9311 return append_sample_func( track_fragment
, sample
);
9314 int lsmash_append_sample( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_sample_t
*sample
)
9316 /* We think max_chunk_duration == 0, which means all samples will be cached on memory, should be prevented.
9317 * This means removal of a feature that we used to have, but anyway very alone chunk does not make sense. */
9318 if( !root
|| !root
->bs
|| !sample
|| !sample
->data
|| !track_ID
9319 || root
->max_chunk_duration
== 0 || root
->max_async_tolerance
== 0 )
9321 /* Write File Type Box here if it was not written yet. */
9322 if( !root
->file_type_written
&& isom_write_ftyp( root
) )
9324 if( root
->fragment
&& root
->fragment
->pool
)
9325 return isom_append_fragment_sample( root
, track_ID
, sample
);
9326 return isom_append_sample( root
, track_ID
, sample
);
9329 /*---- misc functions ----*/
9331 #define CHAPTER_BUFSIZE 512 /* for chapter handling */
9333 static int isom_get_start_time( char *chap_time
, isom_chapter_entry_t
*data
)
9337 if( sscanf( chap_time
, "%"SCNu64
":%2"SCNu64
":%lf", &hh
, &mm
, &ss
) != 3 )
9339 /* check overflow */
9340 if( hh
>= 5124095 || mm
>= 60 || ss
>= 60 )
9343 data
->start_time
= (hh
* 3600 + mm
* 60 + ss
) * 1e9
;
9347 static int isom_lumber_line( char *buff
, int bufsize
, FILE *chapter
)
9350 /* remove newline codes and skip empty line */
9352 if( fgets( buff
, bufsize
, chapter
) == NULL
)
9354 tail
= &buff
[ strlen( buff
) - 1 ];
9355 while( tail
>= buff
&& ( *tail
== '\n' || *tail
== '\r' ) )
9357 }while( tail
< buff
);
9361 static int isom_read_simple_chapter( FILE *chapter
, isom_chapter_entry_t
*data
)
9363 char buff
[CHAPTER_BUFSIZE
];
9366 /* get start_time */
9367 if( isom_lumber_line( buff
, CHAPTER_BUFSIZE
, chapter
) )
9369 char *chapter_time
= strchr( buff
, '=' ); /* find separator */
9371 || isom_get_start_time( chapter_time
, data
)
9372 || isom_lumber_line( buff
, CHAPTER_BUFSIZE
, chapter
) ) /* get chapter_name */
9374 char *chapter_name
= strchr( buff
, '=' ); /* find separator */
9375 if( !chapter_name
++ )
9377 len
= LSMASH_MIN( 255, strlen( chapter_name
) ); /* We support length of chapter_name up to 255 */
9378 data
->chapter_name
= ( char* )malloc( len
+ 1 );
9379 if( !data
->chapter_name
)
9381 memcpy( data
->chapter_name
, chapter_name
, len
);
9382 data
->chapter_name
[len
] = '\0';
9386 static int isom_read_minimum_chapter( FILE *chapter
, isom_chapter_entry_t
*data
)
9388 char buff
[CHAPTER_BUFSIZE
];
9391 if( isom_lumber_line( buff
, CHAPTER_BUFSIZE
, chapter
) /* read newline */
9392 || isom_get_start_time( buff
, data
) ) /* get start_time */
9394 /* get chapter_name */
9395 char *chapter_name
= strchr( buff
, ' ' ); /* find separator */
9396 if( !chapter_name
++ )
9398 len
= LSMASH_MIN( 255, strlen( chapter_name
) ); /* We support length of chapter_name up to 255 */
9399 data
->chapter_name
= ( char* )malloc( len
+ 1 );
9400 if( !data
->chapter_name
)
9402 memcpy( data
->chapter_name
, chapter_name
, len
);
9403 data
->chapter_name
[len
] = '\0';
9407 typedef int (*fn_get_chapter_data
)( FILE *, isom_chapter_entry_t
* );
9409 static fn_get_chapter_data
isom_check_chap_line( char *file_name
)
9411 char buff
[CHAPTER_BUFSIZE
];
9412 FILE *fp
= fopen( file_name
, "rb" );
9415 fn_get_chapter_data fnc
= NULL
;
9416 if( fgets( buff
, CHAPTER_BUFSIZE
, fp
) != NULL
)
9418 if( strncmp( buff
, "CHAPTER", 7 ) == 0 )
9419 fnc
= isom_read_simple_chapter
;
9420 else if( isdigit( buff
[0] ) && isdigit( buff
[1] ) && buff
[2] == ':'
9421 && isdigit( buff
[3] ) && isdigit( buff
[4] ) && buff
[5] == ':' )
9422 fnc
= isom_read_minimum_chapter
;
9428 int lsmash_set_tyrant_chapter( lsmash_root_t
*root
, char *file_name
)
9430 /* This function should be called after updating of the latest movie duration. */
9431 if( !root
|| !root
->moov
|| !root
->moov
->mvhd
|| !root
->moov
->mvhd
->timescale
|| !root
->moov
->mvhd
->duration
)
9433 /* check each line format */
9434 fn_get_chapter_data fnc
= isom_check_chap_line( file_name
);
9437 FILE *chapter
= fopen( file_name
, "rb" );
9440 if( isom_add_udta( root
, 0 ) || isom_add_chpl( root
->moov
) )
9442 isom_chapter_entry_t data
;
9443 while( !fnc( chapter
, &data
) )
9445 data
.start_time
= (data
.start_time
+ 50) / 100; /* convert to 100ns unit */
9446 if( data
.start_time
/ 1e7
> (double)root
->moov
->mvhd
->duration
/ root
->moov
->mvhd
->timescale
9447 || isom_add_chpl_entry( root
->moov
->udta
->chpl
, &data
) )
9449 free( data
.chapter_name
);
9450 data
.chapter_name
= NULL
;
9455 if( data
.chapter_name
)
9456 free( data
.chapter_name
);
9461 int lsmash_create_reference_chapter_track( lsmash_root_t
*root
, uint32_t track_ID
, char *file_name
)
9463 if( !root
|| (!root
->qt_compatible
&& !root
->itunes_audio
) || !root
->moov
|| !root
->moov
->mvhd
)
9465 FILE *chapter
= NULL
; /* shut up 'uninitialized' warning */
9466 /* Create a Track Reference Box. */
9467 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
9468 if( !trak
|| isom_add_tref( trak
) )
9470 /* Create a track_ID for a new chapter track. */
9471 uint32_t *id
= (uint32_t *)malloc( sizeof(uint32_t) );
9474 uint32_t chapter_track_ID
= *id
= root
->moov
->mvhd
->next_track_ID
;
9475 /* Create a Track Reference Type Box. */
9476 isom_tref_type_t
*chap
= isom_add_track_reference_type( trak
->tref
, QT_TREF_TYPE_CHAP
, 1, id
);
9478 return -1; /* no need to free id */
9479 /* Create a reference chapter track. */
9480 if( chapter_track_ID
!= lsmash_create_track( root
, ISOM_MEDIA_HANDLER_TYPE_TEXT_TRACK
) )
9482 /* Set track parameters. */
9483 lsmash_track_parameters_t track_param
;
9484 lsmash_initialize_track_parameters( &track_param
);
9485 track_param
.mode
= ISOM_TRACK_IN_MOVIE
| ISOM_TRACK_IN_PREVIEW
;
9486 if( lsmash_set_track_parameters( root
, chapter_track_ID
, &track_param
) )
9488 /* Set media parameters. */
9489 uint64_t media_timescale
= lsmash_get_media_timescale( root
, track_ID
);
9490 if( !media_timescale
)
9492 lsmash_media_parameters_t media_param
;
9493 lsmash_initialize_media_parameters( &media_param
);
9494 media_param
.timescale
= media_timescale
;
9495 media_param
.ISO_language
= root
->max_3gpp_version
>= 6 || root
->itunes_audio
? ISOM_LANGUAGE_CODE_UNDEFINED
: 0;
9496 media_param
.MAC_language
= 0;
9497 if( lsmash_set_media_parameters( root
, chapter_track_ID
, &media_param
) )
9499 /* Create a sample description. */
9500 uint32_t sample_type
= root
->max_3gpp_version
>= 6 || root
->itunes_audio
? ISOM_CODEC_TYPE_TX3G_TEXT
: QT_CODEC_TYPE_TEXT_TEXT
;
9501 uint32_t sample_entry
= lsmash_add_sample_entry( root
, chapter_track_ID
, sample_type
, NULL
);
9504 /* Check each line format. */
9505 fn_get_chapter_data fnc
= isom_check_chap_line( file_name
);
9508 /* Open chapter format file. */
9509 chapter
= fopen( file_name
, "rb" );
9512 /* Parse the file and write text samples. */
9513 isom_chapter_entry_t data
;
9514 while( !fnc( chapter
, &data
) )
9516 /* set start_time */
9517 data
.start_time
= data
.start_time
* 1e-9 * media_timescale
+ 0.5;
9518 /* write a text sample here */
9519 uint16_t name_length
= strlen( data
.chapter_name
);
9520 lsmash_sample_t
*sample
= lsmash_create_sample( 2 + name_length
+ 12 * (sample_type
== QT_CODEC_TYPE_TEXT_TEXT
) );
9523 sample
->data
[0] = (name_length
>> 8) & 0xff;
9524 sample
->data
[1] = name_length
& 0xff;
9525 memcpy( sample
->data
+ 2, data
.chapter_name
, name_length
);
9526 if( sample_type
== QT_CODEC_TYPE_TEXT_TEXT
)
9528 /* QuickTime Player requires Text Encoding Attribute Box ('encd') if media language is ISO language codes : undefined.
9529 * Also this box can avoid garbling if the QuickTime text sample is encoded by Unicode characters.
9530 * Note: 3GPP Timed Text supports only UTF-8 or UTF-16, so this box isn't needed. */
9531 static const uint8_t encd
[12] =
9533 0x00, 0x00, 0x00, 0x0C, /* size: 12 */
9534 0x65, 0x6E, 0x63, 0x64, /* type: 'encd' */
9535 0x00, 0x00, 0x01, 0x00 /* Unicode Encoding */
9537 memcpy( sample
->data
+ 2 + name_length
, encd
, 12 );
9539 sample
->dts
= sample
->cts
= data
.start_time
;
9540 sample
->prop
.random_access_type
= ISOM_SAMPLE_RANDOM_ACCESS_TYPE_SYNC
;
9541 sample
->index
= sample_entry
;
9542 if( lsmash_append_sample( root
, chapter_track_ID
, sample
) )
9544 free( data
.chapter_name
);
9545 data
.chapter_name
= NULL
;
9547 if( lsmash_flush_pooled_samples( root
, chapter_track_ID
, 0 ) )
9549 trak
= isom_get_trak( root
, chapter_track_ID
);
9553 trak
->is_chapter
= 1;
9554 trak
->related_track_ID
= track_ID
;
9559 if( data
.chapter_name
)
9560 free( data
.chapter_name
);
9561 free( chap
->track_ID
);
9562 chap
->track_ID
= NULL
;
9563 /* Remove the reference chapter track attached at tail of the list. */
9564 lsmash_remove_entry_direct( root
->moov
->trak_list
, root
->moov
->trak_list
->tail
, isom_remove_trak
);
9568 int lsmash_delete_explicit_timeline_map( lsmash_root_t
*root
, uint32_t track_ID
)
9570 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
9573 isom_remove_edts( trak
->edts
);
9575 return isom_update_tkhd_duration( trak
);
9578 void lsmash_delete_tyrant_chapter( lsmash_root_t
*root
)
9580 if( !root
|| !root
->moov
|| !root
->moov
->udta
)
9582 isom_remove_chpl( root
->moov
->udta
->chpl
);
9583 root
->moov
->udta
->chpl
= NULL
;
9586 #ifdef LSMASH_DEMUXER_ENABLED
9587 /*---- remuxer functions ----*/
9589 static int isom_copy_mean( isom_metaitem_t
*dst
, isom_metaitem_t
*src
)
9593 isom_remove_mean( dst
->mean
);
9594 if( !src
|| !src
->mean
)
9596 if( isom_add_mean( dst
) )
9598 if( src
->mean
->meaning_string
)
9600 dst
->mean
->meaning_string
= lsmash_memdup( src
->mean
->meaning_string
, src
->mean
->meaning_string_length
);
9601 if( !dst
->mean
->meaning_string
)
9603 dst
->mean
->meaning_string_length
= src
->mean
->meaning_string_length
;
9608 static int isom_copy_name( isom_metaitem_t
*dst
, isom_metaitem_t
*src
)
9612 isom_remove_name( dst
->name
);
9613 if( !src
|| !src
->name
)
9615 if( isom_add_name( dst
) )
9617 if( src
->name
->name
)
9619 dst
->name
->name
= lsmash_memdup( src
->name
->name
, src
->name
->name_length
);
9620 if( !dst
->name
->name
)
9622 dst
->name
->name_length
= src
->name
->name_length
;
9627 static int isom_copy_data( isom_metaitem_t
*dst
, isom_metaitem_t
*src
)
9631 isom_remove_data( dst
->data
);
9632 if( !src
|| !src
->data
)
9634 if( isom_add_data( dst
) )
9636 isom_copy_fields( dst
, src
, data
);
9637 if( src
->data
->value
)
9639 dst
->data
->value
= lsmash_memdup( src
->data
->value
, src
->data
->value_length
);
9640 if( !dst
->data
->value
)
9642 dst
->data
->value_length
= src
->data
->value_length
;
9647 static isom_metaitem_t
*isom_duplicate_metaitem( isom_metaitem_t
*src
)
9649 isom_metaitem_t
*dst
= lsmash_memdup( src
, sizeof(isom_metaitem_t
) );
9655 /* Copy children. */
9656 if( isom_copy_mean( dst
, src
)
9657 || isom_copy_name( dst
, src
)
9658 || isom_copy_data( dst
, src
) )
9660 isom_remove_metaitem( dst
);
9666 lsmash_itunes_metadata_list_t
*lsmash_export_itunes_metadata( lsmash_root_t
*root
)
9668 if( !root
|| !root
->moov
)
9670 if( !root
->moov
->udta
|| !root
->moov
->udta
->meta
|| !root
->moov
->udta
->meta
->ilst
)
9672 isom_ilst_t
*dst
= malloc( sizeof(isom_ilst_t
) );
9675 memset( dst
, 0, sizeof(isom_ilst_t
) );
9676 return (lsmash_itunes_metadata_list_t
*)dst
;
9678 isom_ilst_t
*src
= root
->moov
->udta
->meta
->ilst
;
9679 isom_ilst_t
*dst
= lsmash_memdup( src
, sizeof(isom_ilst_t
) );
9684 dst
->item_list
= NULL
;
9685 if( src
->item_list
)
9687 dst
->item_list
= lsmash_create_entry_list();
9688 if( !dst
->item_list
)
9693 for( lsmash_entry_t
*entry
= src
->item_list
->head
; entry
; entry
= entry
->next
)
9695 isom_metaitem_t
*dst_metaitem
= isom_duplicate_metaitem( (isom_metaitem_t
*)entry
->data
);
9698 isom_remove_ilst( dst
);
9701 if( lsmash_add_entry( dst
->item_list
, dst_metaitem
) )
9703 isom_remove_metaitem( dst_metaitem
);
9704 isom_remove_ilst( dst
);
9709 return (lsmash_itunes_metadata_list_t
*)dst
;
9712 int lsmash_import_itunes_metadata( lsmash_root_t
*root
, lsmash_itunes_metadata_list_t
*list
)
9714 if( !root
|| !list
)
9716 if( !root
->itunes_movie
)
9718 isom_ilst_t
*src
= (isom_ilst_t
*)list
;
9719 if( !src
->item_list
|| !src
->item_list
->entry_count
)
9721 if( (!root
->moov
->udta
&& isom_add_udta( root
, 0 ))
9722 || (!root
->moov
->udta
->meta
&& isom_add_meta( (isom_box_t
*)root
->moov
->udta
))
9723 || (!root
->moov
->udta
->meta
->hdlr
&& isom_add_hdlr( NULL
, root
->moov
->udta
->meta
, NULL
, ISOM_META_HANDLER_TYPE_ITUNES_METADATA
))
9724 || (!root
->moov
->udta
->meta
->ilst
&& isom_add_ilst( root
->moov
)) )
9726 isom_ilst_t
*dst
= root
->moov
->udta
->meta
->ilst
;
9727 for( lsmash_entry_t
*entry
= src
->item_list
->head
; entry
; entry
= entry
->next
)
9729 isom_metaitem_t
*dst_metaitem
= isom_duplicate_metaitem( (isom_metaitem_t
*)entry
->data
);
9732 if( lsmash_add_entry( dst
->item_list
, dst_metaitem
) )
9734 isom_remove_metaitem( dst_metaitem
);
9741 void lsmash_destroy_itunes_metadata( lsmash_itunes_metadata_list_t
*list
)
9743 isom_remove_ilst( (isom_ilst_t
*)list
);
9745 #endif /* LSMASH_DEMUXER_ENABLED */