1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2010-2012 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 */
35 #include "description.h"
36 #ifdef LSMASH_DEMUXER_ENABLED
44 char *isom_4cc2str( uint32_t fourcc
)
47 str
[0] = (fourcc
>> 24) & 0xff;
48 str
[1] = (fourcc
>> 16) & 0xff;
49 str
[2] = (fourcc
>> 8) & 0xff;
50 str
[3] = fourcc
& 0xff;
55 isom_trak_entry_t
*isom_get_trak( lsmash_root_t
*root
, uint32_t track_ID
)
57 if( !track_ID
|| !root
|| !root
->moov
|| !root
->moov
->trak_list
)
59 for( lsmash_entry_t
*entry
= root
->moov
->trak_list
->head
; entry
; entry
= entry
->next
)
61 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)entry
->data
;
62 if( !trak
|| !trak
->tkhd
)
64 if( trak
->tkhd
->track_ID
== track_ID
)
70 isom_trex_entry_t
*isom_get_trex( isom_mvex_t
*mvex
, uint32_t track_ID
)
72 if( !track_ID
|| !mvex
|| !mvex
->trex_list
)
74 for( lsmash_entry_t
*entry
= mvex
->trex_list
->head
; entry
; entry
= entry
->next
)
76 isom_trex_entry_t
*trex
= (isom_trex_entry_t
*)entry
->data
;
79 if( trex
->track_ID
== track_ID
)
85 static isom_traf_entry_t
*isom_get_traf( isom_moof_entry_t
*moof
, uint32_t track_ID
)
87 if( !track_ID
|| !moof
|| !moof
->traf_list
)
89 for( lsmash_entry_t
*entry
= moof
->traf_list
->head
; entry
; entry
= entry
->next
)
91 isom_traf_entry_t
*traf
= (isom_traf_entry_t
*)entry
->data
;
92 if( !traf
|| !traf
->tfhd
)
94 if( traf
->tfhd
->track_ID
== track_ID
)
100 isom_tfra_entry_t
*isom_get_tfra( isom_mfra_t
*mfra
, uint32_t track_ID
)
102 if( !track_ID
|| !mfra
|| !mfra
->tfra_list
)
104 for( lsmash_entry_t
*entry
= mfra
->tfra_list
->head
; entry
; entry
= entry
->next
)
106 isom_tfra_entry_t
*tfra
= (isom_tfra_entry_t
*)entry
->data
;
109 if( tfra
->track_ID
== track_ID
)
115 static int isom_add_elst_entry( isom_elst_t
*elst
, uint64_t segment_duration
, int64_t media_time
, int32_t media_rate
)
117 isom_elst_entry_t
*data
= malloc( sizeof(isom_elst_entry_t
) );
120 data
->segment_duration
= segment_duration
;
121 data
->media_time
= media_time
;
122 data
->media_rate
= media_rate
;
123 if( lsmash_add_entry( elst
->list
, data
) )
128 if( data
->segment_duration
> UINT32_MAX
|| data
->media_time
> INT32_MAX
|| data
->media_time
< INT32_MIN
)
133 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
)
135 if( !tref
|| !tref
->ref_list
)
137 isom_tref_type_t
*ref
= lsmash_malloc_zero( sizeof(isom_tref_type_t
) );
140 /* Initialize common fields. */
141 ref
->root
= tref
->root
;
142 ref
->parent
= (isom_box_t
*)tref
;
144 ref
->type
= lsmash_form_iso_box_type( type
);
146 ref
->ref_count
= ref_count
;
147 ref
->track_ID
= track_ID
;
148 if( lsmash_add_entry( tref
->ref_list
, ref
) )
156 static int isom_add_dref_entry( isom_dref_t
*dref
, uint32_t flags
, char *name
, char *location
)
158 if( !dref
|| !dref
->list
)
160 isom_dref_entry_t
*data
= lsmash_malloc_zero( sizeof(isom_dref_entry_t
) );
163 isom_init_box_common( data
, dref
, name
? ISOM_BOX_TYPE_URN
: ISOM_BOX_TYPE_URL
);
167 data
->location_length
= strlen( location
) + 1;
168 data
->location
= lsmash_memdup( location
, data
->location_length
);
169 if( !data
->location
)
177 data
->name_length
= strlen( name
) + 1;
178 data
->name
= lsmash_memdup( name
, data
->name_length
);
182 free( data
->location
);
187 if( lsmash_add_entry( dref
->list
, data
) )
190 free( data
->location
);
199 isom_avcC_ps_entry_t
*isom_create_ps_entry( uint8_t *ps
, uint32_t ps_size
)
201 isom_avcC_ps_entry_t
*entry
= malloc( sizeof(isom_avcC_ps_entry_t
) );
204 entry
->parameterSetNALUnit
= lsmash_memdup( ps
, ps_size
);
205 if( !entry
->parameterSetNALUnit
)
210 entry
->parameterSetLength
= ps_size
;
214 void isom_remove_avcC_ps( isom_avcC_ps_entry_t
*ps
)
218 if( ps
->parameterSetNALUnit
)
219 free( ps
->parameterSetNALUnit
);
224 static int isom_add_mp4s_entry( isom_stsd_t
*stsd
)
226 if( !stsd
|| !stsd
->list
)
228 isom_mp4s_entry_t
*mp4s
= lsmash_malloc_zero( sizeof(isom_mp4s_entry_t
) );
231 isom_init_box_common( mp4s
, stsd
, ISOM_CODEC_TYPE_MP4S_SYSTEM
);
232 mp4s
->data_reference_index
= 1;
233 if( lsmash_add_entry( stsd
->list
, mp4s
) )
242 int isom_add_frma( isom_wave_t
*wave
)
244 if( !wave
|| wave
->frma
)
246 isom_create_box( frma
, wave
, QT_BOX_TYPE_FRMA
);
251 int isom_add_enda( isom_wave_t
*wave
)
253 if( !wave
|| wave
->enda
)
255 isom_create_box( enda
, wave
, QT_BOX_TYPE_ENDA
);
260 int isom_add_mp4a( isom_wave_t
*wave
)
262 if( !wave
|| wave
->mp4a
)
264 isom_create_box( mp4a
, wave
, QT_BOX_TYPE_MP4A
);
269 int isom_add_terminator( isom_wave_t
*wave
)
271 if( !wave
|| wave
->terminator
)
273 isom_create_box( terminator
, wave
, QT_BOX_TYPE_TERMINATOR
);
274 wave
->terminator
= terminator
;
278 static int isom_add_text_entry( isom_stsd_t
*stsd
)
280 if( !stsd
|| !stsd
->list
)
282 isom_text_entry_t
*text
= lsmash_malloc_zero( sizeof(isom_text_entry_t
) );
285 isom_init_box_common( text
, stsd
, QT_CODEC_TYPE_TEXT_TEXT
);
286 text
->data_reference_index
= 1;
287 if( lsmash_add_entry( stsd
->list
, text
) )
295 int isom_add_ftab( isom_tx3g_entry_t
*tx3g
)
299 isom_ftab_t
*ftab
= lsmash_malloc_zero( sizeof(isom_ftab_t
) );
302 isom_init_box_common( ftab
, tx3g
, ISOM_BOX_TYPE_FTAB
);
303 ftab
->list
= lsmash_create_entry_list();
313 static int isom_add_tx3g_entry( isom_stsd_t
*stsd
)
315 if( !stsd
|| !stsd
->list
)
317 isom_tx3g_entry_t
*tx3g
= lsmash_malloc_zero( sizeof(isom_tx3g_entry_t
) );
320 isom_init_box_common( tx3g
, stsd
, ISOM_CODEC_TYPE_TX3G_TEXT
);
321 tx3g
->data_reference_index
= 1;
322 if( isom_add_ftab( tx3g
) ||
323 lsmash_add_entry( stsd
->list
, tx3g
) )
331 /* This function returns 0 if failed, sample_entry_number if succeeded. */
332 int lsmash_add_sample_entry( lsmash_root_t
*root
, uint32_t track_ID
, void *summary
)
336 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
337 if( !trak
|| !trak
->root
|| !trak
->root
->ftyp
|| !trak
->mdia
|| !trak
->mdia
->minf
338 || !trak
->mdia
->minf
->stbl
|| !trak
->mdia
->minf
->stbl
->stsd
|| !trak
->mdia
->minf
->stbl
->stsd
->list
)
340 isom_stsd_t
*stsd
= trak
->mdia
->minf
->stbl
->stsd
;
341 lsmash_entry_list_t
*list
= stsd
->list
;
343 lsmash_codec_type_t sample_type
= ((lsmash_summary_t
*)summary
)->sample_type
;
344 if( lsmash_check_codec_type_identical( sample_type
, LSMASH_CODEC_TYPE_RAW
) )
346 if( trak
->mdia
->minf
->vmhd
)
347 ret
= isom_setup_visual_description( stsd
, sample_type
, (lsmash_video_summary_t
*)summary
);
348 else if( trak
->mdia
->minf
->smhd
)
349 ret
= isom_setup_audio_description( stsd
, sample_type
, (lsmash_audio_summary_t
*)summary
);
350 return ret
? 0 : list
->entry_count
;
352 static struct description_setup_table_tag
354 lsmash_codec_type_t type
;
356 } description_setup_table
[128] = { { LSMASH_CODEC_TYPE_INITIALIZER
, NULL
} };
357 if( !description_setup_table
[0].func
)
360 #define ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( type, func ) \
361 description_setup_table[i++] = (struct description_setup_table_tag){ type, func }
362 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVC1_VIDEO
, isom_setup_visual_description
);
364 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVC2_VIDEO
, isom_setup_visual_description
);
365 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVCP_VIDEO
, isom_setup_visual_description
);
366 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_SVC1_VIDEO
, isom_setup_visual_description
);
367 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_MVC1_VIDEO
, isom_setup_visual_description
);
368 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_MVC2_VIDEO
, isom_setup_visual_description
);
369 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_MP4V_VIDEO
, isom_setup_visual_description
);
370 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_DRAC_VIDEO
, isom_setup_visual_description
);
371 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_ENCV_VIDEO
, isom_setup_visual_description
);
372 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_MJP2_VIDEO
, isom_setup_visual_description
);
373 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_S263_VIDEO
, isom_setup_visual_description
);
375 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_VC_1_VIDEO
, isom_setup_visual_description
);
376 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_APCH_VIDEO
, isom_setup_visual_description
);
377 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_APCN_VIDEO
, isom_setup_visual_description
);
378 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_APCS_VIDEO
, isom_setup_visual_description
);
379 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_APCO_VIDEO
, isom_setup_visual_description
);
380 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_AP4H_VIDEO
, isom_setup_visual_description
);
381 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_DVC_VIDEO
, isom_setup_visual_description
);
382 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_DVCP_VIDEO
, isom_setup_visual_description
);
383 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_DVPP_VIDEO
, isom_setup_visual_description
);
384 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_DV5N_VIDEO
, isom_setup_visual_description
);
385 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_DV5P_VIDEO
, isom_setup_visual_description
);
386 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_DVH2_VIDEO
, isom_setup_visual_description
);
387 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_DVH3_VIDEO
, isom_setup_visual_description
);
388 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_DVH5_VIDEO
, isom_setup_visual_description
);
389 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_DVH6_VIDEO
, isom_setup_visual_description
);
390 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_DVHP_VIDEO
, isom_setup_visual_description
);
391 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_DVHQ_VIDEO
, isom_setup_visual_description
);
392 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_ULRA_VIDEO
, isom_setup_visual_description
);
393 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_ULRG_VIDEO
, isom_setup_visual_description
);
394 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_ULY2_VIDEO
, isom_setup_visual_description
);
395 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_ULY0_VIDEO
, isom_setup_visual_description
);
396 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_V210_VIDEO
, isom_setup_visual_description
);
397 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_V216_VIDEO
, isom_setup_visual_description
);
398 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_V308_VIDEO
, isom_setup_visual_description
);
399 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_V408_VIDEO
, isom_setup_visual_description
);
400 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_V410_VIDEO
, isom_setup_visual_description
);
401 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_YUV2_VIDEO
, isom_setup_visual_description
);
402 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_MP4A_AUDIO
, isom_setup_audio_description
);
403 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_AC_3_AUDIO
, isom_setup_audio_description
);
404 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_ALAC_AUDIO
, isom_setup_audio_description
);
405 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_EC_3_AUDIO
, isom_setup_audio_description
);
406 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_SAMR_AUDIO
, isom_setup_audio_description
);
407 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_SAWB_AUDIO
, isom_setup_audio_description
);
408 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSC_AUDIO
, isom_setup_audio_description
);
409 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSE_AUDIO
, isom_setup_audio_description
);
410 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSH_AUDIO
, isom_setup_audio_description
);
411 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSL_AUDIO
, isom_setup_audio_description
);
413 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_DRA1_AUDIO
, isom_setup_audio_description
);
414 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_ENCA_AUDIO
, isom_setup_audio_description
);
415 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_G719_AUDIO
, isom_setup_audio_description
);
416 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_G726_AUDIO
, isom_setup_audio_description
);
417 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_M4AE_AUDIO
, isom_setup_audio_description
);
418 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_MLPA_AUDIO
, isom_setup_audio_description
);
419 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_RAW_AUDIO
, isom_setup_audio_description
);
420 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_SAWP_AUDIO
, isom_setup_audio_description
);
421 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_SEVC_AUDIO
, isom_setup_audio_description
);
422 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_SQCP_AUDIO
, isom_setup_audio_description
);
423 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_SSMV_AUDIO
, isom_setup_audio_description
);
424 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_TWOS_AUDIO
, isom_setup_audio_description
);
426 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_MP4A_AUDIO
, isom_setup_audio_description
);
427 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_23NI_AUDIO
, isom_setup_audio_description
);
428 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_NONE_AUDIO
, isom_setup_audio_description
);
429 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_LPCM_AUDIO
, isom_setup_audio_description
);
430 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_SOWT_AUDIO
, isom_setup_audio_description
);
431 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_TWOS_AUDIO
, isom_setup_audio_description
);
432 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_FL32_AUDIO
, isom_setup_audio_description
);
433 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_FL64_AUDIO
, isom_setup_audio_description
);
434 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_IN24_AUDIO
, isom_setup_audio_description
);
435 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_IN32_AUDIO
, isom_setup_audio_description
);
436 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_NOT_SPECIFIED
, isom_setup_audio_description
);
437 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_TX3G_TEXT
, isom_add_tx3g_entry
);
438 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( QT_CODEC_TYPE_TEXT_TEXT
, isom_add_text_entry
);
440 ADD_DESCRIPTION_SETUP_TABLE_ELEMENT( ISOM_CODEC_TYPE_MP4S_SYSTEM
, isom_add_mp4s_entry
);
443 for( int i
= 0; description_setup_table
[i
].func
; i
++ )
444 if( lsmash_check_codec_type_identical( sample_type
, description_setup_table
[i
].type
) )
446 if( isom_setup_visual_description
== description_setup_table
[i
].func
)
447 ret
= isom_setup_visual_description( stsd
, sample_type
, (lsmash_video_summary_t
*)summary
);
448 else if( isom_setup_audio_description
== description_setup_table
[i
].func
)
449 ret
= isom_setup_audio_description( stsd
, sample_type
, (lsmash_audio_summary_t
*)summary
);
450 else if( isom_add_tx3g_entry
== description_setup_table
[i
].func
)
451 ret
= isom_add_tx3g_entry( stsd
);
452 else if( isom_add_text_entry
== description_setup_table
[i
].func
)
453 ret
= isom_add_text_entry( stsd
);
456 return ret
? 0 : list
->entry_count
;
459 static int isom_add_stts_entry( isom_stbl_t
*stbl
, uint32_t sample_delta
)
461 if( !stbl
|| !stbl
->stts
|| !stbl
->stts
->list
)
463 isom_stts_entry_t
*data
= malloc( sizeof(isom_stts_entry_t
) );
466 data
->sample_count
= 1;
467 data
->sample_delta
= sample_delta
;
468 if( lsmash_add_entry( stbl
->stts
->list
, data
) )
476 static int isom_add_ctts_entry( isom_stbl_t
*stbl
, uint32_t sample_offset
)
478 if( !stbl
|| !stbl
->ctts
|| !stbl
->ctts
->list
)
480 isom_ctts_entry_t
*data
= malloc( sizeof(isom_ctts_entry_t
) );
483 data
->sample_count
= 1;
484 data
->sample_offset
= sample_offset
;
485 if( lsmash_add_entry( stbl
->ctts
->list
, data
) )
493 static int isom_add_stsc_entry( isom_stbl_t
*stbl
, uint32_t first_chunk
, uint32_t samples_per_chunk
, uint32_t sample_description_index
)
495 if( !stbl
|| !stbl
->stsc
|| !stbl
->stsc
->list
)
497 isom_stsc_entry_t
*data
= malloc( sizeof(isom_stsc_entry_t
) );
500 data
->first_chunk
= first_chunk
;
501 data
->samples_per_chunk
= samples_per_chunk
;
502 data
->sample_description_index
= sample_description_index
;
503 if( lsmash_add_entry( stbl
->stsc
->list
, data
) )
511 static int isom_add_stsz_entry( isom_stbl_t
*stbl
, uint32_t entry_size
)
513 if( !stbl
|| !stbl
->stsz
)
515 isom_stsz_t
*stsz
= stbl
->stsz
;
516 /* retrieve initial sample_size */
517 if( !stsz
->sample_count
)
518 stsz
->sample_size
= entry_size
;
519 /* if it seems constant access_unit size at present, update sample_count only */
520 if( !stsz
->list
&& stsz
->sample_size
== entry_size
)
522 ++ stsz
->sample_count
;
525 /* found sample_size varies, create sample_size list */
528 stsz
->list
= lsmash_create_entry_list();
531 for( uint32_t i
= 0; i
< stsz
->sample_count
; i
++ )
533 isom_stsz_entry_t
*data
= malloc( sizeof(isom_stsz_entry_t
) );
536 data
->entry_size
= stsz
->sample_size
;
537 if( lsmash_add_entry( stsz
->list
, data
) )
543 stsz
->sample_size
= 0;
545 isom_stsz_entry_t
*data
= malloc( sizeof(isom_stsz_entry_t
) );
548 data
->entry_size
= entry_size
;
549 if( lsmash_add_entry( stsz
->list
, data
) )
554 ++ stsz
->sample_count
;
558 static int isom_add_stss_entry( isom_stbl_t
*stbl
, uint32_t sample_number
)
560 if( !stbl
|| !stbl
->stss
|| !stbl
->stss
->list
)
562 isom_stss_entry_t
*data
= malloc( sizeof(isom_stss_entry_t
) );
565 data
->sample_number
= sample_number
;
566 if( lsmash_add_entry( stbl
->stss
->list
, data
) )
574 static int isom_add_stps_entry( isom_stbl_t
*stbl
, uint32_t sample_number
)
576 if( !stbl
|| !stbl
->stps
|| !stbl
->stps
->list
)
578 isom_stps_entry_t
*data
= malloc( sizeof(isom_stps_entry_t
) );
581 data
->sample_number
= sample_number
;
582 if( lsmash_add_entry( stbl
->stps
->list
, data
) )
590 static int isom_add_sdtp_entry( isom_box_t
*parent
, lsmash_sample_property_t
*prop
, uint8_t avc_extensions
)
592 if( !prop
|| !parent
)
594 isom_sdtp_t
*sdtp
= NULL
;
595 if( lsmash_check_box_type_identical( parent
->type
, ISOM_BOX_TYPE_STBL
) )
596 sdtp
= ((isom_stbl_t
*)parent
)->sdtp
;
597 else if( lsmash_check_box_type_identical( parent
->type
, ISOM_BOX_TYPE_TRAF
) )
598 sdtp
= ((isom_traf_entry_t
*)parent
)->sdtp
;
601 if( !sdtp
|| !sdtp
->list
)
603 isom_sdtp_entry_t
*data
= malloc( sizeof(isom_sdtp_entry_t
) );
606 /* isom_sdtp_entry_t is smaller than lsmash_sample_property_t. */
607 data
->is_leading
= (avc_extensions
? prop
->leading
: prop
->allow_earlier
) & 0x03;
608 data
->sample_depends_on
= prop
->independent
& 0x03;
609 data
->sample_is_depended_on
= prop
->disposable
& 0x03;
610 data
->sample_has_redundancy
= prop
->redundant
& 0x03;
611 if( lsmash_add_entry( sdtp
->list
, data
) )
619 static int isom_add_co64( isom_stbl_t
*stbl
)
621 if( !stbl
|| stbl
->stco
)
623 isom_create_list_box( stco
, stbl
, ISOM_BOX_TYPE_CO64
);
624 stco
->large_presentation
= 1;
629 static int isom_add_stco( isom_stbl_t
*stbl
)
631 if( !stbl
|| stbl
->stco
)
633 isom_create_list_box( stco
, stbl
, ISOM_BOX_TYPE_STCO
);
634 stco
->large_presentation
= 0;
639 static int isom_add_co64_entry( isom_stbl_t
*stbl
, uint64_t chunk_offset
)
641 if( !stbl
|| !stbl
->stco
|| !stbl
->stco
->list
)
643 isom_co64_entry_t
*data
= malloc( sizeof(isom_co64_entry_t
) );
646 data
->chunk_offset
= chunk_offset
;
647 if( lsmash_add_entry( stbl
->stco
->list
, data
) )
655 static int isom_convert_stco_to_co64( isom_stbl_t
* stbl
)
658 isom_stco_t
*stco
= stbl
->stco
;
660 if( isom_add_co64( stbl
) )
662 /* move chunk_offset to co64 from stco */
663 for( lsmash_entry_t
*entry
= stco
->list
->head
; entry
; entry
= entry
->next
)
665 isom_stco_entry_t
*data
= (isom_stco_entry_t
*)entry
->data
;
666 if( isom_add_co64_entry( stbl
, data
->chunk_offset
) )
669 lsmash_remove_list( stco
->list
, NULL
);
674 static int isom_add_stco_entry( isom_stbl_t
*stbl
, uint64_t chunk_offset
)
676 if( !stbl
|| !stbl
->stco
|| !stbl
->stco
->list
)
678 if( stbl
->stco
->large_presentation
)
679 return isom_add_co64_entry( stbl
, chunk_offset
);
680 if( chunk_offset
> UINT32_MAX
)
682 if( isom_convert_stco_to_co64( stbl
) )
684 return isom_add_co64_entry( stbl
, chunk_offset
);
686 isom_stco_entry_t
*data
= malloc( sizeof(isom_stco_entry_t
) );
689 data
->chunk_offset
= (uint32_t)chunk_offset
;
690 if( lsmash_add_entry( stbl
->stco
->list
, data
) )
698 isom_sgpd_entry_t
*isom_get_sample_group_description( isom_stbl_t
*stbl
, uint32_t grouping_type
)
700 if( !stbl
->sgpd_list
)
702 for( lsmash_entry_t
*entry
= stbl
->sgpd_list
->head
; entry
; entry
= entry
->next
)
704 isom_sgpd_entry_t
*sgpd
= (isom_sgpd_entry_t
*)entry
->data
;
705 if( !sgpd
|| !sgpd
->list
)
707 if( sgpd
->grouping_type
== grouping_type
)
713 isom_sbgp_entry_t
*isom_get_sample_to_group( isom_stbl_t
*stbl
, uint32_t grouping_type
)
715 if( !stbl
->sbgp_list
)
717 for( lsmash_entry_t
*entry
= stbl
->sbgp_list
->head
; entry
; entry
= entry
->next
)
719 isom_sbgp_entry_t
*sbgp
= (isom_sbgp_entry_t
*)entry
->data
;
720 if( !sbgp
|| !sbgp
->list
)
722 if( sbgp
->grouping_type
== grouping_type
)
728 static isom_rap_entry_t
*isom_add_rap_group_entry( isom_sgpd_entry_t
*sgpd
)
732 isom_rap_entry_t
*data
= malloc( sizeof(isom_rap_entry_t
) );
735 data
->description_length
= 0;
736 data
->num_leading_samples_known
= 0;
737 data
->num_leading_samples
= 0;
738 if( lsmash_add_entry( sgpd
->list
, data
) )
746 static isom_roll_entry_t
*isom_add_roll_group_entry( isom_sgpd_entry_t
*sgpd
, int16_t roll_distance
)
750 isom_roll_entry_t
*data
= malloc( sizeof(isom_roll_entry_t
) );
753 data
->description_length
= 0;
754 data
->roll_distance
= roll_distance
;
755 if( lsmash_add_entry( sgpd
->list
, data
) )
763 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
)
767 isom_group_assignment_entry_t
*data
= malloc( sizeof(isom_group_assignment_entry_t
) );
770 data
->sample_count
= sample_count
;
771 data
->group_description_index
= group_description_index
;
772 if( lsmash_add_entry( sbgp
->list
, data
) )
780 int isom_add_chpl_entry( isom_chpl_t
*chpl
, isom_chapter_entry_t
*chap_data
)
782 if( !chap_data
->chapter_name
|| !chpl
|| !chpl
->list
)
784 isom_chpl_entry_t
*data
= malloc( sizeof(isom_chpl_entry_t
) );
787 data
->start_time
= chap_data
->start_time
;
788 data
->chapter_name_length
= strlen( chap_data
->chapter_name
);
789 data
->chapter_name
= (char *)malloc( data
->chapter_name_length
+ 1 );
790 if( !data
->chapter_name
)
795 memcpy( data
->chapter_name
, chap_data
->chapter_name
, data
->chapter_name_length
);
796 data
->chapter_name
[data
->chapter_name_length
] = '\0';
797 if( lsmash_add_entry( chpl
->list
, data
) )
799 free( data
->chapter_name
);
806 static isom_trex_entry_t
*isom_add_trex( isom_mvex_t
*mvex
)
810 if( !mvex
->trex_list
)
812 mvex
->trex_list
= lsmash_create_entry_list();
813 if( !mvex
->trex_list
)
816 isom_trex_entry_t
*trex
= lsmash_malloc_zero( sizeof(isom_trex_entry_t
) );
819 isom_init_box_common( trex
, mvex
, ISOM_BOX_TYPE_TREX
);
820 if( lsmash_add_entry( mvex
->trex_list
, trex
) )
828 static isom_trun_entry_t
*isom_add_trun( isom_traf_entry_t
*traf
)
832 if( !traf
->trun_list
)
834 traf
->trun_list
= lsmash_create_entry_list();
835 if( !traf
->trun_list
)
838 isom_trun_entry_t
*trun
= lsmash_malloc_zero( sizeof(isom_trun_entry_t
) );
841 isom_init_box_common( trun
, traf
, ISOM_BOX_TYPE_TRUN
);
842 if( lsmash_add_entry( traf
->trun_list
, trun
) )
850 static isom_traf_entry_t
*isom_add_traf( lsmash_root_t
*root
, isom_moof_entry_t
*moof
)
852 if( !root
|| !root
->moof_list
|| !moof
)
854 if( !moof
->traf_list
)
856 moof
->traf_list
= lsmash_create_entry_list();
857 if( !moof
->traf_list
)
860 isom_traf_entry_t
*traf
= lsmash_malloc_zero( sizeof(isom_traf_entry_t
) );
863 isom_init_box_common( traf
, moof
, ISOM_BOX_TYPE_TRAF
);
864 isom_cache_t
*cache
= malloc( sizeof(isom_cache_t
) );
870 memset( cache
, 0, sizeof(isom_cache_t
) );
871 if( lsmash_add_entry( moof
->traf_list
, traf
) )
881 static isom_moof_entry_t
*isom_add_moof( lsmash_root_t
*root
)
885 if( !root
->moof_list
)
887 root
->moof_list
= lsmash_create_entry_list();
888 if( !root
->moof_list
)
891 isom_moof_entry_t
*moof
= lsmash_malloc_zero( sizeof(isom_moof_entry_t
) );
894 isom_init_box_common( moof
, root
, ISOM_BOX_TYPE_MOOF
);
895 if( lsmash_add_entry( root
->moof_list
, moof
) )
903 static isom_tfra_entry_t
*isom_add_tfra( isom_mfra_t
*mfra
)
907 if( !mfra
->tfra_list
)
909 mfra
->tfra_list
= lsmash_create_entry_list();
910 if( !mfra
->tfra_list
)
913 isom_tfra_entry_t
*tfra
= lsmash_malloc_zero( sizeof(isom_tfra_entry_t
) );
916 isom_init_box_common( tfra
, mfra
, ISOM_BOX_TYPE_TFRA
);
917 if( lsmash_add_entry( mfra
->tfra_list
, tfra
) )
925 static int isom_add_ftyp( lsmash_root_t
*root
)
929 isom_create_box( ftyp
, root
, ISOM_BOX_TYPE_FTYP
);
930 ftyp
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 8;
935 static int isom_add_moov( lsmash_root_t
*root
)
939 isom_create_box( moov
, root
, ISOM_BOX_TYPE_MOOV
);
944 static int isom_add_mvhd( isom_moov_t
*moov
)
946 if( !moov
|| moov
->mvhd
)
948 isom_create_box( mvhd
, moov
, ISOM_BOX_TYPE_MVHD
);
949 mvhd
->rate
= 0x00010000;
950 mvhd
->volume
= 0x0100;
951 mvhd
->matrix
[0] = 0x00010000;
952 mvhd
->matrix
[4] = 0x00010000;
953 mvhd
->matrix
[8] = 0x40000000;
954 mvhd
->next_track_ID
= 1;
959 static int isom_scan_trak_profileLevelIndication( isom_trak_entry_t
*trak
, mp4a_audioProfileLevelIndication
*audio_pli
, mp4sys_visualProfileLevelIndication
*visual_pli
)
961 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
)
963 isom_stsd_t
*stsd
= trak
->mdia
->minf
->stbl
->stsd
;
964 if( !stsd
|| !stsd
->list
|| !stsd
->list
->head
)
966 for( lsmash_entry_t
*entry
= stsd
->list
->head
; entry
; entry
= entry
->next
)
968 isom_sample_entry_t
*sample_entry
= (isom_sample_entry_t
*)entry
->data
;
971 lsmash_codec_type_t sample_type
= (lsmash_codec_type_t
)sample_entry
->type
;
972 if( trak
->mdia
->minf
->vmhd
)
974 if( lsmash_check_codec_type_identical( sample_type
, ISOM_CODEC_TYPE_AVC1_VIDEO
)
975 || lsmash_check_codec_type_identical( sample_type
, ISOM_CODEC_TYPE_AVC2_VIDEO
)
976 || lsmash_check_codec_type_identical( sample_type
, ISOM_CODEC_TYPE_AVCP_VIDEO
)
977 || lsmash_check_codec_type_identical( sample_type
, ISOM_CODEC_TYPE_SVC1_VIDEO
)
978 || lsmash_check_codec_type_identical( sample_type
, ISOM_CODEC_TYPE_MVC1_VIDEO
)
979 || lsmash_check_codec_type_identical( sample_type
, ISOM_CODEC_TYPE_MVC2_VIDEO
) )
981 /* FIXME: Do we have to arbitrate like audio? */
982 if( *visual_pli
== MP4SYS_VISUAL_PLI_NONE_REQUIRED
)
983 *visual_pli
= MP4SYS_VISUAL_PLI_H264_AVC
;
986 *visual_pli
= MP4SYS_VISUAL_PLI_NOT_SPECIFIED
;
988 else if( trak
->mdia
->minf
->smhd
)
990 if( lsmash_check_codec_type_identical( sample_type
, ISOM_CODEC_TYPE_MP4A_AUDIO
) )
992 isom_audio_entry_t
*audio
= (isom_audio_entry_t
*)sample_entry
;
993 #ifdef LSMASH_DEMUXER_ENABLED
994 isom_esds_t
*esds
= (isom_esds_t
*)isom_get_extension_box( &audio
->extensions
, ISOM_BOX_TYPE_ESDS
);
995 if( !esds
|| !esds
->ES
)
997 if( !lsmash_check_codec_type_identical( audio
->summary
.sample_type
, ISOM_CODEC_TYPE_MP4A_AUDIO
) )
998 /* This is needed when copying descriptions. */
999 mp4sys_setup_summary_from_DecoderSpecificInfo( &audio
->summary
, esds
->ES
);
1001 *audio_pli
= mp4a_max_audioProfileLevelIndication( *audio_pli
, mp4a_get_audioProfileLevelIndication( &audio
->summary
) );
1004 /* NOTE: Audio CODECs other than 'mp4a' does not have appropriate pli. */
1005 *audio_pli
= MP4A_AUDIO_PLI_NOT_SPECIFIED
;
1008 ; /* FIXME: Do we have to set OD_profileLevelIndication? */
1013 static int isom_add_iods( isom_moov_t
*moov
)
1015 if( !moov
|| !moov
->trak_list
|| moov
->iods
)
1017 isom_create_box( iods
, moov
, ISOM_BOX_TYPE_IODS
);
1018 iods
->OD
= mp4sys_create_ObjectDescriptor( 1 ); /* NOTE: Use 1 for ObjectDescriptorID of IOD. */
1024 mp4a_audioProfileLevelIndication audio_pli
= MP4A_AUDIO_PLI_NONE_REQUIRED
;
1025 mp4sys_visualProfileLevelIndication visual_pli
= MP4SYS_VISUAL_PLI_NONE_REQUIRED
;
1026 for( lsmash_entry_t
*entry
= moov
->trak_list
->head
; entry
; entry
= entry
->next
)
1028 isom_trak_entry_t
* trak
= (isom_trak_entry_t
*)entry
->data
;
1029 if( !trak
|| !trak
->tkhd
)
1034 if( isom_scan_trak_profileLevelIndication( trak
, &audio_pli
, &visual_pli
) )
1039 if( mp4sys_add_ES_ID_Inc( iods
->OD
, trak
->tkhd
->track_ID
) )
1045 if( mp4sys_to_InitialObjectDescriptor( iods
->OD
,
1046 0, /* FIXME: I'm not quite sure what the spec says. */
1047 MP4SYS_OD_PLI_NONE_REQUIRED
, MP4SYS_SCENE_PLI_NONE_REQUIRED
,
1048 audio_pli
, visual_pli
,
1049 MP4SYS_GRAPHICS_PLI_NONE_REQUIRED
) )
1058 static int isom_add_tkhd( isom_trak_entry_t
*trak
, uint32_t handler_type
)
1060 if( !trak
|| !trak
->root
|| !trak
->root
->moov
|| !trak
->root
->moov
->mvhd
|| !trak
->root
->moov
->trak_list
)
1064 isom_create_box( tkhd
, trak
, ISOM_BOX_TYPE_TKHD
);
1065 if( handler_type
== ISOM_MEDIA_HANDLER_TYPE_AUDIO_TRACK
)
1066 tkhd
->volume
= 0x0100;
1067 tkhd
->matrix
[0] = 0x00010000;
1068 tkhd
->matrix
[4] = 0x00010000;
1069 tkhd
->matrix
[8] = 0x40000000;
1070 tkhd
->duration
= 0xffffffff;
1071 tkhd
->track_ID
= trak
->root
->moov
->mvhd
->next_track_ID
;
1072 ++ trak
->root
->moov
->mvhd
->next_track_ID
;
1078 static int isom_add_clef( isom_tapt_t
*tapt
)
1082 isom_create_box( clef
, tapt
, QT_BOX_TYPE_CLEF
);
1087 static int isom_add_prof( isom_tapt_t
*tapt
)
1091 isom_create_box( prof
, tapt
, QT_BOX_TYPE_PROF
);
1096 static int isom_add_enof( isom_tapt_t
*tapt
)
1100 isom_create_box( enof
, tapt
, QT_BOX_TYPE_ENOF
);
1105 static int isom_add_tapt( isom_trak_entry_t
*trak
)
1109 isom_create_box( tapt
, trak
, QT_BOX_TYPE_TAPT
);
1114 int isom_add_elst( isom_edts_t
*edts
)
1118 isom_create_list_box( elst
, edts
, ISOM_BOX_TYPE_ELST
);
1123 int isom_add_edts( isom_trak_entry_t
*trak
)
1127 isom_create_box( edts
, trak
, ISOM_BOX_TYPE_EDTS
);
1132 int isom_add_tref( isom_trak_entry_t
*trak
)
1136 isom_create_box( tref
, trak
, ISOM_BOX_TYPE_TREF
);
1137 tref
->ref_list
= lsmash_create_entry_list();
1138 if( !tref
->ref_list
)
1147 static int isom_add_mdhd( isom_mdia_t
*mdia
, uint16_t default_language
)
1149 if( !mdia
|| mdia
->mdhd
)
1151 isom_create_box( mdhd
, mdia
, ISOM_BOX_TYPE_MDHD
);
1152 mdhd
->language
= default_language
;
1157 static int isom_add_mdia( isom_trak_entry_t
*trak
)
1159 if( !trak
|| trak
->mdia
)
1161 isom_create_box( mdia
, trak
, ISOM_BOX_TYPE_MDIA
);
1166 int isom_add_hdlr( isom_mdia_t
*mdia
, isom_meta_t
*meta
, isom_minf_t
*minf
, uint32_t media_type
)
1168 if( (!mdia
&& !meta
&& !minf
) || (mdia
&& meta
) || (meta
&& minf
) || (minf
&& mdia
) )
1169 return -1; /* Either one must be given. */
1170 if( (mdia
&& mdia
->hdlr
) || (meta
&& meta
->hdlr
) || (minf
&& minf
->hdlr
) )
1171 return -1; /* Selected one must not have hdlr yet. */
1172 isom_box_t
*parent
= mdia
? (isom_box_t
*)mdia
: meta
? (isom_box_t
*)meta
: (isom_box_t
*)minf
;
1173 isom_create_box( hdlr
, parent
, ISOM_BOX_TYPE_HDLR
);
1174 lsmash_root_t
*root
= hdlr
->root
;
1175 uint32_t type
= mdia
? (root
->qt_compatible
? QT_HANDLER_TYPE_MEDIA
: 0) : (meta
? 0 : QT_HANDLER_TYPE_DATA
);
1176 uint32_t subtype
= media_type
;
1177 hdlr
->componentType
= type
;
1178 hdlr
->componentSubtype
= subtype
;
1179 char *type_name
= NULL
;
1180 char *subtype_name
= NULL
;
1181 uint8_t type_name_length
= 0;
1182 uint8_t subtype_name_length
= 0;
1184 type_name
= "Media ";
1186 type_name
= "Metadata ";
1187 else /* if( minf ) */
1188 type_name
= "Data ";
1189 type_name_length
= strlen( type_name
);
1194 uint8_t subtype_name_length
;
1197 { ISOM_MEDIA_HANDLER_TYPE_AUDIO_TRACK
, "Sound ", 6 },
1198 { ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK
, "Video", 6 },
1199 { ISOM_MEDIA_HANDLER_TYPE_HINT_TRACK
, "Hint ", 5 },
1200 { ISOM_MEDIA_HANDLER_TYPE_TIMED_METADATA_TRACK
, "Metadata ", 9 },
1201 { ISOM_MEDIA_HANDLER_TYPE_TEXT_TRACK
, "Text ", 5 },
1202 { ISOM_META_HANDLER_TYPE_ITUNES_METADATA
, "iTunes ", 7 },
1203 { QT_REFERENCE_HANDLER_TYPE_ALIAS
, "Alias ", 6 },
1204 { QT_REFERENCE_HANDLER_TYPE_RESOURCE
, "Resource ", 9 },
1205 { QT_REFERENCE_HANDLER_TYPE_URL
, "URL ", 4 },
1206 { subtype
, "Unknown ", 8 }
1208 for( int i
= 0; subtype_table
[i
].subtype
; i
++ )
1209 if( subtype
== subtype_table
[i
].subtype
)
1211 subtype_name
= subtype_table
[i
].subtype_name
;
1212 subtype_name_length
= subtype_table
[i
].subtype_name_length
;
1215 uint32_t name_length
= 15 + subtype_name_length
+ type_name_length
+ root
->isom_compatible
+ root
->qt_compatible
;
1216 uint8_t *name
= malloc( name_length
);
1222 if( root
->qt_compatible
)
1223 name
[0] = name_length
& 0xff;
1224 memcpy( name
+ root
->qt_compatible
, "L-SMASH ", 8 );
1225 memcpy( name
+ root
->qt_compatible
+ 8, subtype_name
, subtype_name_length
);
1226 memcpy( name
+ root
->qt_compatible
+ 8 + subtype_name_length
, type_name
, type_name_length
);
1227 memcpy( name
+ root
->qt_compatible
+ 8 + subtype_name_length
+ type_name_length
, "Handler", 7 );
1228 if( root
->isom_compatible
)
1229 name
[name_length
- 1] = 0;
1230 hdlr
->componentName
= name
;
1231 hdlr
->componentName_length
= name_length
;
1241 static int isom_add_minf( isom_mdia_t
*mdia
)
1243 if( !mdia
|| mdia
->minf
)
1245 isom_create_box( minf
, mdia
, ISOM_BOX_TYPE_MINF
);
1250 static int isom_add_vmhd( isom_minf_t
*minf
)
1252 if( !minf
|| minf
->vmhd
)
1254 isom_create_box( vmhd
, minf
, ISOM_BOX_TYPE_VMHD
);
1255 vmhd
->flags
= 0x000001;
1260 static int isom_add_smhd( isom_minf_t
*minf
)
1262 if( !minf
|| minf
->smhd
)
1264 isom_create_box( smhd
, minf
, ISOM_BOX_TYPE_SMHD
);
1269 static int isom_add_hmhd( isom_minf_t
*minf
)
1271 if( !minf
|| minf
->hmhd
)
1273 isom_create_box( hmhd
, minf
, ISOM_BOX_TYPE_HMHD
);
1278 static int isom_add_nmhd( isom_minf_t
*minf
)
1280 if( !minf
|| minf
->nmhd
)
1282 isom_create_box( nmhd
, minf
, ISOM_BOX_TYPE_NMHD
);
1287 static int isom_add_gmin( isom_gmhd_t
*gmhd
)
1289 if( !gmhd
|| gmhd
->gmin
)
1291 isom_create_box( gmin
, gmhd
, QT_BOX_TYPE_GMIN
);
1296 static int isom_add_text( isom_gmhd_t
*gmhd
)
1298 if( !gmhd
|| gmhd
->text
)
1300 isom_create_box( text
, gmhd
, QT_BOX_TYPE_TEXT
);
1301 text
->matrix
[0] = 0x00010000;
1302 text
->matrix
[4] = 0x00010000;
1303 text
->matrix
[8] = 0x40000000;
1308 static int isom_add_gmhd( isom_minf_t
*minf
)
1310 if( !minf
|| minf
->gmhd
)
1312 isom_create_box( gmhd
, minf
, QT_BOX_TYPE_GMHD
);
1317 static int isom_add_dinf( isom_minf_t
*minf
)
1319 if( !minf
|| minf
->dinf
)
1321 isom_create_box( dinf
, minf
, ISOM_BOX_TYPE_DINF
);
1326 static int isom_add_dref( isom_dinf_t
*dinf
)
1328 if( !dinf
|| dinf
->dref
)
1330 isom_create_list_box( dref
, dinf
, ISOM_BOX_TYPE_DREF
);
1332 if( isom_add_dref_entry( dref
, 0x000001, NULL
, NULL
) )
1337 static int isom_add_stsd( isom_stbl_t
*stbl
)
1339 if( !stbl
|| stbl
->stsd
)
1341 isom_create_list_box( stsd
, stbl
, ISOM_BOX_TYPE_STSD
);
1346 static int isom_add_stts( isom_stbl_t
*stbl
)
1348 if( !stbl
|| stbl
->stts
)
1350 isom_create_list_box( stts
, stbl
, ISOM_BOX_TYPE_STTS
);
1355 static int isom_add_ctts( isom_stbl_t
*stbl
)
1357 if( !stbl
|| stbl
->ctts
)
1359 isom_create_list_box( ctts
, stbl
, ISOM_BOX_TYPE_CTTS
);
1364 static int isom_add_cslg( isom_stbl_t
*stbl
)
1366 if( !stbl
|| stbl
->cslg
)
1368 isom_create_box( cslg
, stbl
, ISOM_BOX_TYPE_CSLG
);
1373 static int isom_add_stsc( isom_stbl_t
*stbl
)
1375 if( !stbl
|| stbl
->stsc
)
1377 isom_create_list_box( stsc
, stbl
, ISOM_BOX_TYPE_STSC
);
1382 static int isom_add_stsz( isom_stbl_t
*stbl
)
1384 if( !stbl
|| stbl
->stsz
)
1386 isom_create_box( stsz
, stbl
, ISOM_BOX_TYPE_STSZ
); /* We don't create a list here. */
1391 static int isom_add_stss( isom_stbl_t
*stbl
)
1393 if( !stbl
|| stbl
->stss
)
1395 isom_create_list_box( stss
, stbl
, ISOM_BOX_TYPE_STSS
);
1400 static int isom_add_stps( isom_stbl_t
*stbl
)
1402 if( !stbl
|| stbl
->stps
)
1404 isom_create_list_box( stps
, stbl
, QT_BOX_TYPE_STPS
);
1409 static int isom_add_sdtp( isom_box_t
*parent
)
1413 if( lsmash_check_box_type_identical( parent
->type
, ISOM_BOX_TYPE_STBL
) )
1415 isom_stbl_t
*stbl
= (isom_stbl_t
*)parent
;
1418 isom_create_list_box( sdtp
, stbl
, ISOM_BOX_TYPE_SDTP
);
1421 else if( lsmash_check_box_type_identical( parent
->type
, ISOM_BOX_TYPE_TRAF
) )
1423 isom_traf_entry_t
*traf
= (isom_traf_entry_t
*)parent
;
1426 isom_create_list_box( sdtp
, traf
, ISOM_BOX_TYPE_SDTP
);
1434 static isom_sgpd_entry_t
*isom_add_sgpd( isom_stbl_t
*stbl
, uint32_t grouping_type
)
1438 if( !stbl
->sgpd_list
)
1440 stbl
->sgpd_list
= lsmash_create_entry_list();
1441 if( !stbl
->sgpd_list
)
1444 isom_sgpd_entry_t
*sgpd
= lsmash_malloc_zero( sizeof(isom_sgpd_entry_t
) );
1447 isom_init_box_common( sgpd
, stbl
, ISOM_BOX_TYPE_SGPD
);
1448 sgpd
->list
= lsmash_create_entry_list();
1449 if( !sgpd
->list
|| lsmash_add_entry( stbl
->sgpd_list
, sgpd
) )
1454 sgpd
->grouping_type
= grouping_type
;
1455 sgpd
->version
= 1; /* We use version 1 because it is recommended in the spec. */
1456 switch( grouping_type
)
1458 case ISOM_GROUP_TYPE_RAP
:
1459 sgpd
->default_length
= 1;
1461 case ISOM_GROUP_TYPE_ROLL
:
1462 sgpd
->default_length
= 2;
1465 /* We don't consider other grouping types currently. */
1471 static isom_sbgp_entry_t
*isom_add_sbgp( isom_stbl_t
*stbl
, uint32_t grouping_type
)
1475 if( !stbl
->sbgp_list
)
1477 stbl
->sbgp_list
= lsmash_create_entry_list();
1478 if( !stbl
->sbgp_list
)
1481 isom_sbgp_entry_t
*sbgp
= lsmash_malloc_zero( sizeof(isom_sbgp_entry_t
) );
1484 isom_init_box_common( sbgp
, stbl
, ISOM_BOX_TYPE_SBGP
);
1485 sbgp
->list
= lsmash_create_entry_list();
1486 if( !sbgp
->list
|| lsmash_add_entry( stbl
->sbgp_list
, sbgp
) )
1491 sbgp
->grouping_type
= grouping_type
;
1495 static int isom_add_stbl( isom_minf_t
*minf
)
1497 if( !minf
|| minf
->stbl
)
1499 isom_create_box( stbl
, minf
, ISOM_BOX_TYPE_STBL
);
1504 int isom_add_chpl( isom_moov_t
*moov
)
1506 if( !moov
|| !moov
->udta
|| moov
->udta
->chpl
)
1508 isom_create_list_box( chpl
, moov
->udta
, ISOM_BOX_TYPE_CHPL
);
1509 chpl
->version
= 1; /* version = 1 is popular. */
1510 moov
->udta
->chpl
= chpl
;
1514 int isom_add_metaitem( isom_ilst_t
*ilst
, lsmash_itunes_metadata_item item
)
1516 if( !ilst
|| !ilst
->item_list
)
1518 lsmash_box_type_t type
= lsmash_form_iso_box_type( item
);
1519 isom_create_box( metaitem
, ilst
, type
);
1520 if( lsmash_add_entry( ilst
->item_list
, metaitem
) )
1528 int isom_add_mean( isom_metaitem_t
*metaitem
)
1530 if( !metaitem
|| metaitem
->mean
)
1532 isom_create_box( mean
, metaitem
, ISOM_BOX_TYPE_MEAN
);
1533 metaitem
->mean
= mean
;
1537 int isom_add_name( isom_metaitem_t
*metaitem
)
1539 if( !metaitem
|| metaitem
->name
)
1541 isom_create_box( name
, metaitem
, ISOM_BOX_TYPE_NAME
);
1542 metaitem
->name
= name
;
1546 int isom_add_data( isom_metaitem_t
*metaitem
)
1548 if( !metaitem
|| metaitem
->data
)
1550 isom_create_box( data
, metaitem
, ISOM_BOX_TYPE_DATA
);
1551 metaitem
->data
= data
;
1555 int isom_add_ilst( isom_moov_t
*moov
)
1557 if( !moov
|| !moov
->udta
|| !moov
->udta
->meta
|| moov
->udta
->meta
->ilst
)
1559 isom_create_box( ilst
, moov
->udta
->meta
, ISOM_BOX_TYPE_ILST
);
1560 ilst
->item_list
= lsmash_create_entry_list();
1561 if( !ilst
->item_list
)
1566 moov
->udta
->meta
->ilst
= ilst
;
1570 int isom_add_meta( isom_box_t
*parent
)
1574 isom_create_box( meta
, parent
, ISOM_BOX_TYPE_META
);
1575 if( lsmash_check_box_type_identical( parent
->type
, LSMASH_BOX_TYPE_UNSPECIFIED
) )
1577 lsmash_root_t
*root
= (lsmash_root_t
*)parent
;
1585 else if( lsmash_check_box_type_identical( parent
->type
, ISOM_BOX_TYPE_MOOV
) )
1587 isom_moov_t
*moov
= (isom_moov_t
*)parent
;
1595 else if( lsmash_check_box_type_identical( parent
->type
, ISOM_BOX_TYPE_TRAK
) )
1597 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)parent
;
1607 isom_udta_t
*udta
= (isom_udta_t
*)parent
;
1618 static int isom_add_cprt( isom_udta_t
*udta
)
1622 if( !udta
->cprt_list
)
1624 udta
->cprt_list
= lsmash_create_entry_list();
1625 if( !udta
->cprt_list
)
1628 isom_create_box( cprt
, udta
, ISOM_BOX_TYPE_CPRT
);
1629 if( lsmash_add_entry( udta
->cprt_list
, cprt
) )
1637 int isom_add_udta( lsmash_root_t
*root
, uint32_t track_ID
)
1639 /* track_ID == 0 means the direct addition to moov box */
1642 if( !root
|| !root
->moov
)
1644 if( root
->moov
->udta
)
1646 isom_create_box( udta
, root
->moov
, ISOM_BOX_TYPE_UDTA
);
1647 root
->moov
->udta
= udta
;
1650 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
1655 isom_create_box( udta
, trak
, ISOM_BOX_TYPE_UDTA
);
1660 static isom_trak_entry_t
*isom_add_trak( lsmash_root_t
*root
)
1662 if( !root
|| !root
->moov
)
1664 isom_moov_t
*moov
= root
->moov
;
1665 if( !moov
->trak_list
)
1667 moov
->trak_list
= lsmash_create_entry_list();
1668 if( !moov
->trak_list
)
1671 isom_trak_entry_t
*trak
= lsmash_malloc_zero( sizeof(isom_trak_entry_t
) );
1674 isom_init_box_common( trak
, moov
, ISOM_BOX_TYPE_TRAK
);
1675 isom_cache_t
*cache
= lsmash_malloc_zero( sizeof(isom_cache_t
) );
1681 isom_fragment_t
*fragment
= NULL
;
1682 if( root
->fragment
)
1684 fragment
= lsmash_malloc_zero( sizeof(isom_fragment_t
) );
1691 cache
->fragment
= fragment
;
1693 if( lsmash_add_entry( moov
->trak_list
, trak
) )
1701 trak
->cache
= cache
;
1705 static int isom_add_mvex( isom_moov_t
*moov
)
1707 if( !moov
|| moov
->mvex
)
1709 isom_create_box( mvex
, moov
, ISOM_BOX_TYPE_MVEX
);
1714 static int isom_add_mehd( isom_mvex_t
*mvex
)
1716 if( !mvex
|| mvex
->mehd
)
1718 isom_create_box( mehd
, mvex
, ISOM_BOX_TYPE_MEHD
);
1723 static int isom_add_tfhd( isom_traf_entry_t
*traf
)
1725 if( !traf
|| traf
->tfhd
)
1727 isom_create_box( tfhd
, traf
, ISOM_BOX_TYPE_TFHD
);
1732 static int isom_add_tfdt( isom_traf_entry_t
*traf
)
1734 if( !traf
|| traf
->tfdt
)
1736 isom_create_box( tfdt
, traf
, ISOM_BOX_TYPE_TFDT
);
1741 static int isom_add_mfhd( isom_moof_entry_t
*moof
)
1743 if( !moof
|| moof
->mfhd
)
1745 isom_create_box( mfhd
, moof
, ISOM_BOX_TYPE_MFHD
);
1750 static int isom_add_mfra( lsmash_root_t
*root
)
1752 if( !root
|| root
->mfra
)
1754 isom_create_box( mfra
, root
, ISOM_BOX_TYPE_MFRA
);
1759 static int isom_add_mfro( isom_mfra_t
*mfra
)
1761 if( !mfra
|| mfra
->mfro
)
1763 isom_create_box( mfro
, mfra
, ISOM_BOX_TYPE_MFRO
);
1768 #define isom_remove_box( box_name, parent_type ) \
1771 parent_type *parent = (parent_type *)box_name->parent; \
1774 parent->box_name = NULL; \
1777 void isom_remove_unknown_box( isom_unknown_box_t
*unknown_box
)
1781 if( unknown_box
->unknown_field
)
1782 free( unknown_box
->unknown_field
);
1783 free( unknown_box
);
1786 static void isom_remove_ftyp( isom_ftyp_t
*ftyp
)
1790 if( ftyp
->compatible_brands
)
1791 free( ftyp
->compatible_brands
);
1792 isom_remove_box( ftyp
, lsmash_root_t
);
1795 static void isom_remove_tkhd( isom_tkhd_t
*tkhd
)
1799 isom_remove_box( tkhd
, isom_trak_entry_t
);
1802 static void isom_remove_clef( isom_clef_t
*clef
)
1806 isom_remove_box( clef
, isom_tapt_t
);
1809 static void isom_remove_prof( isom_prof_t
*prof
)
1813 isom_remove_box( prof
, isom_tapt_t
);
1816 static void isom_remove_enof( isom_enof_t
*enof
)
1820 isom_remove_box( enof
, isom_tapt_t
);
1823 void isom_remove_tapt( isom_tapt_t
*tapt
)
1827 isom_remove_clef( tapt
->clef
);
1828 isom_remove_prof( tapt
->prof
);
1829 isom_remove_enof( tapt
->enof
);
1830 isom_remove_box( tapt
, isom_trak_entry_t
);
1833 static void isom_remove_elst( isom_elst_t
*elst
)
1837 lsmash_remove_list( elst
->list
, NULL
);
1838 isom_remove_box( elst
, isom_edts_t
);
1841 static void isom_remove_edts( isom_edts_t
*edts
)
1845 isom_remove_elst( edts
->elst
);
1846 isom_remove_box( edts
, isom_trak_entry_t
);
1849 void isom_remove_track_reference_type( isom_tref_type_t
*ref
)
1854 free( ref
->track_ID
);
1858 void isom_remove_tref( isom_tref_t
*tref
)
1862 lsmash_remove_list( tref
->ref_list
, isom_remove_track_reference_type
);
1863 isom_remove_box( tref
, isom_trak_entry_t
);
1866 static void isom_remove_mdhd( isom_mdhd_t
*mdhd
)
1870 isom_remove_box( mdhd
, isom_mdia_t
);
1873 static void isom_remove_vmhd( isom_vmhd_t
*vmhd
)
1877 isom_remove_box( vmhd
, isom_minf_t
);
1880 static void isom_remove_smhd( isom_smhd_t
*smhd
)
1884 isom_remove_box( smhd
, isom_minf_t
);
1887 static void isom_remove_hmhd( isom_hmhd_t
*hmhd
)
1891 isom_remove_box( hmhd
, isom_minf_t
);
1894 static void isom_remove_nmhd( isom_nmhd_t
*nmhd
)
1898 isom_remove_box( nmhd
, isom_minf_t
);
1901 static void isom_remove_gmin( isom_gmin_t
*gmin
)
1905 isom_remove_box( gmin
, isom_gmhd_t
);
1908 static void isom_remove_text( isom_text_t
*text
)
1912 isom_remove_box( text
, isom_gmhd_t
);
1915 static void isom_remove_gmhd( isom_gmhd_t
*gmhd
)
1919 isom_remove_gmin( gmhd
->gmin
);
1920 isom_remove_text( gmhd
->text
);
1921 isom_remove_box( gmhd
, isom_minf_t
);
1924 static void isom_remove_hdlr( isom_hdlr_t
*hdlr
)
1928 if( hdlr
->componentName
)
1929 free( hdlr
->componentName
);
1932 if( lsmash_check_box_type_identical( hdlr
->parent
->type
, ISOM_BOX_TYPE_MDIA
) )
1933 isom_remove_box( hdlr
, isom_mdia_t
);
1934 else if( lsmash_check_box_type_identical( hdlr
->parent
->type
, ISOM_BOX_TYPE_META
)
1935 || lsmash_check_box_type_identical( hdlr
->parent
->type
, QT_BOX_TYPE_META
) )
1936 isom_remove_box( hdlr
, isom_meta_t
);
1937 else if( lsmash_check_box_type_identical( hdlr
->parent
->type
, ISOM_BOX_TYPE_MINF
) )
1938 isom_remove_box( hdlr
, isom_minf_t
);
1946 void isom_remove_clap( isom_clap_t
*clap
)
1953 void isom_remove_pasp( isom_pasp_t
*pasp
)
1960 void isom_remove_glbl( isom_glbl_t
*glbl
)
1964 if( glbl
->header_data
)
1965 free( glbl
->header_data
);
1969 void isom_remove_colr( isom_colr_t
*colr
)
1976 void isom_remove_gama( isom_gama_t
*gama
)
1983 void isom_remove_fiel( isom_fiel_t
*fiel
)
1990 void isom_remove_cspc( isom_cspc_t
*cspc
)
1997 void isom_remove_sgbt( isom_sgbt_t
*sgbt
)
2004 void isom_remove_stsl( isom_stsl_t
*stsl
)
2011 void isom_remove_esds( isom_esds_t
*esds
)
2015 mp4sys_remove_ES_Descriptor( esds
->ES
);
2019 void isom_remove_avcC( isom_avcC_t
*avcC
)
2023 lsmash_remove_list( avcC
->sequenceParameterSets
, isom_remove_avcC_ps
);
2024 lsmash_remove_list( avcC
->pictureParameterSets
, isom_remove_avcC_ps
);
2025 lsmash_remove_list( avcC
->sequenceParameterSetExt
, isom_remove_avcC_ps
);
2029 void isom_remove_btrt( isom_btrt_t
*btrt
)
2036 static void isom_remove_font_record( isom_font_record_t
*font_record
)
2040 if( font_record
->font_name
)
2041 free( font_record
->font_name
);
2042 free( font_record
);
2045 void isom_remove_ftab( isom_ftab_t
*ftab
)
2049 lsmash_remove_list( ftab
->list
, isom_remove_font_record
);
2050 isom_remove_box( ftab
, isom_tx3g_entry_t
);
2053 void isom_remove_frma( isom_frma_t
*frma
)
2057 isom_remove_box( frma
, isom_wave_t
);
2060 void isom_remove_enda( isom_enda_t
*enda
)
2064 isom_remove_box( enda
, isom_wave_t
);
2067 void isom_remove_mp4a( isom_mp4a_t
*mp4a
)
2071 isom_remove_box( mp4a
, isom_wave_t
);
2074 void isom_remove_terminator( isom_terminator_t
*terminator
)
2078 isom_remove_box( terminator
, isom_wave_t
);
2081 void isom_remove_wave( isom_wave_t
*wave
)
2085 isom_remove_frma( wave
->frma
);
2086 isom_remove_enda( wave
->enda
);
2087 isom_remove_mp4a( wave
->mp4a
);
2088 isom_remove_terminator( wave
->terminator
);
2092 void isom_remove_chan( isom_chan_t
*chan
)
2096 if( chan
->channelDescriptions
)
2097 free( chan
->channelDescriptions
);
2101 static void isom_remove_visual_description( isom_sample_entry_t
*description
)
2103 isom_visual_entry_t
*visual
= (isom_visual_entry_t
*)description
;
2104 isom_remove_sample_description_extensions( &visual
->extensions
);
2105 if( visual
->color_table
.array
)
2106 free( visual
->color_table
.array
);
2110 static void isom_remove_audio_description( isom_sample_entry_t
*description
)
2112 isom_audio_entry_t
*audio
= (isom_audio_entry_t
*)description
;
2113 isom_remove_sample_description_extensions( &audio
->extensions
);
2117 static void isom_remove_hint_description( isom_sample_entry_t
*description
)
2119 isom_hint_entry_t
*hint
= (isom_hint_entry_t
*)description
;
2120 isom_remove_sample_description_extensions( &hint
->extensions
);
2126 static void isom_remove_metadata_description( isom_sample_entry_t
*description
)
2128 isom_metadata_entry_t
*metadata
= (isom_metadata_entry_t
*)description
;
2129 isom_remove_sample_description_extensions( &metadata
->extensions
);
2133 static void isom_remove_tx3g_description( isom_sample_entry_t
*description
)
2135 isom_tx3g_entry_t
*tx3g
= (isom_tx3g_entry_t
*)description
;
2136 isom_remove_sample_description_extensions( &tx3g
->extensions
);
2138 isom_remove_ftab( tx3g
->ftab
);
2142 static void isom_remove_qt_text_description( isom_sample_entry_t
*description
)
2144 isom_text_entry_t
*text
= (isom_text_entry_t
*)description
;
2145 isom_remove_sample_description_extensions( &text
->extensions
);
2146 if( text
->font_name
)
2147 free( text
->font_name
);
2151 static void isom_remove_mp4s_description( isom_sample_entry_t
*description
)
2153 isom_mp4s_entry_t
*mp4s
= (isom_mp4s_entry_t
*)description
;
2154 isom_remove_sample_description_extensions( &mp4s
->extensions
);
2158 void isom_remove_sample_description( isom_sample_entry_t
*sample
)
2162 lsmash_codec_type_t sample_type
= sample
->type
;
2163 if( lsmash_check_box_type_identical( sample_type
, LSMASH_CODEC_TYPE_RAW
) )
2165 if( sample
->manager
& LSMASH_VIDEO_DESCRIPTION
)
2167 isom_remove_visual_description( sample
);
2170 else if( sample
->manager
& LSMASH_AUDIO_DESCRIPTION
)
2172 isom_remove_audio_description( sample
);
2176 static struct description_remover_table_tag
2178 lsmash_codec_type_t type
;
2179 void (*func
)( isom_sample_entry_t
* );
2180 } description_remover_table
[128] = { { LSMASH_CODEC_TYPE_INITIALIZER
, NULL
} };
2181 if( !description_remover_table
[0].func
)
2183 /* Initialize the table. */
2185 #define ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( type, func ) \
2186 description_remover_table[i++] = (struct description_remover_table_tag){ type, func }
2187 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVC1_VIDEO
, isom_remove_visual_description
);
2188 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVC2_VIDEO
, isom_remove_visual_description
);
2189 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVCP_VIDEO
, isom_remove_visual_description
);
2190 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SVC1_VIDEO
, isom_remove_visual_description
);
2191 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MVC1_VIDEO
, isom_remove_visual_description
);
2192 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MVC2_VIDEO
, isom_remove_visual_description
);
2193 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MP4V_VIDEO
, isom_remove_visual_description
);
2194 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DRAC_VIDEO
, isom_remove_visual_description
);
2195 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_ENCV_VIDEO
, isom_remove_visual_description
);
2196 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MJP2_VIDEO
, isom_remove_visual_description
);
2197 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_S263_VIDEO
, isom_remove_visual_description
);
2198 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_VC_1_VIDEO
, isom_remove_visual_description
);
2199 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_CFHD_VIDEO
, isom_remove_visual_description
);
2200 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DV10_VIDEO
, isom_remove_visual_description
);
2201 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVOO_VIDEO
, isom_remove_visual_description
);
2202 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVOR_VIDEO
, isom_remove_visual_description
);
2203 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVTV_VIDEO
, isom_remove_visual_description
);
2204 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVVT_VIDEO
, isom_remove_visual_description
);
2205 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_HD10_VIDEO
, isom_remove_visual_description
);
2206 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_M105_VIDEO
, isom_remove_visual_description
);
2207 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_PNTG_VIDEO
, isom_remove_visual_description
);
2208 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SVQ1_VIDEO
, isom_remove_visual_description
);
2209 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SVQ3_VIDEO
, isom_remove_visual_description
);
2210 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR0_VIDEO
, isom_remove_visual_description
);
2211 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR1_VIDEO
, isom_remove_visual_description
);
2212 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR2_VIDEO
, isom_remove_visual_description
);
2213 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR3_VIDEO
, isom_remove_visual_description
);
2214 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SHR4_VIDEO
, isom_remove_visual_description
);
2215 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_WRLE_VIDEO
, isom_remove_visual_description
);
2216 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_APCH_VIDEO
, isom_remove_visual_description
);
2217 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_APCN_VIDEO
, isom_remove_visual_description
);
2218 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_APCS_VIDEO
, isom_remove_visual_description
);
2219 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_APCO_VIDEO
, isom_remove_visual_description
);
2220 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_AP4H_VIDEO
, isom_remove_visual_description
);
2221 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_CIVD_VIDEO
, isom_remove_visual_description
);
2222 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DRAC_VIDEO
, isom_remove_visual_description
);
2223 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVC_VIDEO
, isom_remove_visual_description
);
2224 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVCP_VIDEO
, isom_remove_visual_description
);
2225 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVPP_VIDEO
, isom_remove_visual_description
);
2226 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DV5N_VIDEO
, isom_remove_visual_description
);
2227 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DV5P_VIDEO
, isom_remove_visual_description
);
2228 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVH2_VIDEO
, isom_remove_visual_description
);
2229 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVH3_VIDEO
, isom_remove_visual_description
);
2230 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVH5_VIDEO
, isom_remove_visual_description
);
2231 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVH6_VIDEO
, isom_remove_visual_description
);
2232 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVHP_VIDEO
, isom_remove_visual_description
);
2233 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_DVHQ_VIDEO
, isom_remove_visual_description
);
2234 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_FLIC_VIDEO
, isom_remove_visual_description
);
2235 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_GIF_VIDEO
, isom_remove_visual_description
);
2236 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_H261_VIDEO
, isom_remove_visual_description
);
2237 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_H263_VIDEO
, isom_remove_visual_description
);
2238 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_JPEG_VIDEO
, isom_remove_visual_description
);
2239 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_MJPA_VIDEO
, isom_remove_visual_description
);
2240 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_MJPB_VIDEO
, isom_remove_visual_description
);
2241 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_PNG_VIDEO
, isom_remove_visual_description
);
2242 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_RLE_VIDEO
, isom_remove_visual_description
);
2243 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_RPZA_VIDEO
, isom_remove_visual_description
);
2244 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_TGA_VIDEO
, isom_remove_visual_description
);
2245 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_TIFF_VIDEO
, isom_remove_visual_description
);
2246 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULRA_VIDEO
, isom_remove_visual_description
);
2247 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULRG_VIDEO
, isom_remove_visual_description
);
2248 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULY2_VIDEO
, isom_remove_visual_description
);
2249 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_ULY0_VIDEO
, isom_remove_visual_description
);
2250 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V210_VIDEO
, isom_remove_visual_description
);
2251 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V216_VIDEO
, isom_remove_visual_description
);
2252 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V308_VIDEO
, isom_remove_visual_description
);
2253 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V408_VIDEO
, isom_remove_visual_description
);
2254 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_V410_VIDEO
, isom_remove_visual_description
);
2255 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_YUV2_VIDEO
, isom_remove_visual_description
);
2256 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MP4A_AUDIO
, isom_remove_audio_description
);
2257 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_AC_3_AUDIO
, isom_remove_audio_description
);
2258 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_ALAC_AUDIO
, isom_remove_audio_description
);
2259 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSC_AUDIO
, isom_remove_audio_description
);
2260 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSE_AUDIO
, isom_remove_audio_description
);
2261 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSH_AUDIO
, isom_remove_audio_description
);
2262 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSL_AUDIO
, isom_remove_audio_description
);
2263 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_EC_3_AUDIO
, isom_remove_audio_description
);
2264 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SAMR_AUDIO
, isom_remove_audio_description
);
2265 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SAWB_AUDIO
, isom_remove_audio_description
);
2266 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_23NI_AUDIO
, isom_remove_audio_description
);
2267 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_NONE_AUDIO
, isom_remove_audio_description
);
2268 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_LPCM_AUDIO
, isom_remove_audio_description
);
2269 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_SOWT_AUDIO
, isom_remove_audio_description
);
2270 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_TWOS_AUDIO
, isom_remove_audio_description
);
2271 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_FL32_AUDIO
, isom_remove_audio_description
);
2272 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_FL64_AUDIO
, isom_remove_audio_description
);
2273 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_IN24_AUDIO
, isom_remove_audio_description
);
2274 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_IN32_AUDIO
, isom_remove_audio_description
);
2275 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_NOT_SPECIFIED
, isom_remove_audio_description
);
2276 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_DRA1_AUDIO
, isom_remove_audio_description
);
2277 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_ENCA_AUDIO
, isom_remove_audio_description
);
2278 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_G719_AUDIO
, isom_remove_audio_description
);
2279 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_G726_AUDIO
, isom_remove_audio_description
);
2280 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_M4AE_AUDIO
, isom_remove_audio_description
);
2281 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MLPA_AUDIO
, isom_remove_audio_description
);
2282 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SAWP_AUDIO
, isom_remove_audio_description
);
2283 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SEVC_AUDIO
, isom_remove_audio_description
);
2284 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SQCP_AUDIO
, isom_remove_audio_description
);
2285 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SSMV_AUDIO
, isom_remove_audio_description
);
2286 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_TWOS_AUDIO
, isom_remove_audio_description
);
2287 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_FDP_HINT
, isom_remove_hint_description
);
2288 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_M2TS_HINT
, isom_remove_hint_description
);
2289 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_PM2T_HINT
, isom_remove_hint_description
);
2290 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_PRTP_HINT
, isom_remove_hint_description
);
2291 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_RM2T_HINT
, isom_remove_hint_description
);
2292 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_RRTP_HINT
, isom_remove_hint_description
);
2293 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_RSRP_HINT
, isom_remove_hint_description
);
2294 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_RTP_HINT
, isom_remove_hint_description
);
2295 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SM2T_HINT
, isom_remove_hint_description
);
2296 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SRTP_HINT
, isom_remove_hint_description
);
2297 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_IXSE_META
, isom_remove_metadata_description
);
2298 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_METT_META
, isom_remove_metadata_description
);
2299 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_METX_META
, isom_remove_metadata_description
);
2300 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MLIX_META
, isom_remove_metadata_description
);
2301 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_OKSD_META
, isom_remove_metadata_description
);
2302 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_SVCM_META
, isom_remove_metadata_description
);
2303 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_TEXT_META
, isom_remove_metadata_description
);
2304 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_URIM_META
, isom_remove_metadata_description
);
2305 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_XML_META
, isom_remove_metadata_description
);
2306 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_TX3G_TEXT
, isom_remove_tx3g_description
);
2307 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( QT_CODEC_TYPE_TEXT_TEXT
, isom_remove_qt_text_description
);
2308 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( ISOM_CODEC_TYPE_MP4S_SYSTEM
, isom_remove_mp4s_description
);
2309 ADD_DESCRIPTION_REMOVER_TABLE_ELEMENT( LSMASH_CODEC_TYPE_UNSPECIFIED
, NULL
);
2311 for( int i
= 0; description_remover_table
[i
].func
; i
++ )
2312 if( lsmash_check_codec_type_identical( sample_type
, description_remover_table
[i
].type
) )
2314 description_remover_table
[i
].func( sample
);
2319 static void isom_remove_stsd( isom_stsd_t
*stsd
)
2323 lsmash_remove_list( stsd
->list
, isom_remove_sample_description
);
2324 isom_remove_box( stsd
, isom_stbl_t
);
2327 static void isom_remove_stts( isom_stts_t
*stts
)
2331 lsmash_remove_list( stts
->list
, NULL
);
2332 isom_remove_box( stts
, isom_stbl_t
);
2335 static void isom_remove_ctts( isom_ctts_t
*ctts
)
2339 lsmash_remove_list( ctts
->list
, NULL
);
2340 isom_remove_box( ctts
, isom_stbl_t
);
2343 static void isom_remove_cslg( isom_cslg_t
*cslg
)
2347 isom_remove_box( cslg
, isom_stbl_t
);
2350 static void isom_remove_stsc( isom_stsc_t
*stsc
)
2354 lsmash_remove_list( stsc
->list
, NULL
);
2355 isom_remove_box( stsc
, isom_stbl_t
);
2358 static void isom_remove_stsz( isom_stsz_t
*stsz
)
2362 lsmash_remove_list( stsz
->list
, NULL
);
2363 isom_remove_box( stsz
, isom_stbl_t
);
2366 static void isom_remove_stss( isom_stss_t
*stss
)
2370 lsmash_remove_list( stss
->list
, NULL
);
2371 isom_remove_box( stss
, isom_stbl_t
);
2374 static void isom_remove_stps( isom_stps_t
*stps
)
2378 lsmash_remove_list( stps
->list
, NULL
);
2379 isom_remove_box( stps
, isom_stbl_t
);
2382 static void isom_remove_sdtp( isom_sdtp_t
*sdtp
)
2386 lsmash_remove_list( sdtp
->list
, NULL
);
2389 if( lsmash_check_box_type_identical( sdtp
->parent
->type
, ISOM_BOX_TYPE_STBL
) )
2390 isom_remove_box( sdtp
, isom_stbl_t
);
2391 else if( lsmash_check_box_type_identical( sdtp
->parent
->type
, ISOM_BOX_TYPE_TRAF
) )
2392 isom_remove_box( sdtp
, isom_traf_entry_t
);
2400 static void isom_remove_stco( isom_stco_t
*stco
)
2404 lsmash_remove_list( stco
->list
, NULL
);
2405 isom_remove_box( stco
, isom_stbl_t
);
2408 static void isom_remove_sgpd( isom_sgpd_entry_t
*sgpd
)
2412 lsmash_remove_list( sgpd
->list
, NULL
);
2416 static void isom_remove_sbgp( isom_sbgp_entry_t
*sbgp
)
2420 lsmash_remove_list( sbgp
->list
, NULL
);
2424 static void isom_remove_stbl( isom_stbl_t
*stbl
)
2428 isom_remove_stsd( stbl
->stsd
);
2429 isom_remove_stts( stbl
->stts
);
2430 isom_remove_ctts( stbl
->ctts
);
2431 isom_remove_cslg( stbl
->cslg
);
2432 isom_remove_stsc( stbl
->stsc
);
2433 isom_remove_stsz( stbl
->stsz
);
2434 isom_remove_stss( stbl
->stss
);
2435 isom_remove_stps( stbl
->stps
);
2436 isom_remove_sdtp( stbl
->sdtp
);
2437 isom_remove_stco( stbl
->stco
);
2438 lsmash_remove_list( stbl
->sgpd_list
, isom_remove_sgpd
);
2439 lsmash_remove_list( stbl
->sbgp_list
, isom_remove_sbgp
);
2440 isom_remove_box( stbl
, isom_minf_t
);
2443 static void isom_remove_dref( isom_dref_t
*dref
)
2452 for( lsmash_entry_t
*entry
= dref
->list
->head
; entry
; )
2454 isom_dref_entry_t
*data
= (isom_dref_entry_t
*)entry
->data
;
2459 if( data
->location
)
2460 free( data
->location
);
2463 lsmash_entry_t
*next
= entry
->next
;
2468 isom_remove_box( dref
, isom_dinf_t
);
2471 static void isom_remove_dinf( isom_dinf_t
*dinf
)
2475 isom_remove_dref( dinf
->dref
);
2476 isom_remove_box( dinf
, isom_minf_t
);
2479 static void isom_remove_minf( isom_minf_t
*minf
)
2483 isom_remove_vmhd( minf
->vmhd
);
2484 isom_remove_smhd( minf
->smhd
);
2485 isom_remove_hmhd( minf
->hmhd
);
2486 isom_remove_nmhd( minf
->nmhd
);
2487 isom_remove_gmhd( minf
->gmhd
);
2488 isom_remove_hdlr( minf
->hdlr
);
2489 isom_remove_dinf( minf
->dinf
);
2490 isom_remove_stbl( minf
->stbl
);
2491 isom_remove_box( minf
, isom_mdia_t
);
2494 static void isom_remove_mdia( isom_mdia_t
*mdia
)
2498 isom_remove_mdhd( mdia
->mdhd
);
2499 isom_remove_minf( mdia
->minf
);
2500 isom_remove_hdlr( mdia
->hdlr
);
2501 isom_remove_box( mdia
, isom_trak_entry_t
);
2504 static void isom_remove_chpl( isom_chpl_t
*chpl
)
2513 for( lsmash_entry_t
*entry
= chpl
->list
->head
; entry
; )
2515 isom_chpl_entry_t
*data
= (isom_chpl_entry_t
*)entry
->data
;
2518 if( data
->chapter_name
)
2519 free( data
->chapter_name
);
2522 lsmash_entry_t
*next
= entry
->next
;
2527 isom_remove_box( chpl
, isom_udta_t
);
2530 static void isom_remove_keys_entry( isom_keys_entry_t
*data
)
2534 if( data
->key_value
)
2535 free( data
->key_value
);
2539 static void isom_remove_keys( isom_keys_t
*keys
)
2543 lsmash_remove_list( keys
->list
, isom_remove_keys_entry
);
2544 isom_remove_box( keys
, isom_meta_t
);
2547 void isom_remove_mean( isom_mean_t
*mean
)
2551 if( mean
->meaning_string
)
2552 free( mean
->meaning_string
);
2553 isom_remove_box( mean
, isom_metaitem_t
);
2556 void isom_remove_name( isom_name_t
*name
)
2562 isom_remove_box( name
, isom_metaitem_t
);
2565 void isom_remove_data( isom_data_t
*data
)
2570 free( data
->value
);
2571 isom_remove_box( data
, isom_metaitem_t
);
2574 void isom_remove_metaitem( isom_metaitem_t
*metaitem
)
2578 isom_remove_mean( metaitem
->mean
);
2579 isom_remove_name( metaitem
->name
);
2580 isom_remove_data( metaitem
->data
);
2584 void isom_remove_ilst( isom_ilst_t
*ilst
)
2588 lsmash_remove_list( ilst
->item_list
, isom_remove_metaitem
);
2589 isom_remove_box( ilst
, isom_meta_t
);
2592 static void isom_remove_meta( isom_meta_t
*meta
)
2596 isom_remove_hdlr( meta
->hdlr
);
2597 isom_remove_dinf( meta
->dinf
);
2598 isom_remove_keys( meta
->keys
);
2599 isom_remove_ilst( meta
->ilst
);
2602 if( lsmash_check_box_type_identical( meta
->parent
->type
, LSMASH_BOX_TYPE_UNSPECIFIED
) )
2603 isom_remove_box( meta
, lsmash_root_t
);
2604 else if( lsmash_check_box_type_identical( meta
->parent
->type
, ISOM_BOX_TYPE_MOOV
) )
2605 isom_remove_box( meta
, isom_moov_t
);
2606 else if( lsmash_check_box_type_identical( meta
->parent
->type
, ISOM_BOX_TYPE_TRAK
) )
2607 isom_remove_box( meta
, isom_trak_entry_t
);
2608 else if( lsmash_check_box_type_identical( meta
->parent
->type
, ISOM_BOX_TYPE_UDTA
) )
2609 isom_remove_box( meta
, isom_udta_t
);
2617 static void isom_remove_cprt( isom_cprt_t
*cprt
)
2622 free( cprt
->notice
);
2626 static void isom_remove_udta( isom_udta_t
*udta
)
2630 isom_remove_chpl( udta
->chpl
);
2631 isom_remove_meta( udta
->meta
);
2636 lsmash_remove_list( udta
->cprt_list
, isom_remove_cprt
);
2639 if( lsmash_check_box_type_identical( udta
->parent
->type
, ISOM_BOX_TYPE_MOOV
) )
2640 isom_remove_box( udta
, isom_moov_t
);
2641 else if( lsmash_check_box_type_identical( udta
->parent
->type
, ISOM_BOX_TYPE_TRAK
) )
2642 isom_remove_box( udta
, isom_trak_entry_t
);
2650 static void isom_remove_sample_pool( isom_sample_pool_t
*pool
);
2652 void isom_remove_trak( isom_trak_entry_t
*trak
)
2656 isom_remove_tkhd( trak
->tkhd
);
2657 isom_remove_tapt( trak
->tapt
);
2658 isom_remove_edts( trak
->edts
);
2659 isom_remove_tref( trak
->tref
);
2660 isom_remove_mdia( trak
->mdia
);
2661 isom_remove_udta( trak
->udta
);
2662 isom_remove_meta( trak
->meta
);
2665 isom_remove_sample_pool( trak
->cache
->chunk
.pool
);
2666 lsmash_remove_list( trak
->cache
->roll
.pool
, NULL
);
2667 if( trak
->cache
->rap
)
2668 free( trak
->cache
->rap
);
2669 free( trak
->cache
);
2671 free( trak
); /* Note: the list that contains this trak still has the address of the entry. */
2674 static void isom_remove_iods( isom_iods_t
*iods
)
2678 mp4sys_remove_ObjectDescriptor( iods
->OD
);
2679 isom_remove_box( iods
, isom_moov_t
);
2682 void isom_remove_ctab( isom_ctab_t
*ctab
)
2686 if( ctab
->color_table
.array
)
2687 free( ctab
->color_table
.array
);
2688 if( ctab
->parent
&& lsmash_check_box_type_identical( ctab
->parent
->type
, ISOM_BOX_TYPE_MOOV
) )
2689 isom_remove_box( ctab
, isom_moov_t
);
2694 static void isom_remove_mehd( isom_mehd_t
*mehd
)
2698 isom_remove_box( mehd
, isom_mvex_t
);
2701 static void isom_remove_mvex( isom_mvex_t
*mvex
)
2705 isom_remove_mehd( mvex
->mehd
);
2706 lsmash_remove_list( mvex
->trex_list
, NULL
);
2707 isom_remove_box( mvex
, isom_moov_t
);
2710 static void isom_remove_moov( lsmash_root_t
*root
)
2712 if( !root
|| !root
->moov
)
2714 isom_moov_t
*moov
= root
->moov
;
2717 isom_remove_iods( moov
->iods
);
2718 lsmash_remove_list( moov
->trak_list
, isom_remove_trak
);
2719 isom_remove_udta( moov
->udta
);
2720 isom_remove_ctab( moov
->ctab
);
2721 isom_remove_meta( moov
->meta
);
2722 isom_remove_mvex( moov
->mvex
);
2727 static void isom_remove_mfhd( isom_mfhd_t
*mfhd
)
2731 isom_remove_box( mfhd
, isom_moof_entry_t
);
2734 static void isom_remove_tfhd( isom_tfhd_t
*tfhd
)
2738 isom_remove_box( tfhd
, isom_traf_entry_t
);
2741 static void isom_remove_tfdt( isom_tfdt_t
*tfdt
)
2745 isom_remove_box( tfdt
, isom_traf_entry_t
);
2748 static void isom_remove_trun( isom_trun_entry_t
*trun
)
2752 lsmash_remove_list( trun
->optional
, NULL
);
2753 free( trun
); /* Note: the list that contains this trun still has the address of the entry. */
2756 static void isom_remove_traf( isom_traf_entry_t
*traf
)
2760 isom_remove_tfhd( traf
->tfhd
);
2761 isom_remove_tfdt( traf
->tfdt
);
2762 lsmash_remove_list( traf
->trun_list
, isom_remove_trun
);
2763 isom_remove_sdtp( traf
->sdtp
);
2764 free( traf
); /* Note: the list that contains this traf still has the address of the entry. */
2767 static void isom_remove_moof( isom_moof_entry_t
*moof
)
2771 isom_remove_mfhd( moof
->mfhd
);
2772 lsmash_remove_list( moof
->traf_list
, isom_remove_traf
);
2776 static void isom_remove_mdat( isom_mdat_t
*mdat
)
2780 isom_remove_box( mdat
, lsmash_root_t
);
2783 static void isom_remove_free( isom_free_t
*skip
)
2789 lsmash_root_t
*root
= (lsmash_root_t
*)skip
->parent
;
2794 static void isom_remove_tfra( isom_tfra_entry_t
*tfra
)
2798 lsmash_remove_list( tfra
->list
, NULL
);
2802 static void isom_remove_mfro( isom_mfro_t
*mfro
)
2806 isom_remove_box( mfro
, isom_mfra_t
);
2809 static void isom_remove_mfra( isom_mfra_t
*mfra
)
2813 lsmash_remove_list( mfra
->tfra_list
, isom_remove_tfra
);
2814 isom_remove_mfro( mfra
->mfro
);
2815 isom_remove_box( mfra
, lsmash_root_t
);
2818 /* We put a placeholder for 64-bit media data if the media_size of the argument is set to 0.
2819 * If a Media Data Box already exists and we don't pick movie fragments structure,
2820 * write the actual size of the current one and start a new one. */
2821 static int isom_new_mdat( lsmash_root_t
*root
, uint64_t media_size
)
2827 /* Write the actual size of the current Media Data Box. */
2828 if( !root
->fragment
&& isom_write_mdat_size( root
) )
2833 isom_create_box( mdat
, root
, ISOM_BOX_TYPE_MDAT
);
2836 /* Start a new Media Data Box. */
2837 return isom_write_mdat_header( root
, media_size
);
2840 int isom_check_compatibility( lsmash_root_t
*root
)
2844 root
->qt_compatible
= 0;
2845 /* Check brand to decide mandatory boxes. */
2846 if( !root
->ftyp
|| !root
->ftyp
->brand_count
)
2848 /* No brand declaration means this file is a MP4 version 1 or QuickTime file format. */
2849 if( root
->moov
&& root
->moov
->iods
)
2851 root
->mp4_version1
= 1;
2852 root
->isom_compatible
= 1;
2855 root
->qt_compatible
= 1;
2858 for( uint32_t i
= 0; i
<= root
->ftyp
->brand_count
; i
++ )
2860 uint32_t brand
= (i
== root
->ftyp
->brand_count
? root
->ftyp
->major_brand
: root
->ftyp
->compatible_brands
[i
]);
2863 case ISOM_BRAND_TYPE_QT
:
2864 root
->qt_compatible
= 1;
2866 case ISOM_BRAND_TYPE_MP41
:
2867 root
->mp4_version1
= 1;
2869 case ISOM_BRAND_TYPE_MP42
:
2870 root
->mp4_version2
= 1;
2872 case ISOM_BRAND_TYPE_AVC1
:
2873 case ISOM_BRAND_TYPE_ISOM
:
2874 root
->max_isom_version
= LSMASH_MAX( root
->max_isom_version
, 1 );
2876 case ISOM_BRAND_TYPE_ISO2
:
2877 root
->max_isom_version
= LSMASH_MAX( root
->max_isom_version
, 2 );
2879 case ISOM_BRAND_TYPE_ISO3
:
2880 root
->max_isom_version
= LSMASH_MAX( root
->max_isom_version
, 3 );
2882 case ISOM_BRAND_TYPE_ISO4
:
2883 root
->max_isom_version
= LSMASH_MAX( root
->max_isom_version
, 4 );
2885 case ISOM_BRAND_TYPE_ISO5
:
2886 root
->max_isom_version
= LSMASH_MAX( root
->max_isom_version
, 5 );
2888 case ISOM_BRAND_TYPE_ISO6
:
2889 root
->max_isom_version
= LSMASH_MAX( root
->max_isom_version
, 6 );
2891 case ISOM_BRAND_TYPE_M4A
:
2892 case ISOM_BRAND_TYPE_M4B
:
2893 case ISOM_BRAND_TYPE_M4P
:
2894 case ISOM_BRAND_TYPE_M4V
:
2895 root
->itunes_movie
= 1;
2897 case ISOM_BRAND_TYPE_3GP4
:
2898 root
->max_3gpp_version
= LSMASH_MAX( root
->max_3gpp_version
, 4 );
2900 case ISOM_BRAND_TYPE_3GP5
:
2901 root
->max_3gpp_version
= LSMASH_MAX( root
->max_3gpp_version
, 5 );
2903 case ISOM_BRAND_TYPE_3GE6
:
2904 case ISOM_BRAND_TYPE_3GG6
:
2905 case ISOM_BRAND_TYPE_3GP6
:
2906 case ISOM_BRAND_TYPE_3GR6
:
2907 case ISOM_BRAND_TYPE_3GS6
:
2908 root
->max_3gpp_version
= LSMASH_MAX( root
->max_3gpp_version
, 6 );
2915 case ISOM_BRAND_TYPE_AVC1
:
2916 case ISOM_BRAND_TYPE_ISO2
:
2917 case ISOM_BRAND_TYPE_ISO3
:
2918 case ISOM_BRAND_TYPE_ISO4
:
2919 case ISOM_BRAND_TYPE_ISO5
:
2920 case ISOM_BRAND_TYPE_ISO6
:
2921 root
->avc_extensions
= 1;
2927 root
->isom_compatible
= !root
->qt_compatible
|| root
->mp4_version1
|| root
->mp4_version2
|| root
->itunes_movie
|| root
->max_3gpp_version
;
2931 static uint32_t isom_get_sample_count( isom_trak_entry_t
*trak
)
2933 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
|| !trak
->mdia
->minf
->stbl
->stsz
)
2935 return trak
->mdia
->minf
->stbl
->stsz
->sample_count
;
2938 static uint64_t isom_get_dts( isom_stts_t
*stts
, uint32_t sample_number
)
2940 if( !stts
|| !stts
->list
)
2944 lsmash_entry_t
*entry
;
2945 isom_stts_entry_t
*data
;
2946 for( entry
= stts
->list
->head
; entry
; entry
= entry
->next
)
2948 data
= (isom_stts_entry_t
*)entry
->data
;
2951 if( i
+ data
->sample_count
> sample_number
)
2953 dts
+= (uint64_t)data
->sample_delta
* data
->sample_count
;
2954 i
+= data
->sample_count
;
2958 dts
+= (uint64_t)data
->sample_delta
* (sample_number
- i
);
2963 static uint64_t isom_get_cts( isom_stts_t
*stts
, isom_ctts_t
*ctts
, uint32_t sample_number
)
2965 if( !stts
|| !stts
->list
)
2968 return isom_get_dts( stts
, sample_number
);
2969 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. */
2970 lsmash_entry_t
*entry
;
2971 isom_ctts_entry_t
*data
;
2972 if( sample_number
== 0 )
2974 for( entry
= ctts
->list
->head
; entry
; entry
= entry
->next
)
2976 data
= (isom_ctts_entry_t
*)entry
->data
;
2979 if( i
+ data
->sample_count
> sample_number
)
2981 i
+= data
->sample_count
;
2985 return isom_get_dts( stts
, sample_number
) + data
->sample_offset
;
2989 static int isom_replace_last_sample_delta( isom_stbl_t
*stbl
, uint32_t sample_delta
)
2991 if( !stbl
|| !stbl
->stts
|| !stbl
->stts
->list
|| !stbl
->stts
->list
->tail
|| !stbl
->stts
->list
->tail
->data
)
2993 isom_stts_entry_t
*last_stts_data
= (isom_stts_entry_t
*)stbl
->stts
->list
->tail
->data
;
2994 if( sample_delta
!= last_stts_data
->sample_delta
)
2996 if( last_stts_data
->sample_count
> 1 )
2998 last_stts_data
->sample_count
-= 1;
2999 if( isom_add_stts_entry( stbl
, sample_delta
) )
3003 last_stts_data
->sample_delta
= sample_delta
;
3008 static int isom_update_mdhd_duration( isom_trak_entry_t
*trak
, uint32_t last_sample_delta
)
3010 if( !trak
|| !trak
->root
|| !trak
->cache
|| !trak
->mdia
|| !trak
->mdia
->mdhd
|| !trak
->mdia
->minf
3011 || !trak
->mdia
->minf
->stbl
|| !trak
->mdia
->minf
->stbl
->stts
|| !trak
->mdia
->minf
->stbl
->stts
->list
)
3013 lsmash_root_t
*root
= trak
->root
;
3014 isom_mdhd_t
*mdhd
= trak
->mdia
->mdhd
;
3015 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
3016 isom_stts_t
*stts
= stbl
->stts
;
3017 isom_ctts_t
*ctts
= stbl
->ctts
;
3018 isom_cslg_t
*cslg
= stbl
->cslg
;
3020 uint32_t sample_count
= isom_get_sample_count( trak
);
3023 /* Return error if non-fragmented movie has no samples. */
3024 if( !root
->fragment
&& !stts
->list
->entry_count
)
3028 /* Now we have at least 1 sample, so do stts_entry. */
3029 lsmash_entry_t
*last_stts
= stts
->list
->tail
;
3030 isom_stts_entry_t
*last_stts_data
= (isom_stts_entry_t
*)last_stts
->data
;
3031 if( sample_count
== 1 )
3032 mdhd
->duration
= last_stts_data
->sample_delta
;
3033 /* Now we have at least 2 samples,
3034 * but dunno whether 1 stts_entry which has 2 samples or 2 stts_entry which has 1 samle each. */
3037 /* use dts instead of cts */
3038 mdhd
->duration
= isom_get_dts( stts
, sample_count
);
3039 if( last_sample_delta
)
3041 mdhd
->duration
+= last_sample_delta
;
3042 if( isom_replace_last_sample_delta( stbl
, last_sample_delta
) )
3045 else if( last_stts_data
->sample_count
> 1 )
3046 mdhd
->duration
+= last_stts_data
->sample_delta
; /* no need to update last_stts_data->sample_delta */
3049 /* Remove the last entry. */
3050 if( lsmash_remove_entry( stts
->list
, stts
->list
->entry_count
, NULL
) )
3052 /* copy the previous sample_delta. */
3053 ++ ((isom_stts_entry_t
*)stts
->list
->tail
->data
)->sample_count
;
3054 mdhd
->duration
+= ((isom_stts_entry_t
*)stts
->list
->tail
->data
)->sample_delta
;
3059 if( !ctts
->list
|| ctts
->list
->entry_count
== 0 )
3062 uint64_t max_cts
= 0, max2_cts
= 0, min_cts
= UINT64_MAX
;
3063 uint32_t max_offset
= 0, min_offset
= UINT32_MAX
;
3064 int32_t ctd_shift
= trak
->cache
->timestamp
.ctd_shift
;
3066 lsmash_entry_t
*stts_entry
= stts
->list
->head
;
3067 lsmash_entry_t
*ctts_entry
= ctts
->list
->head
;
3069 for( uint32_t i
= 0; i
< sample_count
; i
++ )
3071 if( !ctts_entry
|| !stts_entry
)
3073 isom_stts_entry_t
*stts_data
= (isom_stts_entry_t
*)stts_entry
->data
;
3074 isom_ctts_entry_t
*ctts_data
= (isom_ctts_entry_t
*)ctts_entry
->data
;
3075 if( !stts_data
|| !ctts_data
)
3080 /* Anyway, add composition to decode timeline shift for calculating maximum and minimum CTS correctly. */
3081 int32_t sample_offset
= (int32_t)ctts_data
->sample_offset
;
3082 cts
= dts
+ sample_offset
+ ctd_shift
;
3083 max_offset
= LSMASH_MAX( (int32_t)max_offset
, sample_offset
);
3084 min_offset
= LSMASH_MIN( (int32_t)min_offset
, sample_offset
);
3088 cts
= dts
+ ctts_data
->sample_offset
;
3089 max_offset
= LSMASH_MAX( max_offset
, ctts_data
->sample_offset
);
3090 min_offset
= LSMASH_MIN( min_offset
, ctts_data
->sample_offset
);
3092 min_cts
= LSMASH_MIN( min_cts
, cts
);
3098 else if( max2_cts
< cts
)
3100 dts
+= stts_data
->sample_delta
;
3101 /* If finished sample_count of current entry, move to next. */
3102 if( ++j
== ctts_data
->sample_count
)
3104 ctts_entry
= ctts_entry
->next
;
3107 if( ++k
== stts_data
->sample_count
)
3109 stts_entry
= stts_entry
->next
;
3113 dts
-= last_stts_data
->sample_delta
;
3114 if( root
->fragment
)
3115 /* Overall presentation is extended exceeding this initial movie.
3116 * So, any players shall display the movie exceeding the durations
3117 * indicated in Movie Header Box, Track Header Boxes and Media Header Boxes.
3118 * Samples up to the duration indicated in Movie Extends Header Box shall be displayed.
3119 * In the absence of Movie Extends Header Box, all samples shall be displayed. */
3120 mdhd
->duration
+= dts
+ last_sample_delta
;
3123 if( !last_sample_delta
)
3125 /* The spec allows an arbitrary value for the duration of the last sample. So, we pick last-1 sample's. */
3126 last_sample_delta
= max_cts
- max2_cts
;
3128 mdhd
->duration
= max_cts
- min_cts
+ last_sample_delta
;
3129 /* To match dts and media duration, update stts and mdhd relatively. */
3130 if( mdhd
->duration
> dts
)
3131 last_sample_delta
= mdhd
->duration
- dts
;
3133 mdhd
->duration
= dts
+ last_sample_delta
; /* media duration must not less than last dts. */
3135 if( isom_replace_last_sample_delta( stbl
, last_sample_delta
) )
3137 /* Explicit composition information and timeline shifting */
3138 if( cslg
|| root
->qt_compatible
|| root
->max_isom_version
>= 4 )
3142 /* Remove composition to decode timeline shift. */
3143 max_cts
-= ctd_shift
;
3144 max2_cts
-= ctd_shift
;
3145 min_cts
-= ctd_shift
;
3147 int64_t composition_end_time
= max_cts
+ (max_cts
- max2_cts
);
3149 && ((int32_t)min_offset
<= INT32_MAX
) && ((int32_t)max_offset
<= INT32_MAX
)
3150 && ((int64_t)min_cts
<= INT32_MAX
) && (composition_end_time
<= INT32_MAX
) )
3154 if( isom_add_cslg( trak
->mdia
->minf
->stbl
) )
3158 cslg
->compositionToDTSShift
= ctd_shift
;
3159 cslg
->leastDecodeToDisplayDelta
= min_offset
;
3160 cslg
->greatestDecodeToDisplayDelta
= max_offset
;
3161 cslg
->compositionStartTime
= min_cts
;
3162 cslg
->compositionEndTime
= composition_end_time
;
3172 if( mdhd
->duration
> UINT32_MAX
)
3177 static int isom_update_mvhd_duration( isom_moov_t
*moov
)
3179 if( !moov
|| !moov
->mvhd
)
3181 isom_mvhd_t
*mvhd
= moov
->mvhd
;
3183 for( lsmash_entry_t
*entry
= moov
->trak_list
->head
; entry
; entry
= entry
->next
)
3185 /* We pick maximum track duration as movie duration. */
3186 isom_trak_entry_t
*data
= (isom_trak_entry_t
*)entry
->data
;
3187 if( !data
|| !data
->tkhd
)
3189 mvhd
->duration
= entry
!= moov
->trak_list
->head
? LSMASH_MAX( mvhd
->duration
, data
->tkhd
->duration
) : data
->tkhd
->duration
;
3191 if( mvhd
->duration
> UINT32_MAX
)
3196 static int isom_update_tkhd_duration( isom_trak_entry_t
*trak
)
3198 if( !trak
|| !trak
->tkhd
|| !trak
->root
|| !trak
->root
->moov
)
3200 lsmash_root_t
*root
= trak
->root
;
3201 isom_tkhd_t
*tkhd
= trak
->tkhd
;
3203 if( root
->fragment
|| !trak
->edts
|| !trak
->edts
->elst
)
3205 /* If this presentation might be extended or this track doesn't have edit list, calculate track duration from media duration. */
3206 if( !trak
->mdia
|| !trak
->mdia
->mdhd
|| !root
->moov
->mvhd
|| !trak
->mdia
->mdhd
->timescale
)
3208 if( !trak
->mdia
->mdhd
->duration
&& isom_update_mdhd_duration( trak
, 0 ) )
3210 tkhd
->duration
= trak
->mdia
->mdhd
->duration
* ((double)root
->moov
->mvhd
->timescale
/ trak
->mdia
->mdhd
->timescale
);
3214 /* If the presentation won't be extended and this track has any edit, then track duration is just the sum of the segment_duartions. */
3215 for( lsmash_entry_t
*entry
= trak
->edts
->elst
->list
->head
; entry
; entry
= entry
->next
)
3217 isom_elst_entry_t
*data
= (isom_elst_entry_t
*)entry
->data
;
3220 tkhd
->duration
+= data
->segment_duration
;
3223 if( tkhd
->duration
> UINT32_MAX
)
3225 if( !root
->fragment
&& !tkhd
->duration
)
3226 tkhd
->duration
= tkhd
->version
== 1 ? 0xffffffffffffffff : 0xffffffff;
3227 return isom_update_mvhd_duration( root
->moov
);
3230 int lsmash_update_track_duration( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t last_sample_delta
)
3232 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
3235 if( isom_update_mdhd_duration( trak
, last_sample_delta
) )
3237 /* If the presentation won't be extended and this track has any edit, we don't change or update duration in tkhd. */
3238 return (!root
->fragment
&& trak
->edts
&& trak
->edts
->elst
)
3239 ? isom_update_mvhd_duration( root
->moov
) /* Only update movie duration. */
3240 : isom_update_tkhd_duration( trak
); /* Also update movie duration internally. */
3243 static inline int isom_increment_sample_number_in_entry( uint32_t *sample_number_in_entry
, uint32_t sample_count_in_entry
, lsmash_entry_t
**entry
)
3245 if( *sample_number_in_entry
!= sample_count_in_entry
)
3247 *sample_number_in_entry
+= 1;
3250 /* Precede the next entry. */
3251 *sample_number_in_entry
= 1;
3254 *entry
= (*entry
)->next
;
3255 if( *entry
&& !(*entry
)->data
)
3261 static int isom_calculate_bitrate_description( isom_mdia_t
*mdia
, uint32_t *bufferSizeDB
, uint32_t *maxBitrate
, uint32_t *avgBitrate
, uint32_t sample_description_index
)
3263 isom_stsz_t
*stsz
= mdia
->minf
->stbl
->stsz
;
3264 lsmash_entry_t
*stsz_entry
= stsz
->list
? stsz
->list
->head
: NULL
;
3265 lsmash_entry_t
*stts_entry
= mdia
->minf
->stbl
->stts
->list
->head
;
3266 lsmash_entry_t
*stsc_entry
= NULL
;
3267 lsmash_entry_t
*next_stsc_entry
= mdia
->minf
->stbl
->stsc
->list
->head
;
3268 isom_stts_entry_t
*stts_data
= NULL
;
3269 isom_stsc_entry_t
*stsc_data
= NULL
;
3270 if( next_stsc_entry
&& !next_stsc_entry
->data
)
3274 uint32_t time_wnd
= 0;
3275 uint32_t timescale
= mdia
->mdhd
->timescale
;
3276 uint32_t chunk_number
= 0;
3277 uint32_t sample_number_in_stts
= 1;
3278 uint32_t sample_number_in_chunk
= 1;
3284 if( !stsc_data
|| sample_number_in_chunk
== stsc_data
->samples_per_chunk
)
3286 /* Move the next chunk. */
3287 sample_number_in_chunk
= 1;
3289 /* Check if the next entry is broken. */
3290 while( next_stsc_entry
&& ((isom_stsc_entry_t
*)next_stsc_entry
->data
)->first_chunk
< chunk_number
)
3292 /* Just skip broken next entry. */
3293 next_stsc_entry
= next_stsc_entry
->next
;
3294 if( next_stsc_entry
&& !next_stsc_entry
->data
)
3297 /* Check if the next chunk belongs to the next sequence of chunks. */
3298 if( next_stsc_entry
&& ((isom_stsc_entry_t
*)next_stsc_entry
->data
)->first_chunk
== chunk_number
)
3300 stsc_entry
= next_stsc_entry
;
3301 next_stsc_entry
= next_stsc_entry
->next
;
3302 if( next_stsc_entry
&& !next_stsc_entry
->data
)
3304 stsc_data
= (isom_stsc_entry_t
*)stsc_entry
->data
;
3305 /* Check if the next contiguous chunks belong to given sample description. */
3306 if( stsc_data
->sample_description_index
!= sample_description_index
)
3308 /* Skip chunks which don't belong to given sample description. */
3309 uint32_t number_of_skips
= 0;
3310 uint32_t first_chunk
= stsc_data
->first_chunk
;
3311 uint32_t samples_per_chunk
= stsc_data
->samples_per_chunk
;
3312 while( next_stsc_entry
)
3314 if( ((isom_stsc_entry_t
*)next_stsc_entry
->data
)->sample_description_index
!= sample_description_index
)
3316 stsc_data
= (isom_stsc_entry_t
*)next_stsc_entry
->data
;
3317 number_of_skips
+= (stsc_data
->first_chunk
- first_chunk
) * samples_per_chunk
;
3318 first_chunk
= stsc_data
->first_chunk
;
3319 samples_per_chunk
= stsc_data
->samples_per_chunk
;
3321 else if( ((isom_stsc_entry_t
*)next_stsc_entry
->data
)->first_chunk
<= first_chunk
)
3322 ; /* broken entry */
3325 /* Just skip the next entry. */
3326 next_stsc_entry
= next_stsc_entry
->next
;
3327 if( next_stsc_entry
&& !next_stsc_entry
->data
)
3330 if( !next_stsc_entry
)
3331 break; /* There is no more chunks which don't belong to given sample description. */
3332 number_of_skips
+= (((isom_stsc_entry_t
*)next_stsc_entry
->data
)->first_chunk
- first_chunk
) * samples_per_chunk
;
3333 for( uint32_t i
= 0; i
< number_of_skips
; i
++ )
3339 stsz_entry
= stsz_entry
->next
;
3343 if( isom_increment_sample_number_in_entry( &sample_number_in_stts
, ((isom_stts_entry_t
*)stts_entry
->data
)->sample_count
, &stts_entry
) )
3346 if( (stsz
->list
&& !stsz_entry
) || !stts_entry
)
3348 chunk_number
= stsc_data
->first_chunk
;
3353 ++sample_number_in_chunk
;
3354 /* Get current sample's size. */
3360 isom_stsz_entry_t
*stsz_data
= (isom_stsz_entry_t
*)stsz_entry
->data
;
3363 size
= stsz_data
->entry_size
;
3364 stsz_entry
= stsz_entry
->next
;
3367 size
= stsz
->sample_size
;
3368 /* Get current sample's DTS. */
3370 dts
+= stts_data
->sample_delta
;
3371 stts_data
= (isom_stts_entry_t
*)stts_entry
->data
;
3374 isom_increment_sample_number_in_entry( &sample_number_in_stts
, stts_data
->sample_count
, &stts_entry
);
3375 /* Calculate bitrate description. */
3376 if( *bufferSizeDB
< size
)
3377 *bufferSizeDB
= size
;
3378 *avgBitrate
+= size
;
3380 if( dts
> time_wnd
+ timescale
)
3382 if( rate
> *maxBitrate
)
3388 double duration
= (double)mdia
->mdhd
->duration
/ timescale
;
3389 *avgBitrate
= (uint32_t)(*avgBitrate
/ duration
);
3391 *maxBitrate
= *avgBitrate
;
3392 /* Convert to bits per second. */
3398 static int isom_update_bitrate_description( isom_mdia_t
*mdia
)
3400 if( !mdia
|| !mdia
->mdhd
|| !mdia
->minf
|| !mdia
->minf
->stbl
)
3402 isom_stbl_t
*stbl
= mdia
->minf
->stbl
;
3403 if( !stbl
->stsd
|| !stbl
->stsd
->list
3405 || !stbl
->stsc
|| !stbl
->stsc
->list
3406 || !stbl
->stts
|| !stbl
->stts
->list
)
3408 uint32_t sample_description_index
= 0;
3409 for( lsmash_entry_t
*entry
= stbl
->stsd
->list
->head
; entry
; entry
= entry
->next
)
3411 isom_sample_entry_t
*sample_entry
= (isom_sample_entry_t
*)entry
->data
;
3414 ++sample_description_index
;
3415 uint32_t bufferSizeDB
;
3416 uint32_t maxBitrate
;
3417 uint32_t avgBitrate
;
3418 /* set bitrate info */
3419 lsmash_codec_type_t sample_type
= (lsmash_codec_type_t
)sample_entry
->type
;
3420 if( lsmash_check_codec_type_identical( sample_type
, ISOM_CODEC_TYPE_AVC1_VIDEO
)
3421 || lsmash_check_codec_type_identical( sample_type
, ISOM_CODEC_TYPE_AVC2_VIDEO
)
3422 || lsmash_check_codec_type_identical( sample_type
, ISOM_CODEC_TYPE_AVCP_VIDEO
) )
3424 isom_visual_entry_t
*stsd_data
= (isom_visual_entry_t
*)sample_entry
;
3427 isom_btrt_t
*btrt
= (isom_btrt_t
*)isom_get_extension_box( &stsd_data
->extensions
, ISOM_BOX_TYPE_BTRT
);
3430 if( isom_calculate_bitrate_description( mdia
, &bufferSizeDB
, &maxBitrate
, &avgBitrate
, sample_description_index
) )
3432 btrt
->bufferSizeDB
= bufferSizeDB
;
3433 btrt
->maxBitrate
= maxBitrate
;
3434 btrt
->avgBitrate
= avgBitrate
;
3437 else if( lsmash_check_codec_type_identical( sample_type
, ISOM_CODEC_TYPE_MP4V_VIDEO
) )
3439 isom_visual_entry_t
*stsd_data
= (isom_visual_entry_t
*)sample_entry
;
3442 isom_esds_t
*esds
= (isom_esds_t
*)isom_get_extension_box( &stsd_data
->extensions
, ISOM_BOX_TYPE_ESDS
);
3443 if( !esds
|| !esds
->ES
)
3445 if( isom_calculate_bitrate_description( mdia
, &bufferSizeDB
, &maxBitrate
, &avgBitrate
, sample_description_index
) )
3447 /* FIXME: avgBitrate is 0 only if VBR in proper. */
3448 if( mp4sys_update_DecoderConfigDescriptor( esds
->ES
, bufferSizeDB
, maxBitrate
, 0 ) )
3451 else if( lsmash_check_codec_type_identical( sample_type
, ISOM_CODEC_TYPE_MP4A_AUDIO
) )
3453 isom_audio_entry_t
*stsd_data
= (isom_audio_entry_t
*)sample_entry
;
3456 isom_esds_t
*esds
= NULL
;
3457 if( ((isom_audio_entry_t
*)sample_entry
)->version
)
3459 /* MPEG-4 Audio in QTFF */
3460 isom_wave_t
*wave
= (isom_wave_t
*)isom_get_extension_box( &stsd_data
->extensions
, QT_BOX_TYPE_WAVE
);
3463 esds
= (isom_esds_t
*)isom_get_extension_box( &wave
->extensions
, ISOM_BOX_TYPE_ESDS
);
3466 esds
= (isom_esds_t
*)isom_get_extension_box( &stsd_data
->extensions
, ISOM_BOX_TYPE_ESDS
);
3467 if( !esds
|| !esds
->ES
)
3469 if( isom_calculate_bitrate_description( mdia
, &bufferSizeDB
, &maxBitrate
, &avgBitrate
, sample_description_index
) )
3471 /* FIXME: avgBitrate is 0 only if VBR in proper. */
3472 if( mp4sys_update_DecoderConfigDescriptor( esds
->ES
, bufferSizeDB
, maxBitrate
, 0 ) )
3475 else if( lsmash_check_codec_type_identical( sample_type
, ISOM_CODEC_TYPE_ALAC_AUDIO
)
3476 || lsmash_check_codec_type_identical( sample_type
, QT_CODEC_TYPE_ALAC_AUDIO
) )
3478 isom_audio_entry_t
*alac
= (isom_audio_entry_t
*)sample_entry
;
3481 uint8_t *exdata
= NULL
;
3482 uint32_t exdata_size
= 0;
3483 isom_extension_box_t
*alac_ext
= isom_get_sample_description_extension( &alac
->extensions
, QT_BOX_TYPE_WAVE
);
3486 /* Apple Lossless Audio inside QuickTime file format
3487 * Though average bitrate field we found is always set to 0 apparently,
3488 * we set up maxFrameBytes and avgBitRate fields. */
3489 if( alac_ext
->format
== EXTENSION_FORMAT_BINARY
)
3490 exdata
= isom_get_child_box_position( alac_ext
->form
.binary
, alac_ext
->size
, QT_BOX_TYPE_ALAC
, &exdata_size
);
3493 isom_wave_t
*wave
= (isom_wave_t
*)alac_ext
->form
.box
;
3494 isom_extension_box_t
*wave_ext
= isom_get_sample_description_extension( &wave
->extensions
, QT_BOX_TYPE_ALAC
);
3495 if( !wave_ext
|| wave_ext
->format
!= EXTENSION_FORMAT_BINARY
)
3497 exdata
= wave_ext
->form
.binary
;
3498 exdata_size
= wave_ext
->size
;
3503 /* Apple Lossless Audio inside ISO Base Media file format */
3504 isom_extension_box_t
*ext
= isom_get_sample_description_extension( &alac
->extensions
, ISOM_BOX_TYPE_ALAC
);
3505 if( !ext
|| ext
->format
!= EXTENSION_FORMAT_BINARY
)
3507 exdata
= ext
->form
.binary
;
3508 exdata_size
= ext
->size
;
3510 if( !exdata
|| exdata_size
< 36 )
3512 if( isom_calculate_bitrate_description( mdia
, &bufferSizeDB
, &maxBitrate
, &avgBitrate
, sample_description_index
) )
3516 exdata
[0] = (bufferSizeDB
>> 24) & 0xff;
3517 exdata
[1] = (bufferSizeDB
>> 16) & 0xff;
3518 exdata
[2] = (bufferSizeDB
>> 8) & 0xff;
3519 exdata
[3] = bufferSizeDB
& 0xff;
3521 exdata
[4] = (avgBitrate
>> 24) & 0xff;
3522 exdata
[5] = (avgBitrate
>> 16) & 0xff;
3523 exdata
[6] = (avgBitrate
>> 8) & 0xff;
3524 exdata
[7] = avgBitrate
& 0xff;
3526 else if( lsmash_check_codec_type_identical( sample_type
, ISOM_CODEC_TYPE_DTSC_AUDIO
)
3527 || lsmash_check_codec_type_identical( sample_type
, ISOM_CODEC_TYPE_DTSE_AUDIO
)
3528 || lsmash_check_codec_type_identical( sample_type
, ISOM_CODEC_TYPE_DTSH_AUDIO
)
3529 || lsmash_check_codec_type_identical( sample_type
, ISOM_CODEC_TYPE_DTSL_AUDIO
) )
3531 isom_audio_entry_t
*dts_audio
= (isom_audio_entry_t
*)sample_entry
;
3534 isom_extension_box_t
*ext
= isom_get_sample_description_extension( &dts_audio
->extensions
, ISOM_BOX_TYPE_DDTS
);
3535 if( !(ext
&& ext
->format
== EXTENSION_FORMAT_BINARY
&& ext
->form
.binary
&& ext
->size
>= 28) )
3537 if( isom_calculate_bitrate_description( mdia
, &bufferSizeDB
, &maxBitrate
, &avgBitrate
, sample_description_index
) )
3539 if( !stbl
->stsz
->list
)
3540 maxBitrate
= avgBitrate
;
3541 uint8_t *exdata
= ext
->form
.binary
+ 12;
3542 exdata
[0] = (maxBitrate
>> 24) & 0xff;
3543 exdata
[1] = (maxBitrate
>> 16) & 0xff;
3544 exdata
[2] = (maxBitrate
>> 8) & 0xff;
3545 exdata
[3] = maxBitrate
& 0xff;
3546 exdata
[4] = (avgBitrate
>> 24) & 0xff;
3547 exdata
[5] = (avgBitrate
>> 16) & 0xff;
3548 exdata
[6] = (avgBitrate
>> 8) & 0xff;
3549 exdata
[7] = avgBitrate
& 0xff;
3551 else if( lsmash_check_codec_type_identical( sample_type
, ISOM_CODEC_TYPE_EC_3_AUDIO
) )
3553 isom_audio_entry_t
*eac3
= (isom_audio_entry_t
*)sample_entry
;
3556 isom_extension_box_t
*ext
= isom_get_sample_description_extension( &eac3
->extensions
, ISOM_BOX_TYPE_DEC3
);
3557 if( !(ext
&& ext
->format
== EXTENSION_FORMAT_BINARY
&& ext
->form
.binary
&& ext
->size
>= 10) )
3560 if( stbl
->stsz
->list
)
3562 if( isom_calculate_bitrate_description( mdia
, &bufferSizeDB
, &maxBitrate
, &avgBitrate
, sample_description_index
) )
3564 bitrate
= maxBitrate
/ 1000; /* Use maximum bitrate if VBR. */
3567 bitrate
= stbl
->stsz
->sample_size
* (eac3
->samplerate
>> 16) / 192000; /* 192000 == 1536 * 1000 / 8 */
3568 uint8_t *exdata
= ext
->form
.binary
+ 8;
3569 exdata
[0] = (bitrate
>> 5) & 0xff;
3570 exdata
[1] = (bitrate
& 0x1f) << 3;
3573 return sample_description_index
? 0 : -1;
3576 static int isom_check_mandatory_boxes( lsmash_root_t
*root
)
3580 if( !root
->moov
|| !root
->moov
->mvhd
)
3582 if( !root
->moov
->trak_list
)
3584 /* A movie requires at least one track. */
3585 if( !root
->moov
->trak_list
->head
)
3587 for( lsmash_entry_t
*entry
= root
->moov
->trak_list
->head
; entry
; entry
= entry
->next
)
3589 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)entry
->data
;
3593 || !trak
->mdia
->mdhd
3594 || !trak
->mdia
->hdlr
3595 || !trak
->mdia
->minf
3596 || !trak
->mdia
->minf
->dinf
3597 || !trak
->mdia
->minf
->dinf
->dref
3598 || !trak
->mdia
->minf
->stbl
3599 || !trak
->mdia
->minf
->stbl
->stsd
3600 || !trak
->mdia
->minf
->stbl
->stsz
3601 || !trak
->mdia
->minf
->stbl
->stts
3602 || !trak
->mdia
->minf
->stbl
->stsc
3603 || !trak
->mdia
->minf
->stbl
->stco
)
3605 if( root
->qt_compatible
&& !trak
->mdia
->minf
->hdlr
)
3607 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
3608 if( !stbl
->stsd
->list
|| !stbl
->stsd
->list
->head
)
3611 && (!stbl
->stsd
->list
|| !stbl
->stsd
->list
->head
3612 || !stbl
->stts
->list
|| !stbl
->stts
->list
->head
3613 || !stbl
->stsc
->list
|| !stbl
->stsc
->list
->head
3614 || !stbl
->stco
->list
|| !stbl
->stco
->list
->head
) )
3617 if( !root
->fragment
)
3619 if( !root
->moov
->mvex
|| !root
->moov
->mvex
->trex_list
)
3621 for( lsmash_entry_t
*entry
= root
->moov
->mvex
->trex_list
->head
; entry
; entry
= entry
->next
)
3622 if( !entry
->data
) /* trex */
3627 static inline uint64_t isom_get_current_mp4time( void )
3629 return (uint64_t)time( NULL
) + ISOM_MAC_EPOCH_OFFSET
;
3632 static int isom_set_media_creation_time( isom_trak_entry_t
*trak
, uint64_t current_mp4time
)
3634 if( !trak
->mdia
|| !trak
->mdia
->mdhd
)
3636 isom_mdhd_t
*mdhd
= trak
->mdia
->mdhd
;
3637 if( !mdhd
->creation_time
)
3638 mdhd
->creation_time
= mdhd
->modification_time
= current_mp4time
;
3642 static int isom_set_track_creation_time( isom_trak_entry_t
*trak
, uint64_t current_mp4time
)
3644 if( !trak
|| !trak
->tkhd
)
3646 isom_tkhd_t
*tkhd
= trak
->tkhd
;
3647 if( !tkhd
->creation_time
)
3648 tkhd
->creation_time
= tkhd
->modification_time
= current_mp4time
;
3649 if( isom_set_media_creation_time( trak
, current_mp4time
) )
3654 static int isom_set_movie_creation_time( lsmash_root_t
*root
)
3656 if( !root
|| !root
->moov
|| !root
->moov
->mvhd
|| !root
->moov
->trak_list
)
3658 uint64_t current_mp4time
= isom_get_current_mp4time();
3659 for( uint32_t i
= 1; i
<= root
->moov
->trak_list
->entry_count
; i
++ )
3660 if( isom_set_track_creation_time( isom_get_trak( root
, i
), current_mp4time
) )
3662 isom_mvhd_t
*mvhd
= root
->moov
->mvhd
;
3663 if( !mvhd
->creation_time
)
3664 mvhd
->creation_time
= mvhd
->modification_time
= current_mp4time
;
3668 #define CHECK_LARGESIZE( x ) \
3669 (x->size) += isom_update_extension_boxes( x ); \
3670 if( (x->size) > UINT32_MAX ) (x->size) += 8
3672 static uint64_t isom_update_extension_boxes( void *box
);
3674 static uint64_t isom_update_unknown_box_size( isom_unknown_box_t
*unknown_box
)
3678 unknown_box
->size
= ISOM_BASEBOX_COMMON_SIZE
+ unknown_box
->unknown_size
;
3679 CHECK_LARGESIZE( unknown_box
);
3680 return unknown_box
->size
;
3683 static uint64_t isom_update_mvhd_size( isom_mvhd_t
*mvhd
)
3688 if( mvhd
->creation_time
> UINT32_MAX
|| mvhd
->modification_time
> UINT32_MAX
|| mvhd
->duration
> UINT32_MAX
)
3690 mvhd
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 96 + (uint64_t)mvhd
->version
* 12;
3691 CHECK_LARGESIZE( mvhd
);
3695 static uint64_t isom_update_iods_size( isom_iods_t
*iods
)
3697 if( !iods
|| !iods
->OD
)
3699 iods
->size
= ISOM_FULLBOX_COMMON_SIZE
+ mp4sys_update_ObjectDescriptor_size( iods
->OD
);
3700 CHECK_LARGESIZE( iods
);
3704 static uint64_t isom_update_ctab_size( isom_ctab_t
*ctab
)
3708 ctab
->size
= ISOM_BASEBOX_COMMON_SIZE
+ (uint64_t)(1 + ctab
->color_table
.size
+ !!ctab
->color_table
.array
) * 8;
3709 CHECK_LARGESIZE( ctab
);
3713 static uint64_t isom_update_tkhd_size( isom_tkhd_t
*tkhd
)
3718 if( tkhd
->creation_time
> UINT32_MAX
|| tkhd
->modification_time
> UINT32_MAX
|| tkhd
->duration
> UINT32_MAX
)
3720 tkhd
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 80 + (uint64_t)tkhd
->version
* 12;
3721 CHECK_LARGESIZE( tkhd
);
3725 static uint64_t isom_update_clef_size( isom_clef_t
*clef
)
3729 clef
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 8;
3730 CHECK_LARGESIZE( clef
);
3734 static uint64_t isom_update_prof_size( isom_prof_t
*prof
)
3738 prof
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 8;
3739 CHECK_LARGESIZE( prof
);
3743 static uint64_t isom_update_enof_size( isom_enof_t
*enof
)
3747 enof
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 8;
3748 CHECK_LARGESIZE( enof
);
3752 static uint64_t isom_update_tapt_size( isom_tapt_t
*tapt
)
3756 tapt
->size
= ISOM_BASEBOX_COMMON_SIZE
3757 + isom_update_clef_size( tapt
->clef
)
3758 + isom_update_prof_size( tapt
->prof
)
3759 + isom_update_enof_size( tapt
->enof
);
3760 CHECK_LARGESIZE( tapt
);
3764 static uint64_t isom_update_elst_size( isom_elst_t
*elst
)
3766 if( !elst
|| !elst
->list
)
3770 for( lsmash_entry_t
*entry
= elst
->list
->head
; entry
; entry
= entry
->next
, i
++ )
3772 isom_elst_entry_t
*data
= (isom_elst_entry_t
*)entry
->data
;
3773 if( data
->segment_duration
> UINT32_MAX
|| data
->media_time
> INT32_MAX
|| data
->media_time
< INT32_MIN
)
3776 elst
->size
= ISOM_LIST_FULLBOX_COMMON_SIZE
+ (uint64_t)i
* ( elst
->version
? 20 : 12 );
3777 CHECK_LARGESIZE( elst
);
3781 static uint64_t isom_update_edts_size( isom_edts_t
*edts
)
3785 edts
->size
= ISOM_BASEBOX_COMMON_SIZE
+ isom_update_elst_size( edts
->elst
);
3786 CHECK_LARGESIZE( edts
);
3790 static uint64_t isom_update_tref_size( isom_tref_t
*tref
)
3794 tref
->size
= ISOM_BASEBOX_COMMON_SIZE
;
3795 if( tref
->ref_list
)
3796 for( lsmash_entry_t
*entry
= tref
->ref_list
->head
; entry
; entry
= entry
->next
)
3798 isom_tref_type_t
*ref
= (isom_tref_type_t
*)entry
->data
;
3799 ref
->size
= ISOM_BASEBOX_COMMON_SIZE
+ (uint64_t)ref
->ref_count
* 4;
3800 CHECK_LARGESIZE( ref
);
3801 tref
->size
+= ref
->size
;
3803 CHECK_LARGESIZE( tref
);
3807 static uint64_t isom_update_mdhd_size( isom_mdhd_t
*mdhd
)
3812 if( mdhd
->creation_time
> UINT32_MAX
|| mdhd
->modification_time
> UINT32_MAX
|| mdhd
->duration
> UINT32_MAX
)
3814 mdhd
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 20 + (uint64_t)mdhd
->version
* 12;
3815 CHECK_LARGESIZE( mdhd
);
3819 static uint64_t isom_update_hdlr_size( isom_hdlr_t
*hdlr
)
3823 hdlr
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 20 + (uint64_t)hdlr
->componentName_length
;
3824 CHECK_LARGESIZE( hdlr
);
3828 static uint64_t isom_update_dref_entry_size( isom_dref_entry_t
*urln
)
3832 urln
->size
= ISOM_FULLBOX_COMMON_SIZE
+ (uint64_t)urln
->name_length
+ urln
->location_length
;
3833 CHECK_LARGESIZE( urln
);
3837 static uint64_t isom_update_dref_size( isom_dref_t
*dref
)
3839 if( !dref
|| !dref
->list
)
3841 dref
->size
= ISOM_LIST_FULLBOX_COMMON_SIZE
;
3843 for( lsmash_entry_t
*entry
= dref
->list
->head
; entry
; entry
= entry
->next
)
3845 isom_dref_entry_t
*data
= (isom_dref_entry_t
*)entry
->data
;
3846 dref
->size
+= isom_update_dref_entry_size( data
);
3848 CHECK_LARGESIZE( dref
);
3852 static uint64_t isom_update_dinf_size( isom_dinf_t
*dinf
)
3856 dinf
->size
= ISOM_BASEBOX_COMMON_SIZE
+ isom_update_dref_size( dinf
->dref
);
3857 CHECK_LARGESIZE( dinf
);
3861 static uint64_t isom_update_vmhd_size( isom_vmhd_t
*vmhd
)
3865 vmhd
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 8;
3866 CHECK_LARGESIZE( vmhd
);
3870 static uint64_t isom_update_smhd_size( isom_smhd_t
*smhd
)
3874 smhd
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 4;
3875 CHECK_LARGESIZE( smhd
);
3879 static uint64_t isom_update_hmhd_size( isom_hmhd_t
*hmhd
)
3883 hmhd
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 16;
3884 CHECK_LARGESIZE( hmhd
);
3888 static uint64_t isom_update_nmhd_size( isom_nmhd_t
*nmhd
)
3892 nmhd
->size
= ISOM_FULLBOX_COMMON_SIZE
;
3893 CHECK_LARGESIZE( nmhd
);
3897 static uint64_t isom_update_gmin_size( isom_gmin_t
*gmin
)
3901 gmin
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 12;
3902 CHECK_LARGESIZE( gmin
);
3906 static uint64_t isom_update_text_size( isom_text_t
*text
)
3910 text
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 36;
3911 CHECK_LARGESIZE( text
);
3915 static uint64_t isom_update_gmhd_size( isom_gmhd_t
*gmhd
)
3919 gmhd
->size
= ISOM_BASEBOX_COMMON_SIZE
3920 + isom_update_gmin_size( gmhd
->gmin
)
3921 + isom_update_text_size( gmhd
->text
);
3922 CHECK_LARGESIZE( gmhd
);
3926 static uint64_t isom_update_pasp_size( isom_pasp_t
*pasp
)
3930 pasp
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 8;
3931 CHECK_LARGESIZE( pasp
);
3935 static uint64_t isom_update_clap_size( isom_clap_t
*clap
)
3939 clap
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 32;
3940 CHECK_LARGESIZE( clap
);
3944 static uint64_t isom_update_glbl_size( isom_glbl_t
*glbl
)
3948 glbl
->size
= ISOM_BASEBOX_COMMON_SIZE
+ (uint64_t)glbl
->header_size
;
3949 CHECK_LARGESIZE( glbl
);
3953 static uint64_t isom_update_colr_size( isom_colr_t
*colr
)
3956 || (colr
->color_parameter_type
!= ISOM_COLOR_PARAMETER_TYPE_NCLX
3957 && colr
->color_parameter_type
!= QT_COLOR_PARAMETER_TYPE_NCLC
) )
3959 colr
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 10 + (colr
->color_parameter_type
== ISOM_COLOR_PARAMETER_TYPE_NCLX
);
3960 CHECK_LARGESIZE( colr
);
3964 static uint64_t isom_update_gama_size( isom_gama_t
*gama
)
3966 if( !gama
|| !gama
->parent
)
3968 /* Note: 'gama' box is superseded by 'colr' box.
3969 * Therefore, writers of QTFF should never write both 'colr' and 'gama' box into an Image Description. */
3970 if( isom_get_extension_box( &((isom_visual_entry_t
*)gama
->parent
)->extensions
, QT_BOX_TYPE_COLR
) )
3972 gama
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 4;
3973 CHECK_LARGESIZE( gama
);
3977 static uint64_t isom_update_fiel_size( isom_fiel_t
*fiel
)
3981 fiel
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 2;
3982 CHECK_LARGESIZE( fiel
);
3986 static uint64_t isom_update_cspc_size( isom_cspc_t
*cspc
)
3990 cspc
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 4;
3991 CHECK_LARGESIZE( cspc
);
3995 static uint64_t isom_update_sgbt_size( isom_sgbt_t
*sgbt
)
3999 sgbt
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 1;
4000 CHECK_LARGESIZE( sgbt
);
4004 static uint64_t isom_update_stsl_size( isom_stsl_t
*stsl
)
4008 stsl
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 6;
4009 CHECK_LARGESIZE( stsl
);
4013 static uint64_t isom_update_esds_size( isom_esds_t
*esds
)
4017 esds
->size
= ISOM_FULLBOX_COMMON_SIZE
+ mp4sys_update_ES_Descriptor_size( esds
->ES
);
4018 CHECK_LARGESIZE( esds
);
4022 static uint64_t isom_update_btrt_size( isom_btrt_t
*btrt
)
4026 btrt
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 12;
4027 CHECK_LARGESIZE( btrt
);
4031 static uint64_t isom_update_visual_entry_size( isom_sample_entry_t
*description
)
4035 isom_visual_entry_t
*visual
= (isom_visual_entry_t
*)description
;
4036 visual
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 78;
4037 if( visual
->color_table_ID
== 0 )
4038 visual
->size
+= (uint64_t)(1 + visual
->color_table
.size
+ !!visual
->color_table
.array
) * 8;
4039 CHECK_LARGESIZE( visual
);
4040 return visual
->size
;
4044 static uint64_t isom_update_mp4s_entry_size( isom_sample_entry_t
*description
)
4046 if( !description
|| !lsmash_check_box_type_identical( description
->type
, ISOM_CODEC_TYPE_MP4S_SYSTEM
) )
4048 isom_mp4s_entry_t
*mp4s
= (isom_mp4s_entry_t
*)description
;
4049 mp4s
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 8 + isom_update_esds_size( mp4s
->esds
);
4050 CHECK_LARGESIZE( mp4s
);
4055 static uint64_t isom_update_frma_size( isom_frma_t
*frma
)
4059 frma
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 4;
4060 CHECK_LARGESIZE( frma
);
4064 static uint64_t isom_update_enda_size( isom_enda_t
*enda
)
4068 enda
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 2;
4069 CHECK_LARGESIZE( enda
);
4073 static uint64_t isom_update_mp4a_size( isom_mp4a_t
*mp4a
)
4077 mp4a
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 4;
4078 CHECK_LARGESIZE( mp4a
);
4082 static uint64_t isom_update_terminator_size( isom_terminator_t
*terminator
)
4086 terminator
->size
= ISOM_BASEBOX_COMMON_SIZE
;
4087 CHECK_LARGESIZE( terminator
);
4088 return terminator
->size
;
4091 static uint64_t isom_update_wave_size( isom_wave_t
*wave
)
4095 wave
->size
= ISOM_BASEBOX_COMMON_SIZE
4096 + isom_update_frma_size( wave
->frma
)
4097 + isom_update_enda_size( wave
->enda
)
4098 + isom_update_mp4a_size( wave
->mp4a
)
4099 + isom_update_terminator_size( wave
->terminator
);
4100 CHECK_LARGESIZE( wave
);
4104 static uint64_t isom_update_chan_size( isom_chan_t
*chan
)
4108 chan
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 12 + 20 * (uint64_t)chan
->numberChannelDescriptions
;
4109 CHECK_LARGESIZE( chan
);
4113 static uint64_t isom_update_audio_entry_size( isom_sample_entry_t
*description
)
4117 isom_audio_entry_t
*audio
= (isom_audio_entry_t
*)description
;
4118 audio
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 28;
4119 if( audio
->version
== 1 )
4121 else if( audio
->version
== 2 )
4123 CHECK_LARGESIZE( audio
);
4127 static uint64_t isom_update_text_entry_size( isom_sample_entry_t
*description
)
4131 isom_text_entry_t
*text
= (isom_text_entry_t
*)description
;
4132 text
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 51 + (uint64_t)text
->font_name_length
;
4133 CHECK_LARGESIZE( text
);
4137 static uint64_t isom_update_ftab_size( isom_ftab_t
*ftab
)
4139 if( !ftab
|| !ftab
->list
)
4141 ftab
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 2;
4142 for( lsmash_entry_t
*entry
= ftab
->list
->head
; entry
; entry
= entry
->next
)
4144 isom_font_record_t
*data
= (isom_font_record_t
*)entry
->data
;
4145 ftab
->size
+= 3 + data
->font_name_length
;
4147 CHECK_LARGESIZE( ftab
);
4151 static uint64_t isom_update_tx3g_entry_size( isom_sample_entry_t
*description
)
4155 isom_tx3g_entry_t
*tx3g
= (isom_tx3g_entry_t
*)description
;
4156 tx3g
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 38 + isom_update_ftab_size( tx3g
->ftab
);
4157 CHECK_LARGESIZE( tx3g
);
4161 static uint64_t isom_update_stsd_size( isom_stsd_t
*stsd
)
4163 if( !stsd
|| !stsd
->list
)
4165 uint64_t size
= ISOM_LIST_FULLBOX_COMMON_SIZE
;
4166 for( lsmash_entry_t
*entry
= stsd
->list
->head
; entry
; entry
= entry
->next
)
4168 isom_sample_entry_t
*data
= (isom_sample_entry_t
*)entry
->data
;
4169 lsmash_codec_type_t sample_type
= (lsmash_codec_type_t
)data
->type
;
4170 if( lsmash_check_codec_type_identical( sample_type
, LSMASH_CODEC_TYPE_RAW
) )
4172 if( data
->manager
& LSMASH_VIDEO_DESCRIPTION
)
4173 size
+= isom_update_visual_entry_size( data
);
4174 else if( data
->manager
& LSMASH_AUDIO_DESCRIPTION
)
4175 size
+= isom_update_audio_entry_size( data
);
4178 static struct description_update_size_table_tag
4180 lsmash_codec_type_t type
;
4181 uint64_t (*func
)( isom_sample_entry_t
* );
4182 } description_update_size_table
[128] = { { LSMASH_CODEC_TYPE_INITIALIZER
, NULL
} };
4183 if( !description_update_size_table
[0].func
)
4185 /* Initialize the table. */
4187 #define ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( type, func ) \
4188 description_update_size_table[i++] = (struct description_update_size_table_tag){ type, func }
4189 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVC1_VIDEO
, isom_update_visual_entry_size
);
4190 #ifdef LSMASH_DEMUXER_ENABLED
4191 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_MP4V_VIDEO
, isom_update_visual_entry_size
);
4194 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVC2_VIDEO
, isom_update_visual_entry_size
);
4195 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_AVCP_VIDEO
, isom_update_visual_entry_size
);
4196 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_SVC1_VIDEO
, isom_update_visual_entry_size
);
4197 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_MVC1_VIDEO
, isom_update_visual_entry_size
);
4198 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_MVC2_VIDEO
, isom_update_visual_entry_size
);
4199 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_DRAC_VIDEO
, isom_update_visual_entry_size
);
4200 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_ENCV_VIDEO
, isom_update_visual_entry_size
);
4201 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_MJP2_VIDEO
, isom_update_visual_entry_size
);
4202 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_S263_VIDEO
, isom_update_visual_entry_size
);
4204 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_VC_1_VIDEO
, isom_update_visual_entry_size
);
4205 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_APCH_VIDEO
, isom_update_visual_entry_size
);
4206 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_APCN_VIDEO
, isom_update_visual_entry_size
);
4207 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_APCS_VIDEO
, isom_update_visual_entry_size
);
4208 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_APCO_VIDEO
, isom_update_visual_entry_size
);
4209 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_AP4H_VIDEO
, isom_update_visual_entry_size
);
4210 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_DVC_VIDEO
, isom_update_visual_entry_size
);
4211 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_DVCP_VIDEO
, isom_update_visual_entry_size
);
4212 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_DVPP_VIDEO
, isom_update_visual_entry_size
);
4213 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_DV5N_VIDEO
, isom_update_visual_entry_size
);
4214 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_DV5P_VIDEO
, isom_update_visual_entry_size
);
4215 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_DVH2_VIDEO
, isom_update_visual_entry_size
);
4216 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_DVH3_VIDEO
, isom_update_visual_entry_size
);
4217 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_DVH5_VIDEO
, isom_update_visual_entry_size
);
4218 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_DVH6_VIDEO
, isom_update_visual_entry_size
);
4219 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_DVHP_VIDEO
, isom_update_visual_entry_size
);
4220 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_DVHQ_VIDEO
, isom_update_visual_entry_size
);
4221 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_ULRA_VIDEO
, isom_update_visual_entry_size
);
4222 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_ULRG_VIDEO
, isom_update_visual_entry_size
);
4223 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_ULY2_VIDEO
, isom_update_visual_entry_size
);
4224 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_ULY0_VIDEO
, isom_update_visual_entry_size
);
4225 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_V210_VIDEO
, isom_update_visual_entry_size
);
4226 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_V216_VIDEO
, isom_update_visual_entry_size
);
4227 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_V308_VIDEO
, isom_update_visual_entry_size
);
4228 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_V408_VIDEO
, isom_update_visual_entry_size
);
4229 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_V410_VIDEO
, isom_update_visual_entry_size
);
4230 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_YUV2_VIDEO
, isom_update_visual_entry_size
);
4231 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_MP4A_AUDIO
, isom_update_audio_entry_size
);
4232 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_AC_3_AUDIO
, isom_update_audio_entry_size
);
4233 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_ALAC_AUDIO
, isom_update_audio_entry_size
);
4234 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSC_AUDIO
, isom_update_audio_entry_size
);
4235 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSE_AUDIO
, isom_update_audio_entry_size
);
4236 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSH_AUDIO
, isom_update_audio_entry_size
);
4237 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_DTSL_AUDIO
, isom_update_audio_entry_size
);
4238 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_EC_3_AUDIO
, isom_update_audio_entry_size
);
4239 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_SAMR_AUDIO
, isom_update_audio_entry_size
);
4240 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_SAWB_AUDIO
, isom_update_audio_entry_size
);
4241 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_ALAC_AUDIO
, isom_update_audio_entry_size
);
4242 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_MP4A_AUDIO
, isom_update_audio_entry_size
);
4243 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_23NI_AUDIO
, isom_update_audio_entry_size
);
4244 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_NONE_AUDIO
, isom_update_audio_entry_size
);
4245 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_LPCM_AUDIO
, isom_update_audio_entry_size
);
4246 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_SOWT_AUDIO
, isom_update_audio_entry_size
);
4247 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_TWOS_AUDIO
, isom_update_audio_entry_size
);
4248 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_FL32_AUDIO
, isom_update_audio_entry_size
);
4249 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_FL64_AUDIO
, isom_update_audio_entry_size
);
4250 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_IN24_AUDIO
, isom_update_audio_entry_size
);
4251 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_IN32_AUDIO
, isom_update_audio_entry_size
);
4252 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_NOT_SPECIFIED
, isom_update_audio_entry_size
);
4254 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_DRA1_AUDIO
, isom_update_audio_entry_size
);
4255 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_ENCA_AUDIO
, isom_update_audio_entry_size
);
4256 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_G719_AUDIO
, isom_update_audio_entry_size
);
4257 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_G726_AUDIO
, isom_update_audio_entry_size
);
4258 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_M4AE_AUDIO
, isom_update_audio_entry_size
);
4259 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_MLPA_AUDIO
, isom_update_audio_entry_size
);
4260 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_RAW_AUDIO
, isom_update_audio_entry_size
);
4261 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_SAWP_AUDIO
, isom_update_audio_entry_size
);
4262 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_SEVC_AUDIO
, isom_update_audio_entry_size
);
4263 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_SQCP_AUDIO
, isom_update_audio_entry_size
);
4264 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_SSMV_AUDIO
, isom_update_audio_entry_size
);
4265 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_TWOS_AUDIO
, isom_update_audio_entry_size
);
4267 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_TX3G_TEXT
, isom_update_tx3g_entry_size
);
4268 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( QT_CODEC_TYPE_TEXT_TEXT
, isom_update_text_entry_size
);
4270 ADD_DESCRIPTION_UPDATE_SIZE_TABLE_ELEMENT( ISOM_CODEC_TYPE_MP4S_SYSTEM
, isom_update_mp4s_entry_size
);
4273 for( int i
= 0; description_update_size_table
[i
].func
; i
++ )
4274 if( lsmash_check_codec_type_identical( sample_type
, description_update_size_table
[i
].type
) )
4276 size
+= description_update_size_table
[i
].func( data
);
4281 CHECK_LARGESIZE( stsd
);
4285 static uint64_t isom_update_stts_size( isom_stts_t
*stts
)
4287 if( !stts
|| !stts
->list
)
4289 stts
->size
= ISOM_LIST_FULLBOX_COMMON_SIZE
+ (uint64_t)stts
->list
->entry_count
* 8;
4290 CHECK_LARGESIZE( stts
);
4294 static uint64_t isom_update_ctts_size( isom_ctts_t
*ctts
)
4296 if( !ctts
|| !ctts
->list
)
4298 ctts
->size
= ISOM_LIST_FULLBOX_COMMON_SIZE
+ (uint64_t)ctts
->list
->entry_count
* 8;
4299 CHECK_LARGESIZE( ctts
);
4303 static uint64_t isom_update_cslg_size( isom_cslg_t
*cslg
)
4307 cslg
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 20;
4308 CHECK_LARGESIZE( cslg
);
4312 static uint64_t isom_update_stsz_size( isom_stsz_t
*stsz
)
4316 stsz
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 8 + ( stsz
->list
? (uint64_t)stsz
->list
->entry_count
* 4 : 0 );
4317 CHECK_LARGESIZE( stsz
);
4321 static uint64_t isom_update_stss_size( isom_stss_t
*stss
)
4323 if( !stss
|| !stss
->list
)
4325 stss
->size
= ISOM_LIST_FULLBOX_COMMON_SIZE
+ (uint64_t)stss
->list
->entry_count
* 4;
4326 CHECK_LARGESIZE( stss
);
4330 static uint64_t isom_update_stps_size( isom_stps_t
*stps
)
4332 if( !stps
|| !stps
->list
)
4334 stps
->size
= ISOM_LIST_FULLBOX_COMMON_SIZE
+ (uint64_t)stps
->list
->entry_count
* 4;
4335 CHECK_LARGESIZE( stps
);
4339 static uint64_t isom_update_sdtp_size( isom_sdtp_t
*sdtp
)
4341 if( !sdtp
|| !sdtp
->list
)
4343 sdtp
->size
= ISOM_FULLBOX_COMMON_SIZE
+ (uint64_t)sdtp
->list
->entry_count
;
4344 CHECK_LARGESIZE( sdtp
);
4348 static uint64_t isom_update_stsc_size( isom_stsc_t
*stsc
)
4350 if( !stsc
|| !stsc
->list
)
4352 stsc
->size
= ISOM_LIST_FULLBOX_COMMON_SIZE
+ (uint64_t)stsc
->list
->entry_count
* 12;
4353 CHECK_LARGESIZE( stsc
);
4357 static uint64_t isom_update_stco_size( isom_stco_t
*stco
)
4359 if( !stco
|| !stco
->list
)
4361 stco
->size
= ISOM_LIST_FULLBOX_COMMON_SIZE
+ (uint64_t)stco
->list
->entry_count
* (stco
->large_presentation
? 8 : 4);
4362 CHECK_LARGESIZE( stco
);
4366 static uint64_t isom_update_sbgp_size( isom_sbgp_entry_t
*sbgp
)
4368 if( !sbgp
|| !sbgp
->list
)
4370 sbgp
->size
= ISOM_LIST_FULLBOX_COMMON_SIZE
+ 4 + (uint64_t)sbgp
->list
->entry_count
* 8;
4371 CHECK_LARGESIZE( sbgp
);
4375 static uint64_t isom_update_sgpd_size( isom_sgpd_entry_t
*sgpd
)
4377 if( !sgpd
|| !sgpd
->list
)
4379 uint64_t size
= ISOM_LIST_FULLBOX_COMMON_SIZE
+ (1 + (sgpd
->version
== 1)) * 4;
4380 size
+= (uint64_t)sgpd
->list
->entry_count
* ((sgpd
->version
== 1) && !sgpd
->default_length
) * 4;
4381 switch( sgpd
->grouping_type
)
4383 case ISOM_GROUP_TYPE_RAP
:
4384 size
+= sgpd
->list
->entry_count
;
4386 case ISOM_GROUP_TYPE_ROLL
:
4387 size
+= (uint64_t)sgpd
->list
->entry_count
* 2;
4390 /* We don't consider other grouping types currently. */
4394 CHECK_LARGESIZE( sgpd
);
4398 static uint64_t isom_update_stbl_size( isom_stbl_t
*stbl
)
4402 stbl
->size
= ISOM_BASEBOX_COMMON_SIZE
4403 + isom_update_stsd_size( stbl
->stsd
)
4404 + isom_update_stts_size( stbl
->stts
)
4405 + isom_update_ctts_size( stbl
->ctts
)
4406 + isom_update_cslg_size( stbl
->cslg
)
4407 + isom_update_stsz_size( stbl
->stsz
)
4408 + isom_update_stss_size( stbl
->stss
)
4409 + isom_update_stps_size( stbl
->stps
)
4410 + isom_update_sdtp_size( stbl
->sdtp
)
4411 + isom_update_stsc_size( stbl
->stsc
)
4412 + isom_update_stco_size( stbl
->stco
);
4413 if( stbl
->sgpd_list
)
4414 for( lsmash_entry_t
*entry
= stbl
->sgpd_list
->head
; entry
; entry
= entry
->next
)
4415 stbl
->size
+= isom_update_sgpd_size( (isom_sgpd_entry_t
*)entry
->data
);
4416 if( stbl
->sbgp_list
)
4417 for( lsmash_entry_t
*entry
= stbl
->sbgp_list
->head
; entry
; entry
= entry
->next
)
4418 stbl
->size
+= isom_update_sbgp_size( (isom_sbgp_entry_t
*)entry
->data
);
4419 CHECK_LARGESIZE( stbl
);
4423 static uint64_t isom_update_minf_size( isom_minf_t
*minf
)
4427 minf
->size
= ISOM_BASEBOX_COMMON_SIZE
4428 + isom_update_vmhd_size( minf
->vmhd
)
4429 + isom_update_smhd_size( minf
->smhd
)
4430 + isom_update_hmhd_size( minf
->hmhd
)
4431 + isom_update_nmhd_size( minf
->nmhd
)
4432 + isom_update_gmhd_size( minf
->gmhd
)
4433 + isom_update_hdlr_size( minf
->hdlr
)
4434 + isom_update_dinf_size( minf
->dinf
)
4435 + isom_update_stbl_size( minf
->stbl
);
4436 CHECK_LARGESIZE( minf
);
4440 static uint64_t isom_update_mdia_size( isom_mdia_t
*mdia
)
4444 mdia
->size
= ISOM_BASEBOX_COMMON_SIZE
4445 + isom_update_mdhd_size( mdia
->mdhd
)
4446 + isom_update_hdlr_size( mdia
->hdlr
)
4447 + isom_update_minf_size( mdia
->minf
);
4448 CHECK_LARGESIZE( mdia
);
4452 static uint64_t isom_update_chpl_size( isom_chpl_t
*chpl
)
4456 chpl
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 4 * (chpl
->version
== 1) + 1;
4457 for( lsmash_entry_t
*entry
= chpl
->list
->head
; entry
; entry
= entry
->next
)
4459 isom_chpl_entry_t
*data
= (isom_chpl_entry_t
*)entry
->data
;
4460 chpl
->size
+= 9 + data
->chapter_name_length
;
4462 CHECK_LARGESIZE( chpl
);
4466 static uint64_t isom_update_mean_size( isom_mean_t
*mean
)
4470 mean
->size
= ISOM_FULLBOX_COMMON_SIZE
+ mean
->meaning_string_length
;
4471 CHECK_LARGESIZE( mean
);
4475 static uint64_t isom_update_name_size( isom_name_t
*name
)
4479 name
->size
= ISOM_FULLBOX_COMMON_SIZE
+ name
->name_length
;
4480 CHECK_LARGESIZE( name
);
4484 static uint64_t isom_update_data_size( isom_data_t
*data
)
4488 data
->size
= ISOM_BASEBOX_COMMON_SIZE
+ 8 + data
->value_length
;
4489 CHECK_LARGESIZE( data
);
4493 static uint64_t isom_update_metaitem_size( isom_metaitem_t
*metaitem
)
4497 metaitem
->size
= ISOM_BASEBOX_COMMON_SIZE
4498 + isom_update_mean_size( metaitem
->mean
)
4499 + isom_update_name_size( metaitem
->name
)
4500 + isom_update_data_size( metaitem
->data
);
4501 CHECK_LARGESIZE( metaitem
);
4502 return metaitem
->size
;
4505 static uint64_t isom_update_ilst_size( isom_ilst_t
*ilst
)
4509 ilst
->size
= ISOM_BASEBOX_COMMON_SIZE
;
4510 for( lsmash_entry_t
*entry
= ilst
->item_list
->head
; entry
; entry
= entry
->next
)
4511 ilst
->size
+= isom_update_metaitem_size( (isom_metaitem_t
*)entry
->data
);
4512 CHECK_LARGESIZE( ilst
);
4516 static uint64_t isom_update_meta_size( isom_meta_t
*meta
)
4520 meta
->size
= ISOM_FULLBOX_COMMON_SIZE
4521 + isom_update_hdlr_size( meta
->hdlr
)
4522 + isom_update_dinf_size( meta
->dinf
)
4523 + isom_update_ilst_size( meta
->ilst
);
4524 CHECK_LARGESIZE( meta
);
4528 static uint64_t isom_update_cprt_size( isom_cprt_t
*cprt
)
4532 cprt
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 2 + cprt
->notice_length
;
4533 CHECK_LARGESIZE( cprt
);
4537 static uint64_t isom_update_udta_size( isom_udta_t
*udta_moov
, isom_udta_t
*udta_trak
)
4539 isom_udta_t
*udta
= udta_trak
? udta_trak
: udta_moov
? udta_moov
: NULL
;
4542 udta
->size
= ISOM_BASEBOX_COMMON_SIZE
4543 + (udta_moov
? isom_update_chpl_size( udta
->chpl
) : 0)
4544 + isom_update_meta_size( udta
->meta
);
4545 if( udta
->cprt_list
)
4546 for( lsmash_entry_t
*entry
= udta
->cprt_list
->head
; entry
; entry
= entry
->next
)
4547 udta
->size
+= isom_update_cprt_size( (isom_cprt_t
*)entry
->data
);
4548 CHECK_LARGESIZE( udta
);
4552 static uint64_t isom_update_trak_entry_size( isom_trak_entry_t
*trak
)
4556 trak
->size
= ISOM_BASEBOX_COMMON_SIZE
4557 + isom_update_tkhd_size( trak
->tkhd
)
4558 + isom_update_tapt_size( trak
->tapt
)
4559 + isom_update_edts_size( trak
->edts
)
4560 + isom_update_tref_size( trak
->tref
)
4561 + isom_update_mdia_size( trak
->mdia
)
4562 + isom_update_udta_size( NULL
, trak
->udta
)
4563 + isom_update_meta_size( trak
->meta
);
4564 CHECK_LARGESIZE( trak
);
4568 static uint64_t isom_update_mehd_size( isom_mehd_t
*mehd
)
4572 if( mehd
->fragment_duration
> UINT32_MAX
)
4574 mehd
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 4 * (1 + (mehd
->version
== 1));
4575 CHECK_LARGESIZE( mehd
);
4579 static uint64_t isom_update_trex_entry_size( isom_trex_entry_t
*trex
)
4583 trex
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 20;
4584 CHECK_LARGESIZE( trex
);
4588 static uint64_t isom_update_mvex_size( isom_mvex_t
*mvex
)
4592 mvex
->size
= ISOM_BASEBOX_COMMON_SIZE
;
4593 if( mvex
->trex_list
)
4594 for( lsmash_entry_t
*entry
= mvex
->trex_list
->head
; entry
; entry
= entry
->next
)
4596 isom_trex_entry_t
*trex
= (isom_trex_entry_t
*)entry
->data
;
4597 mvex
->size
+= isom_update_trex_entry_size( trex
);
4599 if( mvex
->root
->bs
->stream
!= stdout
)
4600 mvex
->size
+= mvex
->mehd
? isom_update_mehd_size( mvex
->mehd
) : 20; /* 20 bytes is of placeholder. */
4601 CHECK_LARGESIZE( mvex
);
4605 static int isom_update_moov_size( isom_moov_t
*moov
)
4609 moov
->size
= ISOM_BASEBOX_COMMON_SIZE
4610 + isom_update_mvhd_size( moov
->mvhd
)
4611 + isom_update_iods_size( moov
->iods
)
4612 + isom_update_udta_size( moov
->udta
, NULL
)
4613 + isom_update_ctab_size( moov
->ctab
)
4614 + isom_update_meta_size( moov
->meta
)
4615 + isom_update_mvex_size( moov
->mvex
);
4616 if( moov
->trak_list
)
4617 for( lsmash_entry_t
*entry
= moov
->trak_list
->head
; entry
; entry
= entry
->next
)
4619 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)entry
->data
;
4620 moov
->size
+= isom_update_trak_entry_size( trak
);
4622 CHECK_LARGESIZE( moov
);
4626 static uint64_t isom_update_mfhd_size( isom_mfhd_t
*mfhd
)
4630 mfhd
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 4;
4631 CHECK_LARGESIZE( mfhd
);
4635 static uint64_t isom_update_tfhd_size( isom_tfhd_t
*tfhd
)
4639 tfhd
->size
= ISOM_FULLBOX_COMMON_SIZE
4641 + 8 * !!( tfhd
->flags
& ISOM_TF_FLAGS_BASE_DATA_OFFSET_PRESENT
)
4642 + 4 * !!( tfhd
->flags
& ISOM_TF_FLAGS_SAMPLE_DESCRIPTION_INDEX_PRESENT
)
4643 + 4 * !!( tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT
)
4644 + 4 * !!( tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_SAMPLE_SIZE_PRESENT
)
4645 + 4 * !!( tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_SAMPLE_FLAGS_PRESENT
);
4646 CHECK_LARGESIZE( tfhd
);
4650 static uint64_t isom_update_tfdt_size( isom_tfdt_t
*tfdt
)
4654 tfdt
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 4 * (1 + (tfdt
->version
== 1));
4655 CHECK_LARGESIZE( tfdt
);
4659 static uint64_t isom_update_trun_entry_size( isom_trun_entry_t
*trun
)
4663 trun
->size
= ISOM_FULLBOX_COMMON_SIZE
4665 + 4 * !!( trun
->flags
& ISOM_TR_FLAGS_DATA_OFFSET_PRESENT
)
4666 + 4 * !!( trun
->flags
& ISOM_TR_FLAGS_FIRST_SAMPLE_FLAGS_PRESENT
);
4667 uint64_t row_size
= 4 * !!( trun
->flags
& ISOM_TR_FLAGS_SAMPLE_DURATION_PRESENT
)
4668 + 4 * !!( trun
->flags
& ISOM_TR_FLAGS_SAMPLE_SIZE_PRESENT
)
4669 + 4 * !!( trun
->flags
& ISOM_TR_FLAGS_SAMPLE_FLAGS_PRESENT
)
4670 + 4 * !!( trun
->flags
& ISOM_TR_FLAGS_SAMPLE_COMPOSITION_TIME_OFFSET_PRESENT
);
4671 trun
->size
+= row_size
* trun
->sample_count
;
4672 CHECK_LARGESIZE( trun
);
4676 static uint64_t isom_update_traf_entry_size( isom_traf_entry_t
*traf
)
4680 traf
->size
= ISOM_BASEBOX_COMMON_SIZE
4681 + isom_update_tfhd_size( traf
->tfhd
)
4682 + isom_update_tfdt_size( traf
->tfdt
)
4683 + isom_update_sdtp_size( traf
->sdtp
);
4684 if( traf
->trun_list
)
4685 for( lsmash_entry_t
*entry
= traf
->trun_list
->head
; entry
; entry
= entry
->next
)
4687 isom_trun_entry_t
*trun
= (isom_trun_entry_t
*)entry
->data
;
4688 traf
->size
+= isom_update_trun_entry_size( trun
);
4690 CHECK_LARGESIZE( traf
);
4694 static int isom_update_moof_entry_size( isom_moof_entry_t
*moof
)
4698 moof
->size
= ISOM_BASEBOX_COMMON_SIZE
+ isom_update_mfhd_size( moof
->mfhd
);
4699 if( moof
->traf_list
)
4700 for( lsmash_entry_t
*entry
= moof
->traf_list
->head
; entry
; entry
= entry
->next
)
4702 isom_traf_entry_t
*traf
= (isom_traf_entry_t
*)entry
->data
;
4703 moof
->size
+= isom_update_traf_entry_size( traf
);
4705 CHECK_LARGESIZE( moof
);
4709 static uint64_t isom_update_tfra_entry_size( isom_tfra_entry_t
*tfra
)
4713 tfra
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 12;
4714 uint32_t entry_size
= 8 * (1 + (tfra
->version
== 1))
4715 + tfra
->length_size_of_traf_num
+ 1
4716 + tfra
->length_size_of_trun_num
+ 1
4717 + tfra
->length_size_of_sample_num
+ 1;
4718 tfra
->size
+= entry_size
* tfra
->number_of_entry
;
4719 CHECK_LARGESIZE( tfra
);
4723 static uint64_t isom_update_mfro_size( isom_mfro_t
*mfro
)
4727 mfro
->size
= ISOM_FULLBOX_COMMON_SIZE
+ 4;
4728 CHECK_LARGESIZE( mfro
);
4732 static int isom_update_mfra_size( isom_mfra_t
*mfra
)
4736 mfra
->size
= ISOM_BASEBOX_COMMON_SIZE
;
4737 if( mfra
->tfra_list
)
4738 for( lsmash_entry_t
*entry
= mfra
->tfra_list
->head
; entry
; entry
= entry
->next
)
4740 isom_tfra_entry_t
*tfra
= (isom_tfra_entry_t
*)entry
->data
;
4741 mfra
->size
+= isom_update_tfra_entry_size( tfra
);
4743 CHECK_LARGESIZE( mfra
);
4746 mfra
->size
+= isom_update_mfro_size( mfra
->mfro
);
4747 mfra
->mfro
->length
= mfra
->size
;
4752 static uint64_t isom_update_extension_boxes( void *box
)
4756 lsmash_entry_list_t
*extensions
= &((isom_box_t
*)box
)->extensions
;
4757 for( lsmash_entry_t
*entry
= extensions
->head
; entry
; entry
= entry
->next
)
4759 isom_extension_box_t
*ext
= (isom_extension_box_t
*)entry
->data
;
4762 if( ext
->format
== EXTENSION_FORMAT_BINARY
)
4767 static struct update_size_table_tag
4769 lsmash_box_type_t type
;
4770 uint64_t (*func
)( void * );
4771 } update_size_table
[32] = { { LSMASH_BOX_TYPE_INITIALIZER
, NULL
} };
4772 if( !update_size_table
[0].func
)
4774 /* Initialize the table. */
4776 #define ADD_UPDATE_SIZE_TABLE_ELEMENT( type, func ) update_size_table[i++] = (struct update_size_table_tag){ type, (uint64_t (*)( void * ))func }
4777 ADD_UPDATE_SIZE_TABLE_ELEMENT( ISOM_BOX_TYPE_ESDS
, isom_update_esds_size
);
4778 ADD_UPDATE_SIZE_TABLE_ELEMENT( ISOM_BOX_TYPE_BTRT
, isom_update_btrt_size
);
4779 ADD_UPDATE_SIZE_TABLE_ELEMENT( ISOM_BOX_TYPE_CLAP
, isom_update_clap_size
);
4780 ADD_UPDATE_SIZE_TABLE_ELEMENT( ISOM_BOX_TYPE_PASP
, isom_update_pasp_size
);
4781 ADD_UPDATE_SIZE_TABLE_ELEMENT( ISOM_BOX_TYPE_STSL
, isom_update_stsl_size
);
4782 ADD_UPDATE_SIZE_TABLE_ELEMENT( ISOM_BOX_TYPE_COLR
, isom_update_colr_size
);
4783 ADD_UPDATE_SIZE_TABLE_ELEMENT( QT_BOX_TYPE_CHAN
, isom_update_chan_size
);
4784 ADD_UPDATE_SIZE_TABLE_ELEMENT( QT_BOX_TYPE_COLR
, isom_update_colr_size
);
4785 ADD_UPDATE_SIZE_TABLE_ELEMENT( QT_BOX_TYPE_CSPC
, isom_update_cspc_size
);
4786 ADD_UPDATE_SIZE_TABLE_ELEMENT( QT_BOX_TYPE_ENDA
, isom_update_enda_size
);
4787 ADD_UPDATE_SIZE_TABLE_ELEMENT( QT_BOX_TYPE_ESDS
, isom_update_esds_size
);
4788 ADD_UPDATE_SIZE_TABLE_ELEMENT( QT_BOX_TYPE_FIEL
, isom_update_fiel_size
);
4789 ADD_UPDATE_SIZE_TABLE_ELEMENT( QT_BOX_TYPE_FRMA
, isom_update_frma_size
);
4790 ADD_UPDATE_SIZE_TABLE_ELEMENT( QT_BOX_TYPE_GAMA
, isom_update_gama_size
);
4791 ADD_UPDATE_SIZE_TABLE_ELEMENT( QT_BOX_TYPE_GLBL
, isom_update_glbl_size
);
4792 ADD_UPDATE_SIZE_TABLE_ELEMENT( QT_BOX_TYPE_SGBT
, isom_update_sgbt_size
);
4793 ADD_UPDATE_SIZE_TABLE_ELEMENT( QT_BOX_TYPE_WAVE
, isom_update_wave_size
);
4794 ADD_UPDATE_SIZE_TABLE_ELEMENT( QT_BOX_TYPE_TERMINATOR
, isom_update_terminator_size
);
4795 ADD_UPDATE_SIZE_TABLE_ELEMENT( LSMASH_BOX_TYPE_UNSPECIFIED
, NULL
);
4796 #undef ADD_UPDATE_SIZE_TABLE_ELEMENT
4798 uint64_t (*update_size_func
)( void * ) = (uint64_t (*)( void * ))isom_update_unknown_box_size
;
4799 for( int i
= 0; update_size_table
[i
].func
; i
++ )
4800 if( lsmash_check_box_type_identical( ext
->type
, update_size_table
[i
].type
) )
4802 update_size_func
= update_size_table
[i
].func
;
4805 size
+= update_size_func( ext
->form
.box
);
4810 /*******************************
4812 *******************************/
4814 /*---- track manipulators ----*/
4816 void lsmash_delete_track( lsmash_root_t
*root
, uint32_t track_ID
)
4818 if( !root
|| !root
->moov
|| !root
->moov
->trak_list
)
4820 for( lsmash_entry_t
*entry
= root
->moov
->trak_list
->head
; entry
; entry
= entry
->next
)
4822 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)entry
->data
;
4823 if( !trak
|| !trak
->tkhd
)
4825 if( trak
->tkhd
->track_ID
== track_ID
)
4827 lsmash_remove_entry_direct( root
->moov
->trak_list
, entry
, isom_remove_trak
);
4833 uint32_t lsmash_create_track( lsmash_root_t
*root
, lsmash_media_type media_type
)
4835 isom_trak_entry_t
*trak
= isom_add_trak( root
);
4838 if( isom_add_tkhd( trak
, media_type
)
4839 || isom_add_mdia( trak
)
4840 || isom_add_mdhd( trak
->mdia
, root
->qt_compatible
? 0 : ISOM_LANGUAGE_CODE_UNDEFINED
)
4841 || isom_add_minf( trak
->mdia
)
4842 || isom_add_stbl( trak
->mdia
->minf
)
4843 || isom_add_dinf( trak
->mdia
->minf
)
4844 || isom_add_dref( trak
->mdia
->minf
->dinf
)
4845 || isom_add_stsd( trak
->mdia
->minf
->stbl
)
4846 || isom_add_stts( trak
->mdia
->minf
->stbl
)
4847 || isom_add_stsc( trak
->mdia
->minf
->stbl
)
4848 || isom_add_stco( trak
->mdia
->minf
->stbl
)
4849 || isom_add_stsz( trak
->mdia
->minf
->stbl
) )
4851 if( isom_add_hdlr( trak
->mdia
, NULL
, NULL
, media_type
) )
4853 if( root
->qt_compatible
&& isom_add_hdlr( NULL
, NULL
, trak
->mdia
->minf
, QT_REFERENCE_HANDLER_TYPE_URL
) )
4855 switch( media_type
)
4857 case ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK
:
4858 if( isom_add_vmhd( trak
->mdia
->minf
) )
4861 case ISOM_MEDIA_HANDLER_TYPE_AUDIO_TRACK
:
4862 if( isom_add_smhd( trak
->mdia
->minf
) )
4865 case ISOM_MEDIA_HANDLER_TYPE_HINT_TRACK
:
4866 if( isom_add_hmhd( trak
->mdia
->minf
) )
4869 case ISOM_MEDIA_HANDLER_TYPE_TEXT_TRACK
:
4870 if( root
->qt_compatible
|| root
->itunes_movie
)
4872 if( isom_add_gmhd( trak
->mdia
->minf
)
4873 || isom_add_gmin( trak
->mdia
->minf
->gmhd
)
4874 || isom_add_text( trak
->mdia
->minf
->gmhd
) )
4878 return 0; /* We support only reference text media track for chapter yet. */
4881 if( isom_add_nmhd( trak
->mdia
->minf
) )
4885 return trak
->tkhd
->track_ID
;
4888 uint32_t lsmash_get_track_ID( lsmash_root_t
*root
, uint32_t track_number
)
4890 if( !root
|| !root
->moov
)
4892 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)lsmash_get_entry_data( root
->moov
->trak_list
, track_number
);
4893 if( !trak
|| !trak
->tkhd
)
4895 return trak
->tkhd
->track_ID
;
4898 void lsmash_initialize_track_parameters( lsmash_track_parameters_t
*param
)
4900 memset( param
, 0, sizeof(lsmash_track_parameters_t
) );
4901 param
->audio_volume
= 0x0100;
4902 param
->matrix
[0] = 0x00010000;
4903 param
->matrix
[4] = 0x00010000;
4904 param
->matrix
[8] = 0x40000000;
4907 int lsmash_set_track_parameters( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_track_parameters_t
*param
)
4909 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
4910 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->hdlr
|| !root
->moov
->mvhd
)
4912 /* Prepare Track Aperture Modes if required. */
4913 if( root
->qt_compatible
&& param
->aperture_modes
)
4915 if( !trak
->tapt
&& isom_add_tapt( trak
) )
4917 isom_tapt_t
*tapt
= trak
->tapt
;
4918 if( (!tapt
->clef
&& isom_add_clef( tapt
))
4919 || (!tapt
->prof
&& isom_add_prof( tapt
))
4920 || (!tapt
->enof
&& isom_add_enof( tapt
)) )
4924 isom_remove_tapt( trak
->tapt
);
4925 /* Set up Track Header. */
4926 uint32_t media_type
= trak
->mdia
->hdlr
->componentSubtype
;
4927 isom_tkhd_t
*tkhd
= trak
->tkhd
;
4928 tkhd
->flags
= param
->mode
;
4929 tkhd
->track_ID
= param
->track_ID
? param
->track_ID
: tkhd
->track_ID
;
4930 tkhd
->duration
= !trak
->edts
|| !trak
->edts
->elst
? param
->duration
: tkhd
->duration
;
4932 * alternate_group, layer, volume and matrix
4933 * According to 14496-14, these value are all set to defaut values in 14496-12.
4934 * And when a file is read as an MPEG-4 file, these values shall be ignored.
4935 * If a file complies with other specifications, then those fields may have non-default values
4936 * as required by those other specifications. */
4937 if( param
->alternate_group
)
4939 if( root
->qt_compatible
|| root
->itunes_movie
|| root
->max_3gpp_version
>= 4 )
4940 tkhd
->alternate_group
= param
->alternate_group
;
4943 tkhd
->alternate_group
= 0;
4944 lsmash_log( LSMASH_LOG_WARNING
, "alternate_group is specified but not compatible with any of the brands. It won't be set.\n" );
4948 tkhd
->alternate_group
= 0;
4949 if( root
->qt_compatible
|| root
->itunes_movie
)
4951 tkhd
->layer
= media_type
== ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK
? param
->video_layer
: 0;
4952 tkhd
->volume
= media_type
== ISOM_MEDIA_HANDLER_TYPE_AUDIO_TRACK
? param
->audio_volume
: 0;
4953 if( media_type
== ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK
)
4954 for( int i
= 0; i
< 9; i
++ )
4955 tkhd
->matrix
[i
] = param
->matrix
[i
];
4957 for( int i
= 0; i
< 9; i
++ )
4958 tkhd
->matrix
[i
] = 0;
4963 tkhd
->volume
= media_type
== ISOM_MEDIA_HANDLER_TYPE_AUDIO_TRACK
? 0x0100 : 0;
4964 tkhd
->matrix
[0] = 0x00010000;
4965 tkhd
->matrix
[1] = tkhd
->matrix
[2] = tkhd
->matrix
[3] = 0;
4966 tkhd
->matrix
[4] = 0x00010000;
4967 tkhd
->matrix
[5] = tkhd
->matrix
[6] = tkhd
->matrix
[7] = 0;
4968 tkhd
->matrix
[8] = 0x40000000;
4970 /* visual presentation size */
4971 tkhd
->width
= media_type
== ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK
? param
->display_width
: 0;
4972 tkhd
->height
= media_type
== ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK
? param
->display_height
: 0;
4973 /* Update next_track_ID if needed. */
4974 if( root
->moov
->mvhd
->next_track_ID
<= tkhd
->track_ID
)
4975 root
->moov
->mvhd
->next_track_ID
= tkhd
->track_ID
+ 1;
4979 int lsmash_get_track_parameters( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_track_parameters_t
*param
)
4981 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
4984 isom_tkhd_t
*tkhd
= trak
->tkhd
;
4985 param
->mode
= tkhd
->flags
;
4986 param
->track_ID
= tkhd
->track_ID
;
4987 param
->duration
= tkhd
->duration
;
4988 param
->video_layer
= tkhd
->layer
;
4989 param
->alternate_group
= tkhd
->alternate_group
;
4990 param
->audio_volume
= tkhd
->volume
;
4991 for( int i
= 0; i
< 9; i
++ )
4992 param
->matrix
[i
] = tkhd
->matrix
[i
];
4993 param
->display_width
= tkhd
->width
;
4994 param
->display_height
= tkhd
->height
;
4995 param
->aperture_modes
= !!trak
->tapt
;
4999 static int isom_set_media_handler_name( lsmash_root_t
*root
, uint32_t track_ID
, char *handler_name
)
5001 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
5002 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->hdlr
)
5004 isom_hdlr_t
*hdlr
= trak
->mdia
->hdlr
;
5005 uint8_t *name
= NULL
;
5006 uint32_t name_length
= strlen( handler_name
) + root
->isom_compatible
+ root
->qt_compatible
;
5007 if( root
->qt_compatible
)
5008 name_length
= LSMASH_MIN( name_length
, 255 );
5009 if( name_length
> hdlr
->componentName_length
&& hdlr
->componentName
)
5010 name
= realloc( hdlr
->componentName
, name_length
);
5011 else if( !hdlr
->componentName
)
5012 name
= malloc( name_length
);
5014 name
= hdlr
->componentName
;
5017 if( root
->qt_compatible
)
5018 name
[0] = name_length
& 0xff;
5019 memcpy( name
+ root
->qt_compatible
, handler_name
, strlen( handler_name
) );
5020 if( root
->isom_compatible
)
5021 name
[name_length
- 1] = 0;
5022 hdlr
->componentName
= name
;
5023 hdlr
->componentName_length
= name_length
;
5027 static int isom_set_data_handler_name( lsmash_root_t
*root
, uint32_t track_ID
, char *handler_name
)
5029 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
5030 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->hdlr
)
5032 isom_hdlr_t
*hdlr
= trak
->mdia
->minf
->hdlr
;
5033 uint8_t *name
= NULL
;
5034 uint32_t name_length
= strlen( handler_name
) + root
->isom_compatible
+ root
->qt_compatible
;
5035 if( root
->qt_compatible
)
5036 name_length
= LSMASH_MIN( name_length
, 255 );
5037 if( name_length
> hdlr
->componentName_length
&& hdlr
->componentName
)
5038 name
= realloc( hdlr
->componentName
, name_length
);
5039 else if( !hdlr
->componentName
)
5040 name
= malloc( name_length
);
5042 name
= hdlr
->componentName
;
5045 if( root
->qt_compatible
)
5046 name
[0] = name_length
& 0xff;
5047 memcpy( name
+ root
->qt_compatible
, handler_name
, strlen( handler_name
) );
5048 if( root
->isom_compatible
)
5049 name
[name_length
- 1] = 0;
5050 hdlr
->componentName
= name
;
5051 hdlr
->componentName_length
= name_length
;
5055 uint32_t lsmash_get_media_timescale( lsmash_root_t
*root
, uint32_t track_ID
)
5057 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
5058 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->mdhd
)
5060 return trak
->mdia
->mdhd
->timescale
;
5063 uint64_t lsmash_get_media_duration( lsmash_root_t
*root
, uint32_t track_ID
)
5065 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
5066 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->mdhd
)
5068 return trak
->mdia
->mdhd
->duration
;
5071 uint64_t lsmash_get_track_duration( lsmash_root_t
*root
, uint32_t track_ID
)
5073 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
5074 if( !trak
|| !trak
->tkhd
)
5076 return trak
->tkhd
->duration
;
5079 uint32_t lsmash_get_last_sample_delta( lsmash_root_t
*root
, uint32_t track_ID
)
5081 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
5082 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
5083 || !trak
->mdia
->minf
->stbl
->stts
|| !trak
->mdia
->minf
->stbl
->stts
->list
5084 || !trak
->mdia
->minf
->stbl
->stts
->list
->tail
|| !trak
->mdia
->minf
->stbl
->stts
->list
->tail
->data
)
5086 return ((isom_stts_entry_t
*)trak
->mdia
->minf
->stbl
->stts
->list
->tail
->data
)->sample_delta
;
5089 uint32_t lsmash_get_start_time_offset( lsmash_root_t
*root
, uint32_t track_ID
)
5091 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
5092 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
5093 || !trak
->mdia
->minf
->stbl
->ctts
|| !trak
->mdia
->minf
->stbl
->ctts
->list
5094 || !trak
->mdia
->minf
->stbl
->ctts
->list
->head
|| !trak
->mdia
->minf
->stbl
->ctts
->list
->head
->data
)
5096 return ((isom_ctts_entry_t
*)trak
->mdia
->minf
->stbl
->ctts
->list
->head
->data
)->sample_offset
;
5099 uint32_t lsmash_get_composition_to_decode_shift( lsmash_root_t
*root
, uint32_t track_ID
)
5101 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
5102 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
)
5104 uint32_t sample_count
= isom_get_sample_count( trak
);
5105 if( sample_count
== 0 )
5107 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
5108 if( !stbl
->stts
|| !stbl
->stts
->list
|| !stbl
->ctts
|| !stbl
->ctts
->list
)
5110 if( !(root
->max_isom_version
>= 4 && stbl
->ctts
->version
== 1) && !root
->qt_compatible
)
5111 return 0; /* This movie shall not have composition to decode timeline shift. */
5112 lsmash_entry_t
*stts_entry
= stbl
->stts
->list
->head
;
5113 lsmash_entry_t
*ctts_entry
= stbl
->ctts
->list
->head
;
5114 if( !stts_entry
|| !ctts_entry
)
5118 uint32_t ctd_shift
= 0;
5121 for( uint32_t k
= 0; k
< sample_count
; i
++ )
5123 isom_stts_entry_t
*stts_data
= (isom_stts_entry_t
*)stts_entry
->data
;
5124 isom_ctts_entry_t
*ctts_data
= (isom_ctts_entry_t
*)ctts_entry
->data
;
5125 if( !stts_data
|| !ctts_data
)
5127 cts
= dts
+ (int32_t)ctts_data
->sample_offset
;
5128 if( dts
> cts
+ ctd_shift
)
5129 ctd_shift
= dts
- cts
;
5130 dts
+= stts_data
->sample_delta
;
5131 if( ++i
== stts_data
->sample_count
)
5133 stts_entry
= stts_entry
->next
;
5138 if( ++j
== ctts_data
->sample_count
)
5140 ctts_entry
= ctts_entry
->next
;
5149 uint16_t lsmash_pack_iso_language( char *iso_language
)
5151 if( !iso_language
|| strlen( iso_language
) != 3 )
5153 return (uint16_t)LSMASH_PACK_ISO_LANGUAGE( iso_language
[0], iso_language
[1], iso_language
[2] );
5156 static int isom_iso2mac_language( uint16_t ISO_language
, uint16_t *MAC_language
)
5161 for( ; isom_languages
[i
].iso_name
; i
++ )
5162 if( ISO_language
== isom_languages
[i
].iso_name
)
5164 if( !isom_languages
[i
].iso_name
)
5166 *MAC_language
= isom_languages
[i
].mac_value
;
5170 static int isom_mac2iso_language( uint16_t MAC_language
, uint16_t *ISO_language
)
5175 for( ; isom_languages
[i
].iso_name
; i
++ )
5176 if( MAC_language
== isom_languages
[i
].mac_value
)
5178 *ISO_language
= isom_languages
[i
].iso_name
? isom_languages
[i
].iso_name
: ISOM_LANGUAGE_CODE_UNDEFINED
;
5182 static int isom_set_media_language( lsmash_root_t
*root
, uint32_t track_ID
, uint16_t ISO_language
, uint16_t MAC_language
)
5184 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
5185 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->mdhd
)
5187 uint16_t language
= 0;
5188 if( root
->isom_compatible
)
5191 language
= ISO_language
;
5192 else if( MAC_language
)
5194 if( isom_mac2iso_language( MAC_language
, &language
) )
5198 language
= ISOM_LANGUAGE_CODE_UNDEFINED
;
5200 else if( root
->qt_compatible
)
5204 if( isom_iso2mac_language( ISO_language
, &language
) )
5208 language
= MAC_language
;
5212 trak
->mdia
->mdhd
->language
= language
;
5216 static int isom_create_grouping( isom_trak_entry_t
*trak
, isom_grouping_type grouping_type
)
5218 lsmash_root_t
*root
= trak
->root
;
5219 switch( grouping_type
)
5221 case ISOM_GROUP_TYPE_RAP
:
5222 assert( root
->max_isom_version
>= 6 );
5224 case ISOM_GROUP_TYPE_ROLL
:
5225 assert( root
->avc_extensions
|| root
->qt_compatible
);
5231 if( !isom_add_sgpd( trak
->mdia
->minf
->stbl
, grouping_type
)
5232 || !isom_add_sbgp( trak
->mdia
->minf
->stbl
, grouping_type
) )
5237 void lsmash_initialize_media_parameters( lsmash_media_parameters_t
*param
)
5239 memset( param
, 0, sizeof(lsmash_media_parameters_t
) );
5240 param
->timescale
= 1;
5243 int lsmash_set_media_parameters( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_media_parameters_t
*param
)
5245 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
5246 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->mdhd
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
)
5248 trak
->mdia
->mdhd
->timescale
= param
->timescale
;
5249 if( isom_set_media_language( root
, track_ID
, param
->ISO_language
, param
->MAC_language
) )
5251 if( param
->media_handler_name
5252 && isom_set_media_handler_name( root
, track_ID
, param
->media_handler_name
) )
5254 if( root
->qt_compatible
&& param
->data_handler_name
5255 && isom_set_data_handler_name( root
, track_ID
, param
->data_handler_name
) )
5257 if( (root
->avc_extensions
|| root
->qt_compatible
) && param
->roll_grouping
5258 && isom_create_grouping( trak
, ISOM_GROUP_TYPE_ROLL
) )
5260 if( (root
->max_isom_version
>= 6) && param
->rap_grouping
5261 && isom_create_grouping( trak
, ISOM_GROUP_TYPE_RAP
) )
5266 int lsmash_get_media_parameters( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_media_parameters_t
*param
)
5268 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
5269 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->mdhd
|| !trak
->mdia
->hdlr
5270 || !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
)
5272 isom_mdhd_t
*mdhd
= trak
->mdia
->mdhd
;
5273 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
5274 isom_sbgp_entry_t
*sbgp
;
5275 isom_sgpd_entry_t
*sgpd
;
5276 param
->timescale
= mdhd
->timescale
;
5277 param
->handler_type
= trak
->mdia
->hdlr
->componentSubtype
;
5278 param
->duration
= mdhd
->duration
;
5279 /* Whether sample grouping present. */
5280 sbgp
= isom_get_sample_to_group( stbl
, ISOM_GROUP_TYPE_ROLL
);
5281 sgpd
= isom_get_sample_group_description( stbl
, ISOM_GROUP_TYPE_ROLL
);
5282 param
->roll_grouping
= sbgp
&& sgpd
;
5283 sbgp
= isom_get_sample_to_group( stbl
, ISOM_GROUP_TYPE_RAP
);
5284 sgpd
= isom_get_sample_group_description( stbl
, ISOM_GROUP_TYPE_RAP
);
5285 param
->rap_grouping
= sbgp
&& sgpd
;
5286 /* Get media language. */
5287 if( mdhd
->language
>= 0x800 )
5289 param
->MAC_language
= 0;
5290 param
->ISO_language
= mdhd
->language
;
5294 param
->MAC_language
= mdhd
->language
;
5295 param
->ISO_language
= 0;
5297 /* Get handler name(s). */
5298 isom_hdlr_t
*hdlr
= trak
->mdia
->hdlr
;
5299 int length
= LSMASH_MIN( 255, hdlr
->componentName_length
);
5302 memcpy( param
->media_handler_name_shadow
, hdlr
->componentName
+ root
->qt_compatible
, length
);
5303 param
->media_handler_name_shadow
[length
- 2 + root
->isom_compatible
+ root
->qt_compatible
] = '\0';
5304 param
->media_handler_name
= param
->media_handler_name_shadow
;
5308 param
->media_handler_name
= NULL
;
5309 memset( param
->media_handler_name_shadow
, 0, sizeof(param
->media_handler_name_shadow
) );
5311 if( trak
->mdia
->minf
->hdlr
)
5313 hdlr
= trak
->mdia
->minf
->hdlr
;
5314 length
= LSMASH_MIN( 255, hdlr
->componentName_length
);
5317 memcpy( param
->data_handler_name_shadow
, hdlr
->componentName
+ root
->qt_compatible
, length
);
5318 param
->data_handler_name_shadow
[length
- 2 + root
->isom_compatible
+ root
->qt_compatible
] = '\0';
5319 param
->data_handler_name
= param
->data_handler_name_shadow
;
5323 param
->data_handler_name
= NULL
;
5324 memset( param
->data_handler_name_shadow
, 0, sizeof(param
->data_handler_name_shadow
) );
5329 param
->data_handler_name
= NULL
;
5330 memset( param
->data_handler_name_shadow
, 0, sizeof(param
->data_handler_name_shadow
) );
5335 /*---- movie manipulators ----*/
5337 lsmash_root_t
*lsmash_open_movie( const char *filename
, lsmash_file_mode mode
)
5341 char open_mode
[4] = { 0 };
5342 if( mode
& LSMASH_FILE_MODE_WRITE
)
5343 memcpy( open_mode
, "w+b", 4 );
5344 #ifdef LSMASH_DEMUXER_ENABLED
5345 else if( mode
& LSMASH_FILE_MODE_READ
)
5346 memcpy( open_mode
, "rb", 3 );
5350 lsmash_root_t
*root
= lsmash_malloc_zero( sizeof(lsmash_root_t
) );
5354 root
->bs
= lsmash_malloc_zero( sizeof(lsmash_bs_t
) );
5357 if( !strcmp( filename
, "-" ) )
5359 if( mode
& LSMASH_FILE_MODE_READ
)
5360 root
->bs
->stream
= stdin
;
5361 else if( (mode
& LSMASH_FILE_MODE_WRITE
) && (mode
& LSMASH_FILE_MODE_FRAGMENTED
) )
5362 root
->bs
->stream
= stdout
;
5365 root
->bs
->stream
= fopen( filename
, open_mode
);
5366 if( !root
->bs
->stream
)
5369 if( mode
& LSMASH_FILE_MODE_WRITE
)
5371 if( isom_add_moov( root
) || isom_add_mvhd( root
->moov
) )
5373 root
->qt_compatible
= 1; /* QTFF is default file format. */
5375 #ifdef LSMASH_DEMUXER_ENABLED
5376 if( (mode
& (LSMASH_FILE_MODE_READ
| LSMASH_FILE_MODE_DUMP
)) )
5378 if( isom_read_root( root
) )
5380 root
->max_read_size
= 4 * 1024 * 1024;
5383 if( mode
& LSMASH_FILE_MODE_FRAGMENTED
)
5385 root
->fragment
= lsmash_malloc_zero( sizeof(isom_fragment_manager_t
) );
5386 if( !root
->fragment
)
5388 root
->fragment
->pool
= lsmash_create_entry_list();
5389 if( !root
->fragment
->pool
)
5394 lsmash_destroy_root( root
);
5398 static int isom_finish_fragment_movie( lsmash_root_t
*root
);
5400 /* A movie fragment cannot switch a sample description to another.
5401 * So you must call this function before switching sample descriptions. */
5402 int lsmash_create_fragment_movie( lsmash_root_t
*root
)
5404 if( !root
|| !root
->bs
|| !root
->fragment
|| !root
->moov
|| !root
->moov
->trak_list
)
5406 /* Finish the previous movie fragment before starting a new one. */
5407 if( isom_finish_fragment_movie( root
) )
5409 /* We always hold only one movie fragment except for the initial movie (a pair of moov and mdat). */
5410 if( root
->fragment
->movie
&& root
->moof_list
->entry_count
!= 1 )
5412 isom_moof_entry_t
*moof
= isom_add_moof( root
);
5413 if( isom_add_mfhd( moof
) )
5415 root
->fragment
->movie
= moof
;
5416 moof
->mfhd
->sequence_number
= ++ root
->fragment
->fragment_count
;
5417 if( root
->moof_list
->entry_count
== 1 )
5419 /* Remove the previous movie fragment. */
5420 return lsmash_remove_entry( root
->moof_list
, 1, isom_remove_moof
);
5423 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
)
5425 if( brand_count
> 50 )
5426 return -1; /* We support setting brands up to 50. */
5429 /* Absence of File Type Box means this file is a QuickTime or MP4 version 1 format file. */
5432 if( root
->ftyp
->compatible_brands
)
5433 free( root
->ftyp
->compatible_brands
);
5439 if( !root
->ftyp
&& isom_add_ftyp( root
) )
5441 isom_ftyp_t
*ftyp
= root
->ftyp
;
5442 ftyp
->major_brand
= major_brand
;
5443 ftyp
->minor_version
= minor_version
;
5444 lsmash_brand_type
*compatible_brands
;
5445 if( !ftyp
->compatible_brands
)
5446 compatible_brands
= malloc( brand_count
* sizeof(uint32_t) );
5448 compatible_brands
= realloc( ftyp
->compatible_brands
, brand_count
* sizeof(uint32_t) );
5449 if( !compatible_brands
)
5451 ftyp
->compatible_brands
= compatible_brands
;
5452 for( uint32_t i
= 0; i
< brand_count
; i
++ )
5454 ftyp
->compatible_brands
[i
] = brands
[i
];
5457 ftyp
->brand_count
= brand_count
;
5458 return isom_check_compatibility( root
);
5461 void lsmash_initialize_movie_parameters( lsmash_movie_parameters_t
*param
)
5463 memset( param
, 0, sizeof(lsmash_movie_parameters_t
) );
5464 param
->max_chunk_duration
= 0.5;
5465 param
->max_async_tolerance
= 2.0;
5466 param
->max_chunk_size
= 4 * 1024 * 1024;
5467 param
->max_read_size
= 4 * 1024 * 1024;
5468 param
->timescale
= 600;
5469 param
->playback_rate
= 0x00010000;
5470 param
->playback_volume
= 0x0100;
5473 int lsmash_set_movie_parameters( lsmash_root_t
*root
, lsmash_movie_parameters_t
*param
)
5475 if( !root
|| !root
->moov
|| !root
->moov
->mvhd
5476 || isom_set_brands( root
, param
->major_brand
, param
->minor_version
, param
->brands
, param
->number_of_brands
) )
5478 isom_mvhd_t
*mvhd
= root
->moov
->mvhd
;
5479 root
->max_chunk_duration
= param
->max_chunk_duration
;
5480 root
->max_async_tolerance
= LSMASH_MAX( param
->max_async_tolerance
, 2 * param
->max_chunk_duration
);
5481 root
->max_chunk_size
= param
->max_chunk_size
;
5482 root
->max_read_size
= param
->max_read_size
;
5483 mvhd
->timescale
= param
->timescale
;
5484 if( root
->qt_compatible
|| root
->itunes_movie
)
5486 mvhd
->rate
= param
->playback_rate
;
5487 mvhd
->volume
= param
->playback_volume
;
5488 mvhd
->previewTime
= param
->preview_time
;
5489 mvhd
->previewDuration
= param
->preview_duration
;
5490 mvhd
->posterTime
= param
->poster_time
;
5494 mvhd
->rate
= 0x00010000;
5495 mvhd
->volume
= 0x0100;
5496 mvhd
->previewTime
= 0;
5497 mvhd
->previewDuration
= 0;
5498 mvhd
->posterTime
= 0;
5503 int lsmash_get_movie_parameters( lsmash_root_t
*root
, lsmash_movie_parameters_t
*param
)
5505 if( !root
|| !root
->moov
|| !root
->moov
->mvhd
)
5507 isom_mvhd_t
*mvhd
= root
->moov
->mvhd
;
5510 isom_ftyp_t
*ftyp
= root
->ftyp
;
5511 uint32_t brand_count
= LSMASH_MIN( ftyp
->brand_count
, 50 ); /* brands up to 50 */
5512 for( uint32_t i
= 0; i
< brand_count
; i
++ )
5513 param
->brands_shadow
[i
] = ftyp
->compatible_brands
[i
];
5514 param
->major_brand
= ftyp
->major_brand
;
5515 param
->brands
= param
->brands_shadow
;
5516 param
->number_of_brands
= brand_count
;
5517 param
->minor_version
= ftyp
->minor_version
;
5519 param
->max_chunk_duration
= root
->max_chunk_duration
;
5520 param
->max_async_tolerance
= root
->max_async_tolerance
;
5521 param
->max_chunk_size
= root
->max_chunk_size
;
5522 param
->max_read_size
= root
->max_read_size
;
5523 param
->timescale
= mvhd
->timescale
;
5524 param
->duration
= mvhd
->duration
;
5525 param
->playback_rate
= mvhd
->rate
;
5526 param
->playback_volume
= mvhd
->volume
;
5527 param
->preview_time
= mvhd
->previewTime
;
5528 param
->preview_duration
= mvhd
->previewDuration
;
5529 param
->poster_time
= mvhd
->posterTime
;
5530 param
->number_of_tracks
= root
->moov
->trak_list
? root
->moov
->trak_list
->entry_count
: 0;
5534 uint32_t lsmash_get_movie_timescale( lsmash_root_t
*root
)
5536 if( !root
|| !root
->moov
|| !root
->moov
->mvhd
)
5538 return root
->moov
->mvhd
->timescale
;
5541 int lsmash_set_free( lsmash_root_t
*root
, uint8_t *data
, uint64_t data_length
)
5543 if( !root
|| !root
->free
|| !data
|| !data_length
)
5545 isom_free_t
*skip
= root
->free
;
5546 uint8_t *tmp
= NULL
;
5548 tmp
= malloc( data_length
);
5549 else if( skip
->length
< data_length
)
5550 tmp
= realloc( skip
->data
, data_length
);
5553 memcpy( tmp
, data
, data_length
);
5555 skip
->length
= data_length
;
5559 int lsmash_add_free( lsmash_root_t
*root
, uint8_t *data
, uint64_t data_length
)
5565 isom_create_box( skip
, root
, ISOM_BOX_TYPE_FREE
);
5568 if( data
&& data_length
)
5569 return lsmash_set_free( root
, data
, data_length
);
5573 int lsmash_create_object_descriptor( lsmash_root_t
*root
)
5577 /* Return error if this file is not compatible with MP4 file format. */
5578 if( !root
->mp4_version1
&& !root
->mp4_version2
)
5580 return isom_add_iods( root
->moov
);
5583 /*---- finishing functions ----*/
5585 static int isom_set_fragment_overall_duration( lsmash_root_t
*root
)
5587 isom_mvex_t
*mvex
= root
->moov
->mvex
;
5588 if( isom_add_mehd( mvex
) )
5590 /* Get the longest duration of the tracks. */
5591 uint64_t longest_duration
= 0;
5592 for( lsmash_entry_t
*entry
= root
->moov
->trak_list
->head
; entry
; entry
= entry
->next
)
5594 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)entry
->data
;
5595 if( !trak
|| !trak
->cache
|| !trak
->cache
->fragment
|| !trak
->mdia
|| !trak
->mdia
->mdhd
|| !trak
->mdia
->mdhd
->timescale
)
5598 if( !trak
->edts
|| !trak
->edts
->elst
|| !trak
->edts
->elst
->list
)
5600 duration
= trak
->cache
->fragment
->largest_cts
+ trak
->cache
->fragment
->last_duration
;
5601 duration
= (uint64_t)(((double)duration
/ trak
->mdia
->mdhd
->timescale
) * root
->moov
->mvhd
->timescale
);
5606 for( lsmash_entry_t
*elst_entry
= trak
->edts
->elst
->list
->head
; elst_entry
; elst_entry
= elst_entry
->next
)
5608 isom_elst_entry_t
*data
= (isom_elst_entry_t
*)elst_entry
->data
;
5611 duration
+= data
->segment_duration
;
5614 longest_duration
= LSMASH_MAX( duration
, longest_duration
);
5616 mvex
->mehd
->fragment_duration
= longest_duration
;
5617 mvex
->mehd
->version
= 1;
5618 isom_update_mehd_size( mvex
->mehd
);
5619 /* Write Movie Extends Header Box here. */
5620 lsmash_bs_t
*bs
= root
->bs
;
5621 FILE *stream
= bs
->stream
;
5622 uint64_t current_pos
= lsmash_ftell( stream
);
5623 lsmash_fseek( stream
, mvex
->placeholder_pos
, SEEK_SET
);
5624 int ret
= isom_write_mehd( bs
, mvex
->mehd
);
5626 ret
= lsmash_bs_write_data( bs
);
5627 lsmash_fseek( stream
, current_pos
, SEEK_SET
);
5631 static int isom_write_fragment_random_access_info( lsmash_root_t
*root
)
5633 if( !root
->moov
->mvex
|| !root
->moov
->mvex
->trex_list
)
5635 /* Reconstruct the Movie Fragment Random Access Box.
5636 * All 'time' field in the Track Fragment Random Access Boxes shall reflect edit list. */
5637 uint32_t movie_timescale
= lsmash_get_movie_timescale( root
);
5638 if( movie_timescale
== 0 )
5639 return -1; /* Division by zero will occur. */
5640 for( lsmash_entry_t
*trex_entry
= root
->moov
->mvex
->trex_list
->head
; trex_entry
; trex_entry
= trex_entry
->next
)
5642 isom_trex_entry_t
*trex
= (isom_trex_entry_t
*)trex_entry
->data
;
5645 /* Get the edit list of the track associated with the trex->track_ID.
5646 * If failed or absent, implicit timeline mapping edit is used, and skip this operation for the track. */
5647 isom_trak_entry_t
*trak
= isom_get_trak( root
, trex
->track_ID
);
5650 if( !trak
->edts
|| !trak
->edts
->elst
|| !trak
->edts
->elst
->list
5651 || !trak
->edts
->elst
->list
->head
|| !trak
->edts
->elst
->list
->head
->data
)
5653 isom_elst_t
*elst
= trak
->edts
->elst
;
5654 /* Get the Track Fragment Random Access Boxes of the track associated with the trex->track_ID.
5655 * If failed or absent, skip reconstructing the Track Fragment Random Access Box of the track. */
5656 isom_tfra_entry_t
*tfra
= isom_get_tfra( root
->mfra
, trex
->track_ID
);
5659 /* Reconstruct the Track Fragment Random Access Box. */
5660 lsmash_entry_t
*edit_entry
= elst
->list
->head
;
5661 isom_elst_entry_t
*edit
= edit_entry
->data
;
5662 uint64_t edit_offset
= 0; /* units in media timescale */
5663 uint32_t media_timescale
= lsmash_get_media_timescale( root
, trex
->track_ID
);
5664 for( lsmash_entry_t
*rap_entry
= tfra
->list
->head
; rap_entry
; )
5666 isom_tfra_location_time_entry_t
*rap
= (isom_tfra_location_time_entry_t
*)rap_entry
->data
;
5669 /* Irregular case. Drop this entry. */
5670 lsmash_entry_t
*next
= rap_entry
->next
;
5671 lsmash_remove_entry_direct( tfra
->list
, rap_entry
, NULL
);
5675 uint64_t composition_time
= rap
->time
;
5676 /* Skip edits that doesn't need the current sync sample indicated in the Track Fragment Random Access Box. */
5679 uint64_t segment_duration
= ((edit
->segment_duration
- 1) / movie_timescale
+ 1) * media_timescale
;
5680 if( edit
->media_time
!= ISOM_EDIT_MODE_EMPTY
5681 && composition_time
< edit
->media_time
+ segment_duration
)
5682 break; /* This Timeline Mapping Edit might require the current sync sample.
5683 * Note: this condition doesn't cover all cases.
5684 * For instance, matching the both following conditions
5685 * 1. A sync sample isn't in the presentation.
5686 * 2. The other samples, which precede it in the composition timeline, is in the presentation. */
5687 edit_offset
+= segment_duration
;
5688 edit_entry
= edit_entry
->next
;
5691 /* No more presentation. */
5695 edit
= edit_entry
->data
;
5699 /* No more presentation.
5700 * Drop the rest of sync samples since they are generally absent in the whole presentation.
5701 * Though the exceptions are sync samples with earlier composition time, we ignore them. (SAP type 2: TEPT = TDEC = TSAP < TPTF)
5702 * To support this exception, we need sorting entries of the list by composition times. */
5703 for( ; rap_entry
; rap_entry
= rap_entry
->next
)
5704 lsmash_remove_entry_direct( tfra
->list
, rap_entry
, NULL
);
5707 /* If the sync sample isn't in the presentation,
5708 * we pick the earliest presentation time of the current edit as its presentation time. */
5709 rap
->time
= edit_offset
;
5710 if( composition_time
>= edit
->media_time
)
5711 rap
->time
+= composition_time
- edit
->media_time
;
5712 rap_entry
= rap_entry
->next
;
5715 /* Decide the size of the Movie Fragment Random Access Box. */
5716 if( isom_update_mfra_size( root
->mfra
) )
5718 /* Write the Movie Fragment Random Access Box. */
5719 return isom_write_mfra( root
->bs
, root
->mfra
);
5722 int lsmash_finish_movie( lsmash_root_t
*root
, lsmash_adhoc_remux_t
* remux
)
5724 if( !root
|| !root
->bs
|| !root
->moov
|| !root
->moov
->trak_list
)
5726 if( root
->fragment
)
5728 /* Output the final movie fragment. */
5729 if( isom_finish_fragment_movie( root
) )
5731 if( root
->bs
->stream
== stdout
)
5733 /* Write the overall random access information at the tail of the movie. */
5734 if( isom_write_fragment_random_access_info( root
) )
5736 /* Set overall duration of the movie. */
5737 return isom_set_fragment_overall_duration( root
);
5739 isom_moov_t
*moov
= root
->moov
;
5740 for( lsmash_entry_t
*entry
= moov
->trak_list
->head
; entry
; entry
= entry
->next
)
5742 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)entry
->data
;
5743 if( !trak
|| !trak
->cache
|| !trak
->tkhd
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
)
5745 uint32_t track_ID
= trak
->tkhd
->track_ID
;
5746 uint32_t related_track_ID
= trak
->related_track_ID
;
5747 /* Disable the track if the track is a track reference chapter. */
5748 if( trak
->is_chapter
)
5749 trak
->tkhd
->flags
&= ~ISOM_TRACK_ENABLED
;
5750 if( trak
->is_chapter
&& related_track_ID
)
5752 /* In order that the track duration of the chapter track doesn't exceed that of the related track. */
5754 edit
.duration
= LSMASH_MIN( trak
->tkhd
->duration
, lsmash_get_track_duration( root
, related_track_ID
) );
5755 edit
.start_time
= 0;
5756 edit
.rate
= ISOM_EDIT_MODE_NORMAL
;
5757 if( lsmash_create_explicit_timeline_map( root
, track_ID
, edit
) )
5760 /* Add stss box if any samples aren't sync sample. */
5761 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
5762 if( !trak
->cache
->all_sync
&& !stbl
->stss
&& isom_add_stss( stbl
) )
5764 if( isom_update_bitrate_description( trak
->mdia
) )
5767 if( root
->mp4_version1
== 1 && isom_add_iods( moov
) )
5769 if( isom_check_mandatory_boxes( root
)
5770 || isom_set_movie_creation_time( root
)
5771 || isom_update_moov_size( moov
)
5772 || isom_write_mdat_size( root
) )
5775 lsmash_bs_t
*bs
= root
->bs
;
5776 uint64_t meta_size
= root
->meta
? root
->meta
->size
: 0;
5779 if( isom_write_moov( root
)
5780 || isom_write_meta( bs
, root
->meta
) )
5782 root
->size
+= moov
->size
+ meta_size
;
5786 /* stco->co64 conversion, depending on last chunk's offset */
5787 for( lsmash_entry_t
* entry
= moov
->trak_list
->head
; entry
; )
5789 isom_trak_entry_t
* trak
= (isom_trak_entry_t
*)entry
->data
;
5790 isom_stco_t
* stco
= trak
->mdia
->minf
->stbl
->stco
;
5791 if( !stco
->list
->tail
)
5793 if( stco
->large_presentation
5794 || (((isom_stco_entry_t
*)stco
->list
->tail
->data
)->chunk_offset
+ moov
->size
+ meta_size
) <= UINT32_MAX
)
5796 entry
= entry
->next
;
5797 continue; /* no need to convert stco into co64 */
5799 /* stco->co64 conversion */
5800 if( isom_convert_stco_to_co64( trak
->mdia
->minf
->stbl
)
5801 || isom_update_moov_size( moov
) )
5803 entry
= moov
->trak_list
->head
; /* whenever any conversion, re-check all traks */
5806 /* now the amount of offset is fixed. */
5807 uint64_t mtf_size
= moov
->size
+ meta_size
; /* sum of size of boxes moved to front */
5809 /* buffer size must be at least mtf_size * 2 */
5810 remux
->buffer_size
= LSMASH_MAX( remux
->buffer_size
, mtf_size
* 2 );
5813 if( (buf
[0] = (uint8_t*)malloc( remux
->buffer_size
)) == NULL
)
5814 return -1; /* NOTE: i think we still can fallback to "return isom_write_moov( root );" here. */
5815 uint64_t size
= remux
->buffer_size
/ 2;
5816 buf
[1] = buf
[0] + size
; /* split to 2 buffers */
5818 /* now the amount of offset is fixed. apply that to stco/co64 */
5819 for( lsmash_entry_t
* entry
= moov
->trak_list
->head
; entry
; entry
= entry
->next
)
5821 isom_stco_t
* stco
= ((isom_trak_entry_t
*)entry
->data
)->mdia
->minf
->stbl
->stco
;
5822 if( stco
->large_presentation
)
5823 for( lsmash_entry_t
* co64_entry
= stco
->list
->head
; co64_entry
; co64_entry
= co64_entry
->next
)
5824 ((isom_co64_entry_t
*)co64_entry
->data
)->chunk_offset
+= mtf_size
;
5826 for( lsmash_entry_t
* stco_entry
= stco
->list
->head
; stco_entry
; stco_entry
= stco_entry
->next
)
5827 ((isom_stco_entry_t
*)stco_entry
->data
)->chunk_offset
+= mtf_size
;
5830 FILE *stream
= bs
->stream
;
5831 isom_mdat_t
*mdat
= root
->mdat
;
5832 uint64_t total
= root
->size
+ mtf_size
;
5834 /* backup starting area of mdat and write moov + meta there instead */
5835 if( lsmash_fseek( stream
, mdat
->placeholder_pos
, SEEK_SET
) )
5837 readnum
= fread( buf
[0], 1, size
, stream
);
5838 uint64_t read_pos
= lsmash_ftell( stream
);
5840 /* write moov + meta there instead */
5841 if( lsmash_fseek( stream
, mdat
->placeholder_pos
, SEEK_SET
)
5842 || isom_write_moov( root
)
5843 || isom_write_meta( bs
, root
->meta
) )
5845 uint64_t write_pos
= lsmash_ftell( stream
);
5847 mdat
->placeholder_pos
+= mtf_size
; /* update placeholder */
5851 while( readnum
== size
)
5853 if( lsmash_fseek( stream
, read_pos
, SEEK_SET
) )
5855 readnum
= fread( buf
[buf_switch
], 1, size
, stream
);
5856 read_pos
= lsmash_ftell( stream
);
5860 if( lsmash_fseek( stream
, write_pos
, SEEK_SET
)
5861 || fwrite( buf
[buf_switch
], 1, size
, stream
) != size
)
5863 write_pos
= lsmash_ftell( stream
);
5864 if( remux
->func
) remux
->func( remux
->param
, write_pos
, total
); // FIXME:
5866 if( fwrite( buf
[buf_switch
^0x1], 1, readnum
, stream
) != readnum
)
5868 if( remux
->func
) remux
->func( remux
->param
, total
, total
); // FIXME:
5870 root
->size
+= mtf_size
;
5879 #define GET_MOST_USED( box_name, index, flag_name ) \
5880 if( most_used[index] < stats.flag_name[i] ) \
5882 most_used[index] = stats.flag_name[i]; \
5883 box_name->default_sample_flags.flag_name = i; \
5886 static int isom_create_fragment_overall_default_settings( lsmash_root_t
*root
)
5888 if( isom_add_mvex( root
->moov
) )
5890 for( lsmash_entry_t
*trak_entry
= root
->moov
->trak_list
->head
; trak_entry
; trak_entry
= trak_entry
->next
)
5892 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)trak_entry
->data
;
5893 if( !trak
|| !trak
->cache
|| !trak
->tkhd
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
)
5895 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
5896 if( !stbl
->stts
|| !stbl
->stts
->list
|| !stbl
->stsz
5897 || (stbl
->stts
->list
->tail
&& !stbl
->stts
->list
->tail
->data
)
5898 || (stbl
->stsz
->list
&& stbl
->stsz
->list
->head
&& !stbl
->stsz
->list
->head
->data
) )
5900 isom_trex_entry_t
*trex
= isom_add_trex( root
->moov
->mvex
);
5903 trex
->track_ID
= trak
->tkhd
->track_ID
;
5904 /* Set up defaults. */
5905 trex
->default_sample_description_index
= trak
->cache
->chunk
.sample_description_index
? trak
->cache
->chunk
.sample_description_index
: 1;
5906 trex
->default_sample_duration
= stbl
->stts
->list
->tail
? ((isom_stts_entry_t
*)stbl
->stts
->list
->tail
->data
)->sample_delta
: 1;
5907 trex
->default_sample_size
= !stbl
->stsz
->list
5908 ? stbl
->stsz
->sample_size
: stbl
->stsz
->list
->head
5909 ? ((isom_stsz_entry_t
*)stbl
->stsz
->list
->head
->data
)->entry_size
: 0;
5910 if( stbl
->sdtp
&& stbl
->sdtp
->list
)
5912 struct sample_flags_stats_t
5914 uint32_t is_leading
[4];
5915 uint32_t sample_depends_on
[4];
5916 uint32_t sample_is_depended_on
[4];
5917 uint32_t sample_has_redundancy
[4];
5918 } stats
= { { 0 }, { 0 }, { 0 }, { 0 } };
5919 for( lsmash_entry_t
*sdtp_entry
= stbl
->sdtp
->list
->head
; sdtp_entry
; sdtp_entry
= sdtp_entry
->next
)
5921 isom_sdtp_entry_t
*data
= (isom_sdtp_entry_t
*)sdtp_entry
->data
;
5924 ++ stats
.is_leading
[ data
->is_leading
];
5925 ++ stats
.sample_depends_on
[ data
->sample_depends_on
];
5926 ++ stats
.sample_is_depended_on
[ data
->sample_is_depended_on
];
5927 ++ stats
.sample_has_redundancy
[ data
->sample_has_redundancy
];
5929 uint32_t most_used
[4] = { 0, 0, 0, 0 };
5930 for( int i
= 0; i
< 4; i
++ )
5932 GET_MOST_USED( trex
, 0, is_leading
);
5933 GET_MOST_USED( trex
, 1, sample_depends_on
);
5934 GET_MOST_USED( trex
, 2, sample_is_depended_on
);
5935 GET_MOST_USED( trex
, 3, sample_has_redundancy
);
5938 trex
->default_sample_flags
.sample_is_non_sync_sample
= !trak
->cache
->all_sync
;
5943 static int isom_prepare_random_access_info( lsmash_root_t
*root
)
5945 if( root
->bs
->stream
== stdout
)
5947 if( isom_add_mfra( root
)
5948 || isom_add_mfro( root
->mfra
) )
5953 static int isom_output_fragment_media_data( lsmash_root_t
*root
)
5955 isom_fragment_manager_t
*fragment
= root
->fragment
;
5956 if( !fragment
->pool
->entry_count
)
5958 /* no need to write media data */
5959 lsmash_remove_entries( fragment
->pool
, lsmash_delete_sample
);
5960 fragment
->pool_size
= 0;
5963 /* If there is no available Media Data Box to write samples, add and write a new one. */
5964 if( isom_new_mdat( root
, fragment
->pool_size
) )
5966 /* Write samples in the current movie fragment. */
5967 for( lsmash_entry_t
* entry
= fragment
->pool
->head
; entry
; entry
= entry
->next
)
5969 isom_sample_pool_t
*pool
= (isom_sample_pool_t
*)entry
->data
;
5972 lsmash_bs_put_bytes( root
->bs
, pool
->size
, pool
->data
);
5974 if( lsmash_bs_write_data( root
->bs
) )
5976 root
->size
+= root
->mdat
->size
;
5977 lsmash_remove_entries( fragment
->pool
, isom_remove_sample_pool
);
5978 fragment
->pool_size
= 0;
5982 static int isom_finish_fragment_initial_movie( lsmash_root_t
*root
)
5984 if( !root
->moov
|| !root
->moov
->trak_list
)
5986 isom_moov_t
*moov
= root
->moov
;
5987 for( lsmash_entry_t
*entry
= moov
->trak_list
->head
; entry
; entry
= entry
->next
)
5989 isom_trak_entry_t
*trak
= (isom_trak_entry_t
*)entry
->data
;
5990 if( !trak
|| !trak
->cache
|| !trak
->tkhd
|| !trak
->mdia
|| !trak
->mdia
->mdhd
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
)
5992 if( isom_get_sample_count( trak
) )
5994 /* Add stss box if any samples aren't sync sample. */
5995 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
5996 if( !trak
->cache
->all_sync
&& !stbl
->stss
&& isom_add_stss( stbl
) )
6000 trak
->tkhd
->duration
= 0;
6001 if( isom_update_bitrate_description( trak
->mdia
) )
6004 if( root
->mp4_version1
== 1 && isom_add_iods( moov
) )
6006 if( isom_create_fragment_overall_default_settings( root
)
6007 || isom_prepare_random_access_info( root
)
6008 || isom_check_mandatory_boxes( root
)
6009 || isom_set_movie_creation_time( root
)
6010 || isom_update_moov_size( moov
) )
6012 /* stco->co64 conversion, depending on last chunk's offset */
6013 uint64_t meta_size
= root
->meta
? root
->meta
->size
: 0;
6014 for( lsmash_entry_t
* entry
= moov
->trak_list
->head
; entry
; )
6016 isom_trak_entry_t
* trak
= (isom_trak_entry_t
*)entry
->data
;
6017 isom_stco_t
* stco
= trak
->mdia
->minf
->stbl
->stco
;
6018 if( !stco
->list
->tail
/* no samples */
6019 || stco
->large_presentation
6020 || (((isom_stco_entry_t
*)stco
->list
->tail
->data
)->chunk_offset
+ moov
->size
+ meta_size
) <= UINT32_MAX
)
6022 entry
= entry
->next
;
6023 continue; /* no need to convert stco into co64 */
6025 /* stco->co64 conversion */
6026 if( isom_convert_stco_to_co64( trak
->mdia
->minf
->stbl
)
6027 || isom_update_moov_size( moov
) )
6029 entry
= moov
->trak_list
->head
; /* whenever any conversion, re-check all traks */
6031 /* Now, the amount of offset is fixed. Apply that to stco/co64. */
6032 uint64_t preceding_size
= moov
->size
+ meta_size
;
6033 for( lsmash_entry_t
* entry
= moov
->trak_list
->head
; entry
; entry
= entry
->next
)
6035 isom_stco_t
* stco
= ((isom_trak_entry_t
*)entry
->data
)->mdia
->minf
->stbl
->stco
;
6036 if( stco
->large_presentation
)
6037 for( lsmash_entry_t
* co64_entry
= stco
->list
->head
; co64_entry
; co64_entry
= co64_entry
->next
)
6038 ((isom_co64_entry_t
*)co64_entry
->data
)->chunk_offset
+= preceding_size
;
6040 for( lsmash_entry_t
* stco_entry
= stco
->list
->head
; stco_entry
; stco_entry
= stco_entry
->next
)
6041 ((isom_stco_entry_t
*)stco_entry
->data
)->chunk_offset
+= preceding_size
;
6043 /* Write File Type Box here if it was not written yet. */
6044 if( !root
->file_type_written
&& isom_write_ftyp( root
) )
6046 /* Write Movie Box. */
6047 if( isom_write_moov( root
)
6048 || isom_write_meta( root
->bs
, root
->meta
) )
6050 root
->size
+= preceding_size
;
6051 /* Output samples. */
6052 return isom_output_fragment_media_data( root
);
6055 /* Return 1 if there is diffrence, otherwise return 0. */
6056 static int isom_compare_sample_flags( isom_sample_flags_t
*a
, isom_sample_flags_t
*b
)
6058 return (a
->reserved
!= b
->reserved
)
6059 || (a
->is_leading
!= b
->is_leading
)
6060 || (a
->sample_depends_on
!= b
->sample_depends_on
)
6061 || (a
->sample_is_depended_on
!= b
->sample_is_depended_on
)
6062 || (a
->sample_has_redundancy
!= b
->sample_has_redundancy
)
6063 || (a
->sample_padding_value
!= b
->sample_padding_value
)
6064 || (a
->sample_is_non_sync_sample
!= b
->sample_is_non_sync_sample
)
6065 || (a
->sample_degradation_priority
!= b
->sample_degradation_priority
);
6068 static int isom_finish_fragment_movie( lsmash_root_t
*root
)
6070 if( !root
->moov
|| !root
->moov
->trak_list
|| !root
->fragment
|| !root
->fragment
->pool
)
6072 isom_moof_entry_t
*moof
= root
->fragment
->movie
;
6074 return isom_finish_fragment_initial_movie( root
);
6075 /* Calculate appropriate default_sample_flags of each Track Fragment Header Box.
6076 * And check whether that default_sample_flags is useful or not. */
6077 for( lsmash_entry_t
*entry
= moof
->traf_list
->head
; entry
; entry
= entry
->next
)
6079 isom_traf_entry_t
*traf
= (isom_traf_entry_t
*)entry
->data
;
6080 if( !traf
|| !traf
->tfhd
|| !traf
->root
|| !traf
->root
->moov
|| !traf
->root
->moov
->mvex
)
6082 isom_tfhd_t
*tfhd
= traf
->tfhd
;
6083 isom_trex_entry_t
*trex
= isom_get_trex( root
->moov
->mvex
, tfhd
->track_ID
);
6086 struct sample_flags_stats_t
6088 uint32_t is_leading
[4];
6089 uint32_t sample_depends_on
[4];
6090 uint32_t sample_is_depended_on
[4];
6091 uint32_t sample_has_redundancy
[4];
6092 uint32_t sample_is_non_sync_sample
[2];
6093 } stats
= { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } };
6094 for( lsmash_entry_t
*trun_entry
= traf
->trun_list
->head
; trun_entry
; trun_entry
= trun_entry
->next
)
6096 isom_trun_entry_t
*trun
= (isom_trun_entry_t
*)trun_entry
->data
;
6097 if( !trun
|| !trun
->sample_count
)
6099 isom_sample_flags_t
*sample_flags
;
6100 if( trun
->flags
& ISOM_TR_FLAGS_SAMPLE_FLAGS_PRESENT
)
6102 if( !trun
->optional
)
6104 for( lsmash_entry_t
*optional_entry
= trun
->optional
->head
; optional_entry
; optional_entry
= optional_entry
->next
)
6106 isom_trun_optional_row_t
*row
= (isom_trun_optional_row_t
*)optional_entry
->data
;
6109 sample_flags
= &row
->sample_flags
;
6110 ++ stats
.is_leading
[ sample_flags
->is_leading
];
6111 ++ stats
.sample_depends_on
[ sample_flags
->sample_depends_on
];
6112 ++ stats
.sample_is_depended_on
[ sample_flags
->sample_is_depended_on
];
6113 ++ stats
.sample_has_redundancy
[ sample_flags
->sample_has_redundancy
];
6114 ++ stats
.sample_is_non_sync_sample
[ sample_flags
->sample_is_non_sync_sample
];
6119 sample_flags
= &tfhd
->default_sample_flags
;
6120 stats
.is_leading
[ sample_flags
->is_leading
] += trun
->sample_count
;
6121 stats
.sample_depends_on
[ sample_flags
->sample_depends_on
] += trun
->sample_count
;
6122 stats
.sample_is_depended_on
[ sample_flags
->sample_is_depended_on
] += trun
->sample_count
;
6123 stats
.sample_has_redundancy
[ sample_flags
->sample_has_redundancy
] += trun
->sample_count
;
6124 stats
.sample_is_non_sync_sample
[ sample_flags
->sample_is_non_sync_sample
] += trun
->sample_count
;
6127 uint32_t most_used
[5] = { 0, 0, 0, 0, 0 };
6128 for( int i
= 0; i
< 4; i
++ )
6130 GET_MOST_USED( tfhd
, 0, is_leading
);
6131 GET_MOST_USED( tfhd
, 1, sample_depends_on
);
6132 GET_MOST_USED( tfhd
, 2, sample_is_depended_on
);
6133 GET_MOST_USED( tfhd
, 3, sample_has_redundancy
);
6135 GET_MOST_USED( tfhd
, 4, sample_is_non_sync_sample
);
6137 int useful_default_sample_duration
= 0;
6138 int useful_default_sample_size
= 0;
6139 for( lsmash_entry_t
*trun_entry
= traf
->trun_list
->head
; trun_entry
; trun_entry
= trun_entry
->next
)
6141 isom_trun_entry_t
*trun
= (isom_trun_entry_t
*)trun_entry
->data
;
6142 if( !(trun
->flags
& ISOM_TR_FLAGS_SAMPLE_DURATION_PRESENT
) )
6143 useful_default_sample_duration
= 1;
6144 if( !(trun
->flags
& ISOM_TR_FLAGS_SAMPLE_SIZE_PRESENT
) )
6145 useful_default_sample_size
= 1;
6146 int useful_first_sample_flags
= 1;
6147 int useful_default_sample_flags
= 1;
6148 if( trun
->sample_count
== 1 )
6150 /* It is enough to check only if first_sample_flags equals default_sample_flags or not.
6151 * If it is equal, just use default_sample_flags.
6152 * If not, just use first_sample_flags of this run. */
6153 if( !isom_compare_sample_flags( &trun
->first_sample_flags
, &tfhd
->default_sample_flags
) )
6154 useful_first_sample_flags
= 0;
6156 else if( trun
->optional
&& trun
->optional
->head
)
6158 lsmash_entry_t
*optional_entry
= trun
->optional
->head
->next
;
6159 isom_trun_optional_row_t
*row
= (isom_trun_optional_row_t
*)optional_entry
->data
;
6160 isom_sample_flags_t representative_sample_flags
= row
->sample_flags
;
6161 if( isom_compare_sample_flags( &tfhd
->default_sample_flags
, &representative_sample_flags
) )
6162 useful_default_sample_flags
= 0;
6163 if( !isom_compare_sample_flags( &trun
->first_sample_flags
, &representative_sample_flags
) )
6164 useful_first_sample_flags
= 0;
6165 if( useful_default_sample_flags
)
6166 for( optional_entry
= optional_entry
->next
; optional_entry
; optional_entry
= optional_entry
->next
)
6168 row
= (isom_trun_optional_row_t
*)optional_entry
->data
;
6169 if( isom_compare_sample_flags( &representative_sample_flags
, &row
->sample_flags
) )
6171 useful_default_sample_flags
= 0;
6176 if( useful_default_sample_flags
)
6178 tfhd
->flags
|= ISOM_TF_FLAGS_DEFAULT_SAMPLE_FLAGS_PRESENT
;
6179 trun
->flags
&= ~ISOM_TR_FLAGS_SAMPLE_FLAGS_PRESENT
;
6183 useful_first_sample_flags
= 0;
6184 trun
->flags
|= ISOM_TR_FLAGS_SAMPLE_FLAGS_PRESENT
;
6186 if( useful_first_sample_flags
)
6187 trun
->flags
|= ISOM_TR_FLAGS_FIRST_SAMPLE_FLAGS_PRESENT
;
6189 if( useful_default_sample_duration
&& tfhd
->default_sample_duration
!= trex
->default_sample_duration
)
6190 tfhd
->flags
|= ISOM_TF_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT
;
6192 tfhd
->default_sample_duration
= trex
->default_sample_duration
; /* This might be redundant, but is to be more natural. */
6193 if( useful_default_sample_size
&& tfhd
->default_sample_size
!= trex
->default_sample_size
)
6194 tfhd
->flags
|= ISOM_TF_FLAGS_DEFAULT_SAMPLE_SIZE_PRESENT
;
6196 tfhd
->default_sample_size
= trex
->default_sample_size
; /* This might be redundant, but is to be more natural. */
6197 if( !(tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_SAMPLE_FLAGS_PRESENT
) )
6198 tfhd
->default_sample_flags
= trex
->default_sample_flags
; /* This might be redundant, but is to be more natural. */
6199 else if( !isom_compare_sample_flags( &tfhd
->default_sample_flags
, &trex
->default_sample_flags
) )
6200 tfhd
->flags
&= ~ISOM_TF_FLAGS_DEFAULT_SAMPLE_FLAGS_PRESENT
;
6202 /* When using for live streaming, setting explicit base_data_offset is not preferable.
6203 * However, it's OK because we haven't supported this yet.
6204 * Implicit base_data_offsets that originate in the first byte of each Movie Fragment Box will be implemented
6205 * by the feature of ISO Base Media File Format version 5 or later.
6206 * Media Data Box starts immediately after Movie Fragment Box. */
6207 for( lsmash_entry_t
*entry
= moof
->traf_list
->head
; entry
; entry
= entry
->next
)
6209 isom_traf_entry_t
*traf
= (isom_traf_entry_t
*)entry
->data
;
6210 traf
->tfhd
->flags
|= ISOM_TF_FLAGS_BASE_DATA_OFFSET_PRESENT
;
6212 /* Consider the update of tf_flags here. */
6213 if( isom_update_moof_entry_size( moof
) )
6215 /* Now, we can calculate offsets in the current movie fragment, so do it. */
6216 for( lsmash_entry_t
*entry
= moof
->traf_list
->head
; entry
; entry
= entry
->next
)
6218 isom_traf_entry_t
*traf
= (isom_traf_entry_t
*)entry
->data
;
6219 traf
->tfhd
->base_data_offset
= root
->size
+ moof
->size
+ ISOM_BASEBOX_COMMON_SIZE
;
6221 if( isom_write_moof( root
->bs
, moof
) )
6223 root
->size
+= moof
->size
;
6224 /* Output samples. */
6225 return isom_output_fragment_media_data( root
);
6228 #undef GET_MOST_USED
6230 static isom_trun_optional_row_t
*isom_request_trun_optional_row( isom_trun_entry_t
*trun
, isom_tfhd_t
*tfhd
, uint32_t sample_number
)
6232 isom_trun_optional_row_t
*row
= NULL
;
6233 if( !trun
->optional
)
6235 trun
->optional
= lsmash_create_entry_list();
6236 if( !trun
->optional
)
6239 if( trun
->optional
->entry_count
< sample_number
)
6241 while( trun
->optional
->entry_count
< sample_number
)
6243 row
= malloc( sizeof(isom_trun_optional_row_t
) );
6246 /* Copy from default. */
6247 row
->sample_duration
= tfhd
->default_sample_duration
;
6248 row
->sample_size
= tfhd
->default_sample_size
;
6249 row
->sample_flags
= tfhd
->default_sample_flags
;
6250 row
->sample_composition_time_offset
= 0;
6251 if( lsmash_add_entry( trun
->optional
, row
) )
6260 for( lsmash_entry_t
*entry
= trun
->optional
->head
; entry
; entry
= entry
->next
)
6262 row
= (isom_trun_optional_row_t
*)entry
->data
;
6265 if( ++i
== sample_number
)
6271 int lsmash_create_fragment_empty_duration( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t duration
)
6273 if( !root
|| !root
->fragment
|| !root
->fragment
->movie
|| !root
->moov
)
6275 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6276 if( !trak
|| !trak
->tkhd
)
6278 isom_trex_entry_t
*trex
= isom_get_trex( root
->moov
->mvex
, track_ID
);
6281 isom_moof_entry_t
*moof
= root
->fragment
->movie
;
6282 isom_traf_entry_t
*traf
= isom_get_traf( moof
, track_ID
);
6285 traf
= isom_add_traf( root
, moof
);
6286 if( isom_add_tfhd( traf
) )
6288 isom_tfhd_t
*tfhd
= traf
->tfhd
;
6289 tfhd
->flags
= ISOM_TF_FLAGS_DURATION_IS_EMPTY
; /* no samples for this track fragment yet */
6290 tfhd
->track_ID
= trak
->tkhd
->track_ID
;
6291 tfhd
->default_sample_duration
= duration
;
6292 if( duration
!= trex
->default_sample_duration
)
6293 tfhd
->flags
|= ISOM_TF_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT
;
6294 traf
->cache
= trak
->cache
;
6295 traf
->cache
->fragment
->traf_number
= moof
->traf_list
->entry_count
;
6296 traf
->cache
->fragment
->last_duration
+= duration
; /* The duration of the last sample includes this empty-duration. */
6300 static int isom_set_fragment_last_duration( isom_traf_entry_t
*traf
, uint32_t last_duration
)
6302 isom_tfhd_t
*tfhd
= traf
->tfhd
;
6303 if( !traf
->trun_list
|| !traf
->trun_list
->tail
|| !traf
->trun_list
->tail
->data
)
6305 /* There are no track runs in this track fragment, so it is a empty-duration. */
6306 isom_trex_entry_t
*trex
= isom_get_trex( traf
->root
->moov
->mvex
, tfhd
->track_ID
);
6309 tfhd
->flags
|= ISOM_TF_FLAGS_DURATION_IS_EMPTY
;
6310 if( last_duration
!= trex
->default_sample_duration
)
6311 tfhd
->flags
|= ISOM_TF_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT
;
6312 tfhd
->default_sample_duration
= last_duration
;
6313 traf
->cache
->fragment
->last_duration
= last_duration
;
6316 /* Update the last sample_duration if needed. */
6317 isom_trun_entry_t
*trun
= (isom_trun_entry_t
*)traf
->trun_list
->tail
->data
;
6318 if( trun
->sample_count
== 1 && traf
->trun_list
->entry_count
== 1 )
6320 isom_trex_entry_t
*trex
= isom_get_trex( traf
->root
->moov
->mvex
, tfhd
->track_ID
);
6323 if( last_duration
!= trex
->default_sample_duration
)
6324 tfhd
->flags
|= ISOM_TF_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT
;
6325 tfhd
->default_sample_duration
= last_duration
;
6327 else if( last_duration
!= tfhd
->default_sample_duration
)
6328 trun
->flags
|= ISOM_TR_FLAGS_SAMPLE_DURATION_PRESENT
;
6331 isom_trun_optional_row_t
*row
= isom_request_trun_optional_row( trun
, tfhd
, trun
->sample_count
);
6334 row
->sample_duration
= last_duration
;
6336 traf
->cache
->fragment
->last_duration
= last_duration
;
6340 int lsmash_set_last_sample_delta( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t sample_delta
)
6342 if( !root
|| !track_ID
)
6344 if( root
->fragment
&& root
->fragment
->movie
)
6346 isom_traf_entry_t
*traf
= isom_get_traf( root
->fragment
->movie
, track_ID
);
6347 if( !traf
|| !traf
->cache
|| !traf
->tfhd
|| !traf
->trun_list
)
6349 return isom_set_fragment_last_duration( traf
, sample_delta
);
6351 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6352 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->mdhd
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
6353 || !trak
->mdia
->minf
->stbl
->stsz
|| !trak
->mdia
->minf
->stbl
->stts
|| !trak
->mdia
->minf
->stbl
->stts
->list
)
6355 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
6356 isom_stts_t
*stts
= stbl
->stts
;
6357 uint32_t sample_count
= isom_get_sample_count( trak
);
6358 if( !stts
->list
->tail
)
6361 return 0; /* no samples */
6362 if( sample_count
> 1 )
6363 return -1; /* irregular sample_count */
6364 if( isom_add_stts_entry( stbl
, sample_delta
) )
6366 return lsmash_update_track_duration( root
, track_ID
, 0 );
6369 for( lsmash_entry_t
*entry
= stts
->list
->head
; entry
; entry
= entry
->next
)
6370 i
+= ((isom_stts_entry_t
*)entry
->data
)->sample_count
;
6371 if( sample_count
< i
)
6373 isom_stts_entry_t
*last_stts_data
= (isom_stts_entry_t
*)stts
->list
->tail
->data
;
6374 if( !last_stts_data
)
6376 if( sample_count
> i
)
6378 if( sample_count
- i
> 1 )
6380 /* Add a sample_delta. */
6381 if( sample_delta
== last_stts_data
->sample_delta
)
6382 ++ last_stts_data
->sample_count
;
6383 else if( isom_add_stts_entry( stbl
, sample_delta
) )
6386 else if( sample_count
== i
&& isom_replace_last_sample_delta( stbl
, sample_delta
) )
6388 return lsmash_update_track_duration( root
, track_ID
, sample_delta
);
6391 void lsmash_discard_boxes( lsmash_root_t
*root
)
6395 isom_remove_ftyp( root
->ftyp
);
6396 isom_remove_moov( root
);
6397 lsmash_remove_list( root
->moof_list
, isom_remove_moof
);
6398 isom_remove_mdat( root
->mdat
);
6399 isom_remove_free( root
->free
);
6400 isom_remove_meta( root
->meta
);
6401 isom_remove_mfra( root
->mfra
);
6404 root
->moof_list
= NULL
;
6410 void lsmash_destroy_root( lsmash_root_t
*root
)
6414 #ifdef LSMASH_DEMUXER_ENABLED
6415 isom_remove_print_funcs( root
);
6416 isom_remove_timelines( root
);
6418 lsmash_discard_boxes( root
);
6421 if( root
->bs
->stream
)
6422 fclose( root
->bs
->stream
);
6423 if( root
->bs
->data
)
6424 free( root
->bs
->data
);
6427 if( root
->fragment
)
6429 lsmash_remove_list( root
->fragment
->pool
, lsmash_delete_sample
);
6430 free( root
->fragment
);
6435 /*---- timeline manipulator ----*/
6437 int lsmash_modify_explicit_timeline_map( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t edit_number
, lsmash_edit_t edit
)
6439 if( !edit
.duration
|| edit
.start_time
< -1 )
6441 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6442 if( !trak
|| !trak
->edts
|| !trak
->edts
->elst
|| !trak
->edts
->elst
->list
)
6444 isom_elst_t
*elst
= trak
->edts
->elst
;
6445 isom_elst_entry_t
*data
= (isom_elst_entry_t
*)lsmash_get_entry_data( elst
->list
, edit_number
);
6448 data
->segment_duration
= edit
.duration
;
6449 data
->media_time
= edit
.start_time
;
6450 data
->media_rate
= edit
.rate
;
6451 if( !elst
->pos
|| !root
->fragment
|| root
->bs
->stream
== stdout
)
6452 return isom_update_tkhd_duration( trak
);
6453 /* Rewrite the specified entry.
6454 * Note: we don't update the version of the Edit List Box. */
6455 lsmash_bs_t
*bs
= root
->bs
;
6456 FILE *stream
= bs
->stream
;
6457 uint64_t current_pos
= lsmash_ftell( stream
);
6458 uint64_t entry_pos
= elst
->pos
+ ISOM_LIST_FULLBOX_COMMON_SIZE
+ ((uint64_t)edit_number
- 1) * (elst
->version
== 1 ? 20 : 12);
6459 lsmash_fseek( stream
, entry_pos
, SEEK_SET
);
6462 lsmash_bs_put_be64( bs
, data
->segment_duration
);
6463 lsmash_bs_put_be64( bs
, data
->media_time
);
6467 lsmash_bs_put_be32( bs
, (uint32_t)LSMASH_MIN( data
->segment_duration
, UINT32_MAX
) );
6468 lsmash_bs_put_be32( bs
, (uint32_t)data
->media_time
);
6470 lsmash_bs_put_be32( bs
, data
->media_rate
);
6471 int ret
= lsmash_bs_write_data( bs
);
6472 lsmash_fseek( stream
, current_pos
, SEEK_SET
);
6476 int lsmash_create_explicit_timeline_map( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_edit_t edit
)
6478 if( edit
.start_time
< -1 )
6480 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6481 if( !trak
|| !trak
->tkhd
)
6483 edit
.duration
= (edit
.duration
|| root
->fragment
) ? edit
.duration
6484 : trak
->tkhd
->duration
? trak
->tkhd
->duration
6485 : isom_update_tkhd_duration( trak
) ? 0
6486 : trak
->tkhd
->duration
;
6487 if( isom_add_edts( trak
)
6488 || isom_add_elst( trak
->edts
)
6489 || isom_add_elst_entry( trak
->edts
->elst
, edit
.duration
, edit
.start_time
, edit
.rate
) )
6491 return isom_update_tkhd_duration( trak
);
6494 int lsmash_get_explicit_timeline_map( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t edit_number
, lsmash_edit_t
*edit
)
6498 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6501 if( !trak
->edts
|| !trak
->edts
->elst
)
6505 edit
->start_time
= 0;
6509 isom_elst_entry_t
*elst
= (isom_elst_entry_t
*)lsmash_get_entry_data( trak
->edts
->elst
->list
, edit_number
);
6512 edit
->duration
= elst
->segment_duration
;
6513 edit
->start_time
= elst
->media_time
;
6514 edit
->rate
= elst
->media_rate
;
6518 uint32_t lsmash_count_explicit_timeline_map( lsmash_root_t
*root
, uint32_t track_ID
)
6520 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6521 if( !trak
|| !trak
->edts
|| !trak
->edts
->elst
|| !trak
->edts
->elst
->list
)
6523 return trak
->edts
->elst
->list
->entry_count
;
6526 /*---- create / modification time fields manipulators ----*/
6528 int lsmash_update_media_modification_time( lsmash_root_t
*root
, uint32_t track_ID
)
6530 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6531 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->mdhd
)
6533 isom_mdhd_t
*mdhd
= trak
->mdia
->mdhd
;
6534 mdhd
->modification_time
= isom_get_current_mp4time();
6535 /* overwrite strange creation_time */
6536 if( mdhd
->creation_time
> mdhd
->modification_time
)
6537 mdhd
->creation_time
= mdhd
->modification_time
;
6541 int lsmash_update_track_modification_time( lsmash_root_t
*root
, uint32_t track_ID
)
6543 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
6544 if( !trak
|| !trak
->tkhd
)
6546 isom_tkhd_t
*tkhd
= trak
->tkhd
;
6547 tkhd
->modification_time
= isom_get_current_mp4time();
6548 /* overwrite strange creation_time */
6549 if( tkhd
->creation_time
> tkhd
->modification_time
)
6550 tkhd
->creation_time
= tkhd
->modification_time
;
6554 int lsmash_update_movie_modification_time( lsmash_root_t
*root
)
6556 if( !root
|| !root
->moov
|| !root
->moov
->mvhd
)
6558 isom_mvhd_t
*mvhd
= root
->moov
->mvhd
;
6559 mvhd
->modification_time
= isom_get_current_mp4time();
6560 /* overwrite strange creation_time */
6561 if( mvhd
->creation_time
> mvhd
->modification_time
)
6562 mvhd
->creation_time
= mvhd
->modification_time
;
6566 /*---- sample manipulators ----*/
6567 lsmash_sample_t
*lsmash_create_sample( uint32_t size
)
6569 lsmash_sample_t
*sample
= lsmash_malloc_zero( sizeof(lsmash_sample_t
) );
6574 sample
->data
= malloc( size
);
6580 sample
->length
= size
;
6584 int lsmash_sample_alloc( lsmash_sample_t
*sample
, uint32_t size
)
6591 free( sample
->data
);
6592 sample
->data
= NULL
;
6596 if( size
== sample
->length
)
6600 data
= malloc( size
);
6602 data
= realloc( sample
->data
, size
);
6605 sample
->data
= data
;
6606 sample
->length
= size
;
6610 void lsmash_delete_sample( lsmash_sample_t
*sample
)
6615 free( sample
->data
);
6619 isom_sample_pool_t
*isom_create_sample_pool( uint64_t size
)
6621 isom_sample_pool_t
*pool
= lsmash_malloc_zero( sizeof(isom_sample_pool_t
) );
6626 pool
->data
= malloc( size
);
6636 static void isom_remove_sample_pool( isom_sample_pool_t
*pool
)
6645 static uint32_t isom_add_size( isom_trak_entry_t
*trak
, uint32_t sample_size
)
6647 if( isom_add_stsz_entry( trak
->mdia
->minf
->stbl
, sample_size
) )
6649 return isom_get_sample_count( trak
);
6652 static uint32_t isom_add_dts( isom_stbl_t
*stbl
, isom_timestamp_t
*cache
, uint64_t dts
)
6654 isom_stts_t
*stts
= stbl
->stts
;
6655 if( !stts
->list
->entry_count
)
6657 if( isom_add_stts_entry( stbl
, dts
) )
6662 if( dts
<= cache
->dts
)
6664 uint32_t sample_delta
= dts
- cache
->dts
;
6665 isom_stts_entry_t
*data
= (isom_stts_entry_t
*)stts
->list
->tail
->data
;
6666 if( data
->sample_delta
== sample_delta
)
6667 ++ data
->sample_count
;
6668 else if( isom_add_stts_entry( stbl
, sample_delta
) )
6671 return sample_delta
;
6674 static int isom_add_cts( isom_stbl_t
*stbl
, isom_timestamp_t
*cache
, uint64_t cts
)
6676 isom_ctts_t
*ctts
= stbl
->ctts
;
6679 if( cts
== cache
->dts
)
6684 /* Add ctts box and the first ctts entry. */
6685 if( isom_add_ctts( stbl
) || isom_add_ctts_entry( stbl
, 0 ) )
6688 isom_ctts_entry_t
*data
= (isom_ctts_entry_t
*)ctts
->list
->head
->data
;
6689 uint32_t sample_count
= stbl
->stsz
->sample_count
;
6690 if( sample_count
!= 1 )
6692 data
->sample_count
= sample_count
- 1;
6693 if( isom_add_ctts_entry( stbl
, cts
- cache
->dts
) )
6697 data
->sample_offset
= cts
;
6703 isom_ctts_entry_t
*data
= (isom_ctts_entry_t
*)ctts
->list
->tail
->data
;
6704 uint32_t sample_offset
= cts
- cache
->dts
;
6705 if( data
->sample_offset
== sample_offset
)
6706 ++ data
->sample_count
;
6707 else if( isom_add_ctts_entry( stbl
, sample_offset
) )
6713 static int isom_add_timestamp( isom_trak_entry_t
*trak
, uint64_t dts
, uint64_t cts
)
6715 if( !trak
->cache
|| !trak
->mdia
->minf
->stbl
->stts
|| !trak
->mdia
->minf
->stbl
->stts
->list
)
6717 lsmash_root_t
*root
= trak
->root
;
6718 if( root
->isom_compatible
&& root
->qt_compatible
&& (cts
- dts
) > INT32_MAX
)
6719 return -1; /* sample_offset is not compatible. */
6720 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
6721 isom_timestamp_t
*ts_cache
= &trak
->cache
->timestamp
;
6722 uint32_t sample_count
= isom_get_sample_count( trak
);
6723 uint32_t sample_delta
= sample_count
> 1 ? isom_add_dts( stbl
, ts_cache
, dts
) : 0;
6724 if( sample_count
> 1 && !sample_delta
)
6726 if( isom_add_cts( stbl
, ts_cache
, cts
) )
6728 if( (cts
+ ts_cache
->ctd_shift
) < dts
)
6730 if( (root
->max_isom_version
< 4 && !root
->qt_compatible
) /* Negative sample offset is not supported. */
6731 || (root
->max_isom_version
>= 4 && trak
->root
->qt_compatible
) /* ctts version 1 is not defined in QTFF. */
6732 || ((dts
- cts
) > INT32_MAX
) ) /* Overflow */
6734 ts_cache
->ctd_shift
= dts
- cts
;
6735 if( stbl
->ctts
->version
== 0 && !trak
->root
->qt_compatible
)
6736 stbl
->ctts
->version
= 1;
6738 if( trak
->cache
->fragment
)
6740 isom_fragment_t
*fragment_cache
= trak
->cache
->fragment
;
6741 fragment_cache
->last_duration
= sample_delta
;
6742 fragment_cache
->largest_cts
= LSMASH_MAX( ts_cache
->cts
, fragment_cache
->largest_cts
);
6747 static int isom_add_sync_point( isom_trak_entry_t
*trak
, uint32_t sample_number
, lsmash_sample_property_t
*prop
)
6749 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
6750 isom_cache_t
*cache
= trak
->cache
;
6751 if( !(prop
->ra_flags
& ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC
) ) /* no null check for prop */
6753 if( !cache
->all_sync
)
6755 if( !stbl
->stss
&& isom_add_stss( stbl
) )
6757 if( isom_add_stss_entry( stbl
, 1 ) ) /* Declare here the first sample is a sync sample. */
6759 cache
->all_sync
= 0;
6762 if( cache
->all_sync
) /* We don't need stss box if all samples are sync sample. */
6766 if( isom_get_sample_count( trak
) == 1 )
6768 cache
->all_sync
= 1; /* Also the first sample is a sync sample. */
6771 if( isom_add_stss( stbl
) )
6774 return isom_add_stss_entry( stbl
, sample_number
);
6777 static int isom_add_partial_sync( isom_trak_entry_t
*trak
, uint32_t sample_number
, lsmash_sample_property_t
*prop
)
6779 if( !trak
->root
->qt_compatible
)
6781 if( !(prop
->ra_flags
& QT_SAMPLE_RANDOM_ACCESS_FLAG_PARTIAL_SYNC
)
6782 && !(LSMASH_IS_POST_ROLL_START( prop
->ra_flags
) && prop
->post_roll
.identifier
== prop
->post_roll
.complete
) )
6784 /* This sample is a partial sync sample. */
6785 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
6786 if( !stbl
->stps
&& isom_add_stps( stbl
) )
6788 return isom_add_stps_entry( stbl
, sample_number
);
6791 static int isom_add_dependency_type( isom_trak_entry_t
*trak
, lsmash_sample_property_t
*prop
)
6793 if( !trak
->root
->qt_compatible
&& !trak
->root
->avc_extensions
)
6795 uint8_t avc_extensions
= trak
->root
->avc_extensions
;
6796 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
6798 return isom_add_sdtp_entry( (isom_box_t
*)stbl
, prop
, avc_extensions
);
6799 if( !prop
->allow_earlier
&& !prop
->leading
&& !prop
->independent
&& !prop
->disposable
&& !prop
->redundant
) /* no null check for prop */
6801 if( isom_add_sdtp( (isom_box_t
*)stbl
) )
6803 uint32_t count
= isom_get_sample_count( trak
);
6804 /* fill past samples with ISOM_SAMPLE_*_UNKNOWN */
6805 lsmash_sample_property_t null_prop
= { 0 };
6806 for( uint32_t i
= 1; i
< count
; i
++ )
6807 if( isom_add_sdtp_entry( (isom_box_t
*)stbl
, &null_prop
, avc_extensions
) )
6809 return isom_add_sdtp_entry( (isom_box_t
*)stbl
, prop
, avc_extensions
);
6812 static int isom_rap_grouping_established( isom_rap_group_t
*group
, int num_leading_samples_known
, isom_sgpd_entry_t
*sgpd
)
6814 isom_rap_entry_t
*rap
= group
->random_access
;
6817 assert( rap
== (isom_rap_entry_t
*)sgpd
->list
->tail
->data
);
6818 rap
->num_leading_samples_known
= num_leading_samples_known
;
6819 /* Avoid duplication of sample group descriptions. */
6820 uint32_t group_description_index
= 1;
6821 for( lsmash_entry_t
*entry
= sgpd
->list
->head
; entry
!= sgpd
->list
->tail
; entry
= entry
->next
)
6823 isom_rap_entry_t
*data
= (isom_rap_entry_t
*)entry
->data
;
6826 if( rap
->num_leading_samples_known
== data
->num_leading_samples_known
6827 && rap
->num_leading_samples
== data
->num_leading_samples
)
6829 /* The same description already exists.
6830 * Remove the latest random access entry. */
6831 lsmash_remove_entry_direct( sgpd
->list
, sgpd
->list
->tail
, NULL
);
6832 /* Replace assigned group_description_index with the one corresponding the same description. */
6833 if( group
->assignment
->group_description_index
== 0 )
6835 if( group
->prev_assignment
)
6836 group
->prev_assignment
->group_description_index
= group_description_index
;
6839 group
->assignment
->group_description_index
= group_description_index
;
6842 ++group_description_index
;
6844 group
->random_access
= NULL
;
6848 static int isom_group_random_access( isom_trak_entry_t
*trak
, lsmash_sample_property_t
*prop
)
6850 if( trak
->root
->max_isom_version
< 6 )
6852 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
6853 isom_sbgp_entry_t
*sbgp
= isom_get_sample_to_group( stbl
, ISOM_GROUP_TYPE_RAP
);
6854 isom_sgpd_entry_t
*sgpd
= isom_get_sample_group_description( stbl
, ISOM_GROUP_TYPE_RAP
);
6855 if( !sbgp
|| !sgpd
)
6857 uint8_t is_rap
= (prop
->ra_flags
& ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC
)
6858 || (prop
->ra_flags
& QT_SAMPLE_RANDOM_ACCESS_FLAG_PARTIAL_SYNC
)
6859 || (prop
->ra_flags
& ISOM_SAMPLE_RANDOM_ACCESS_FLAG_RAP
)
6860 || (LSMASH_IS_POST_ROLL_START( prop
->ra_flags
) && prop
->post_roll
.identifier
== prop
->post_roll
.complete
);
6861 isom_rap_group_t
*group
= trak
->cache
->rap
;
6864 /* This sample is the first sample, create a grouping cache. */
6865 assert( isom_get_sample_count( trak
) == 1 );
6866 group
= malloc( sizeof(isom_rap_group_t
) );
6871 group
->random_access
= isom_add_rap_group_entry( sgpd
);
6872 group
->assignment
= isom_add_group_assignment_entry( sbgp
, 1, sgpd
->list
->entry_count
);
6876 /* The first sample is not always random access point. */
6877 group
->random_access
= NULL
;
6878 group
->assignment
= isom_add_group_assignment_entry( sbgp
, 1, 0 );
6880 if( !group
->assignment
)
6885 group
->prev_assignment
= NULL
;
6886 group
->is_prev_rap
= is_rap
;
6887 trak
->cache
->rap
= group
;
6890 if( group
->is_prev_rap
)
6892 /* OK. here, the previous sample is a menber of 'rap '. */
6895 /* This sample isn't a member of 'rap ' and the previous sample is.
6896 * So we create a new group and set 0 on its group_description_index. */
6897 group
->prev_assignment
= group
->assignment
;
6898 group
->assignment
= isom_add_group_assignment_entry( sbgp
, 1, 0 );
6899 if( !group
->assignment
)
6905 else if( !LSMASH_IS_CLOSED_RAP( prop
->ra_flags
) )
6907 /* Create a new group since there is the possibility the next sample is a leading sample.
6908 * This sample is a member of 'rap ', so we set appropriate value on its group_description_index. */
6909 if( isom_rap_grouping_established( group
, 1, sgpd
) )
6911 group
->random_access
= isom_add_rap_group_entry( sgpd
);
6912 group
->prev_assignment
= group
->assignment
;
6913 group
->assignment
= isom_add_group_assignment_entry( sbgp
, 1, sgpd
->list
->entry_count
);
6914 if( !group
->assignment
)
6920 else /* The previous and current sample are a member of 'rap ', and the next sample must not be a leading sample. */
6921 ++ group
->assignment
->sample_count
;
6925 /* This sample is a member of 'rap ' and the previous sample isn't.
6926 * So we create a new group and set appropriate value on its group_description_index. */
6927 if( isom_rap_grouping_established( group
, 1, sgpd
) )
6929 group
->random_access
= isom_add_rap_group_entry( sgpd
);
6930 group
->prev_assignment
= group
->assignment
;
6931 group
->assignment
= isom_add_group_assignment_entry( sbgp
, 1, sgpd
->list
->entry_count
);
6932 if( !group
->assignment
)
6938 else /* The previous and current sample aren't a member of 'rap '. */
6939 ++ group
->assignment
->sample_count
;
6940 /* Obtain the property of the latest random access point group. */
6941 if( !is_rap
&& group
->random_access
)
6943 if( prop
->leading
== ISOM_SAMPLE_LEADING_UNKNOWN
)
6945 /* We can no longer know num_leading_samples in this group. */
6946 if( isom_rap_grouping_established( group
, 0, sgpd
) )
6951 if( prop
->leading
== ISOM_SAMPLE_IS_UNDECODABLE_LEADING
|| prop
->leading
== ISOM_SAMPLE_IS_DECODABLE_LEADING
)
6952 ++ group
->random_access
->num_leading_samples
;
6953 /* no more consecutive leading samples in this group */
6954 else if( isom_rap_grouping_established( group
, 1, sgpd
) )
6958 group
->is_prev_rap
= is_rap
;
6962 static int isom_roll_grouping_established( isom_roll_group_t
*group
, int16_t roll_distance
, isom_sgpd_entry_t
*sgpd
)
6964 /* Avoid duplication of sample group descriptions. */
6965 uint32_t group_description_index
= 1;
6966 for( lsmash_entry_t
*entry
= sgpd
->list
->head
; entry
; entry
= entry
->next
)
6968 isom_roll_entry_t
*data
= (isom_roll_entry_t
*)entry
->data
;
6971 if( roll_distance
== data
->roll_distance
)
6973 /* The same description already exists.
6974 * Set the group_description_index corresponding the same description. */
6975 group
->assignment
->group_description_index
= group_description_index
;
6976 group
->described
= 1;
6979 ++group_description_index
;
6981 /* Add a new roll recovery description. */
6982 if( !isom_add_roll_group_entry( sgpd
, roll_distance
) )
6984 group
->assignment
->group_description_index
= sgpd
->list
->entry_count
;
6985 group
->described
= 1;
6989 static int isom_deduplicate_roll_group( isom_sbgp_entry_t
*sbgp
, lsmash_entry_list_t
*pool
)
6992 uint32_t current_group_number
= sbgp
->list
->entry_count
- pool
->entry_count
+ 1;
6993 isom_group_assignment_entry_t
*prev_assignment
= (isom_group_assignment_entry_t
*)lsmash_get_entry_data( sbgp
->list
, current_group_number
- 1 );
6994 for( lsmash_entry_t
*entry
= pool
->head
; entry
; )
6996 isom_roll_group_t
*group
= (isom_roll_group_t
*)entry
->data
;
6997 if( !group
|| !group
->assignment
)
6999 if( !group
->delimited
|| !group
->described
)
7001 if( prev_assignment
&& prev_assignment
->group_description_index
== group
->assignment
->group_description_index
)
7003 /* Merge the current group with the previous. */
7004 lsmash_entry_t
*next_entry
= entry
->next
;
7005 prev_assignment
->sample_count
+= group
->assignment
->sample_count
;
7006 if( lsmash_remove_entry( sbgp
->list
, current_group_number
, NULL
)
7007 || lsmash_remove_entry_direct( pool
, entry
, NULL
) )
7013 entry
= entry
->next
;
7014 prev_assignment
= group
->assignment
;
7015 ++current_group_number
;
7021 /* Remove pooled caches that has become unnecessary. */
7022 static int isom_clean_roll_pool( isom_sbgp_entry_t
*sbgp
, lsmash_entry_list_t
*pool
)
7024 for( lsmash_entry_t
*entry
= pool
->head
; entry
; entry
= pool
->head
)
7026 isom_roll_group_t
*group
= (isom_roll_group_t
*)entry
->data
;
7029 if( !group
->delimited
|| !group
->described
)
7031 if( lsmash_remove_entry_direct( pool
, entry
, NULL
) )
7037 static int isom_flush_roll_pool( isom_sbgp_entry_t
*sbgp
, lsmash_entry_list_t
*pool
)
7039 if( isom_deduplicate_roll_group( sbgp
, pool
) )
7041 return isom_clean_roll_pool( sbgp
, pool
);
7044 static int isom_all_recovery_described( isom_sbgp_entry_t
*sbgp
, lsmash_entry_list_t
*pool
)
7046 for( lsmash_entry_t
*entry
= pool
->head
; entry
; entry
= entry
->next
)
7048 isom_roll_group_t
*group
= (isom_roll_group_t
*)entry
->data
;
7051 group
->described
= 1;
7053 return isom_flush_roll_pool( sbgp
, pool
);
7056 static int isom_group_roll_recovery( isom_trak_entry_t
*trak
, lsmash_sample_property_t
*prop
)
7058 if( !trak
->root
->avc_extensions
&& !trak
->root
->qt_compatible
)
7060 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
7061 isom_sbgp_entry_t
*sbgp
= isom_get_sample_to_group( stbl
, ISOM_GROUP_TYPE_ROLL
);
7062 isom_sgpd_entry_t
*sgpd
= isom_get_sample_group_description( stbl
, ISOM_GROUP_TYPE_ROLL
);
7063 if( !sbgp
|| !sgpd
)
7065 lsmash_entry_list_t
*pool
= trak
->cache
->roll
.pool
;
7068 pool
= lsmash_create_entry_list();
7071 trak
->cache
->roll
.pool
= pool
;
7073 isom_roll_group_t
*group
= (isom_roll_group_t
*)lsmash_get_entry_data( pool
, pool
->entry_count
);
7074 uint32_t sample_count
= isom_get_sample_count( trak
);
7075 int is_recovery_start
= LSMASH_IS_POST_ROLL_START( prop
->ra_flags
);
7076 int valid_pre_roll
= !is_recovery_start
&& (prop
->ra_flags
!= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_NONE
)
7077 && (prop
->pre_roll
.distance
> 0) && (prop
->pre_roll
.distance
<= -INT16_MIN
);
7078 int new_group
= !group
|| is_recovery_start
|| (group
->prev_is_recovery_start
!= is_recovery_start
);
7081 /* Check pre-roll distance. */
7082 if( !group
->assignment
)
7084 isom_roll_entry_t
*prev_roll
= (isom_roll_entry_t
*)lsmash_get_entry_data( sgpd
->list
, group
->assignment
->group_description_index
);
7086 new_group
= valid_pre_roll
;
7087 else if( !valid_pre_roll
|| (prop
->pre_roll
.distance
!= -prev_roll
->roll_distance
) )
7088 /* Pre-roll distance is different from the previous. */
7094 group
->delimited
= 1;
7096 assert( sample_count
== 1 );
7097 /* Create a new group. */
7098 group
= lsmash_malloc_zero( sizeof(isom_roll_group_t
) );
7101 group
->prev_is_recovery_start
= is_recovery_start
;
7102 group
->assignment
= isom_add_group_assignment_entry( sbgp
, 1, 0 );
7103 if( !group
->assignment
|| lsmash_add_entry( pool
, group
) )
7108 if( is_recovery_start
)
7110 /* a member of non-roll or post-roll group */
7111 group
->first_sample
= sample_count
;
7112 group
->recovery_point
= prop
->post_roll
.complete
;
7116 if( valid_pre_roll
)
7118 /* a member of pre-roll group */
7119 if( isom_roll_grouping_established( group
, -prop
->pre_roll
.distance
, sgpd
) )
7123 /* a member of non-roll group */
7124 group
->described
= 1;
7129 group
->prev_is_recovery_start
= is_recovery_start
;
7130 ++ group
->assignment
->sample_count
;
7132 /* If encountered a sync sample, all recovery is completed here. */
7133 if( prop
->ra_flags
& ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC
)
7134 return isom_all_recovery_described( sbgp
, pool
);
7135 /* Check whether this sample is a random access recovery point or not. */
7136 for( lsmash_entry_t
*entry
= pool
->head
; entry
; entry
= entry
->next
)
7138 group
= (isom_roll_group_t
*)entry
->data
;
7141 if( group
->described
)
7143 if( prop
->post_roll
.identifier
== group
->recovery_point
)
7145 int16_t distance
= sample_count
- group
->first_sample
;
7146 /* Add a roll recovery entry only when roll_distance isn't zero since roll_distance = 0 must not be used. */
7149 /* Now, this group is a 'roll'. */
7150 if( isom_roll_grouping_established( group
, distance
, sgpd
) )
7152 /* All groups before the current group are described. */
7153 lsmash_entry_t
*current
= entry
;
7154 for( entry
= pool
->head
; entry
!= current
; entry
= entry
->next
)
7156 group
= (isom_roll_group_t
*)entry
->data
;
7159 group
->described
= 1;
7163 group
->described
= 1;
7164 break; /* Avoid evaluating groups, in the pool, having the same identifier for recovery point again. */
7167 return isom_flush_roll_pool( sbgp
, pool
);
7170 /* returns 1 if pooled samples must be flushed. */
7171 /* FIXME: I wonder if this function should have a extra argument which indicates force_to_flush_cached_chunk.
7172 see lsmash_append_sample for detail. */
7173 static int isom_add_chunk( isom_trak_entry_t
*trak
, lsmash_sample_t
*sample
)
7175 if( !trak
->root
|| !trak
->cache
|| !trak
->mdia
->mdhd
|| !trak
->mdia
->mdhd
->timescale
7176 || !trak
->mdia
->minf
->stbl
->stsc
|| !trak
->mdia
->minf
->stbl
->stsc
->list
)
7178 lsmash_root_t
*root
= trak
->root
;
7179 isom_chunk_t
*current
= &trak
->cache
->chunk
;
7180 if( !current
->pool
)
7182 /* Very initial settings, just once per track */
7183 current
->pool
= isom_create_sample_pool( 0 );
7184 if( !current
->pool
)
7187 if( !current
->pool
->sample_count
)
7189 /* Cannot decide whether we should flush the current sample or not here yet. */
7190 ++ current
->chunk_number
;
7191 current
->sample_description_index
= sample
->index
;
7192 current
->first_dts
= sample
->dts
;
7195 if( sample
->dts
< current
->first_dts
)
7196 return -1; /* easy error check. */
7197 if( (root
->max_chunk_duration
>= ((double)(sample
->dts
- current
->first_dts
) / trak
->mdia
->mdhd
->timescale
))
7198 && (root
->max_chunk_size
>= current
->pool
->size
+ sample
->length
)
7199 && (current
->sample_description_index
== sample
->index
) )
7200 return 0; /* No need to flush current cached chunk, the current sample must be put into that. */
7201 /* NOTE: chunk relative stuff must be pushed into root after a chunk is fully determined with its contents. */
7202 /* now current cached chunk is fixed, actually add chunk relative properties to root accordingly. */
7203 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
7204 isom_stsc_entry_t
*last_stsc_data
= stbl
->stsc
->list
->tail
? (isom_stsc_entry_t
*)stbl
->stsc
->list
->tail
->data
: NULL
;
7205 /* Create a new chunk sequence in this track if needed. */
7206 if( (!last_stsc_data
7207 || current
->pool
->sample_count
!= last_stsc_data
->samples_per_chunk
7208 || current
->sample_description_index
!= last_stsc_data
->sample_description_index
)
7209 && isom_add_stsc_entry( stbl
, current
->chunk_number
, current
->pool
->sample_count
, current
->sample_description_index
) )
7211 /* Add a new chunk offset in this track. */
7212 uint64_t offset
= root
->size
;
7213 if( root
->fragment
)
7214 offset
+= ISOM_BASEBOX_COMMON_SIZE
+ root
->fragment
->pool_size
;
7215 if( isom_add_stco_entry( stbl
, offset
) )
7217 /* update cache information */
7218 ++ current
->chunk_number
;
7219 /* re-initialize cache, using the current sample */
7220 current
->sample_description_index
= sample
->index
;
7221 current
->first_dts
= sample
->dts
;
7222 /* current->pool must be flushed in isom_append_sample_internal() */
7226 static int isom_write_pooled_samples( lsmash_root_t
*root
, isom_sample_pool_t
*pool
)
7228 if( !root
|| !root
->mdat
|| !root
->bs
|| !root
->bs
->stream
)
7230 lsmash_bs_put_bytes( root
->bs
, pool
->size
, pool
->data
);
7231 if( lsmash_bs_write_data( root
->bs
) )
7233 root
->mdat
->size
+= pool
->size
;
7234 root
->size
+= pool
->size
;
7235 pool
->sample_count
= 0;
7240 static int isom_update_sample_tables( isom_trak_entry_t
*trak
, lsmash_sample_t
*sample
)
7242 /* Add a sample_size and increment sample_count. */
7243 uint32_t sample_count
= isom_add_size( trak
, sample
->length
);
7246 /* Add a decoding timestamp and a composition timestamp. */
7247 if( isom_add_timestamp( trak
, sample
->dts
, sample
->cts
) )
7249 /* Add a sync point if needed. */
7250 if( isom_add_sync_point( trak
, sample_count
, &sample
->prop
) )
7252 /* Add a partial sync point if needed. */
7253 if( isom_add_partial_sync( trak
, sample_count
, &sample
->prop
) )
7255 /* Add leading, independent, disposable and redundant information if needed. */
7256 if( isom_add_dependency_type( trak
, &sample
->prop
) )
7258 /* Group samples into random access point type if needed. */
7259 if( isom_group_random_access( trak
, &sample
->prop
) )
7261 /* Group samples into random access recovery point type if needed. */
7262 if( isom_group_roll_recovery( trak
, &sample
->prop
) )
7264 /* Add a chunk if needed. */
7265 return isom_add_chunk( trak
, sample
);
7268 static int isom_append_fragment_track_run( lsmash_root_t
*root
, isom_chunk_t
*chunk
)
7270 if( !chunk
->pool
|| !chunk
->pool
->size
)
7272 isom_fragment_manager_t
*fragment
= root
->fragment
;
7273 /* Move data in the pool of the current track fragment to the pool of the current movie fragment.
7274 * Empty the pool of current track. We don't delete data of samples here. */
7275 if( lsmash_add_entry( fragment
->pool
, chunk
->pool
) )
7277 fragment
->pool
->entry_count
+= chunk
->pool
->sample_count
;
7278 fragment
->pool_size
+= chunk
->pool
->size
;
7279 chunk
->pool
= isom_create_sample_pool( chunk
->pool
->size
);
7280 return chunk
->pool
? 0 : -1;
7283 static int isom_output_cached_chunk( isom_trak_entry_t
*trak
)
7285 lsmash_root_t
*root
= trak
->root
;
7286 isom_chunk_t
*chunk
= &trak
->cache
->chunk
;
7287 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
7288 isom_stsc_entry_t
*last_stsc_data
= stbl
->stsc
->list
->tail
? (isom_stsc_entry_t
*)stbl
->stsc
->list
->tail
->data
: NULL
;
7289 /* Create a new chunk sequence in this track if needed. */
7290 if( (!last_stsc_data
7291 || chunk
->pool
->sample_count
!= last_stsc_data
->samples_per_chunk
7292 || chunk
->sample_description_index
!= last_stsc_data
->sample_description_index
)
7293 && isom_add_stsc_entry( stbl
, chunk
->chunk_number
, chunk
->pool
->sample_count
, chunk
->sample_description_index
) )
7295 if( root
->fragment
)
7297 /* Add a new chunk offset in this track. */
7298 if( isom_add_stco_entry( stbl
, root
->size
+ ISOM_BASEBOX_COMMON_SIZE
+ root
->fragment
->pool_size
) )
7300 return isom_append_fragment_track_run( root
, chunk
);
7302 /* Add a new chunk offset in this track. */
7303 if( isom_add_stco_entry( stbl
, root
->size
) )
7305 /* Output pooled samples in this track. */
7306 return isom_write_pooled_samples( root
, chunk
->pool
);
7309 static int isom_pool_sample( isom_sample_pool_t
*pool
, lsmash_sample_t
*sample
)
7311 uint64_t pool_size
= pool
->size
+ sample
->length
;
7312 if( pool
->alloc
< pool_size
)
7315 uint64_t alloc
= pool_size
+ (1<<16);
7317 data
= malloc( alloc
);
7319 data
= realloc( pool
->data
, alloc
);
7323 pool
->alloc
= alloc
;
7325 memcpy( pool
->data
+ pool
->size
, sample
->data
, sample
->length
);
7326 pool
->size
= pool_size
;
7327 pool
->sample_count
+= 1;
7328 lsmash_delete_sample( sample
);
7332 static int isom_append_sample_internal( isom_trak_entry_t
*trak
, lsmash_sample_t
*sample
)
7334 int flush
= isom_update_sample_tables( trak
, sample
);
7337 /* flush == 1 means pooled samples must be flushed. */
7338 lsmash_root_t
*root
= trak
->root
;
7339 isom_sample_pool_t
*current_pool
= trak
->cache
->chunk
.pool
;
7340 if( flush
== 1 && isom_write_pooled_samples( root
, current_pool
) )
7342 /* Arbitration system between tracks with extremely scattering dts.
7343 * Here, we check whether asynchronization between the tracks exceeds the tolerance.
7344 * If a track has too old "first DTS" in its cached chunk than current sample's DTS, then its pooled samples must be flushed.
7345 * We don't consider presentation of media since any edit can pick an arbitrary portion of media in track.
7346 * Note: you needn't read this loop until you grasp the basic handling of chunks. */
7347 double tolerance
= root
->max_async_tolerance
;
7348 for( lsmash_entry_t
*entry
= root
->moov
->trak_list
->head
; entry
; entry
= entry
->next
)
7350 isom_trak_entry_t
*other
= (isom_trak_entry_t
*)entry
->data
;
7353 if( !other
|| !other
->cache
|| !other
->mdia
|| !other
->mdia
->mdhd
|| !other
->mdia
->mdhd
->timescale
7354 || !other
->mdia
->minf
|| !other
->mdia
->minf
->stbl
|| !other
->mdia
->minf
->stbl
->stsc
|| !other
->mdia
->minf
->stbl
->stsc
->list
)
7356 isom_chunk_t
*chunk
= &other
->cache
->chunk
;
7357 if( !chunk
->pool
|| !chunk
->pool
->sample_count
)
7359 double diff
= ((double)sample
->dts
/ trak
->mdia
->mdhd
->timescale
)
7360 - ((double)chunk
->first_dts
/ other
->mdia
->mdhd
->timescale
);
7361 if( diff
> tolerance
&& isom_output_cached_chunk( other
) )
7363 /* Note: we don't flush the cached chunk in the current track and the current sample here
7364 * even if the conditional expression of '-diff > tolerance' meets.
7365 * That's useless because appending a sample to another track would be a good equivalent.
7366 * It's even harmful because it causes excess chunk division by calling
7367 * isom_output_cached_chunk() which always generates a new chunk.
7368 * Anyway some excess chunk division will be there, but rather less without it.
7369 * To completely avoid this, we need to observe at least whether the current sample will be placed
7370 * right next to the previous chunk of the same track or not. */
7372 /* anyway the current sample must be pooled. */
7373 return isom_pool_sample( current_pool
, sample
);
7376 static int isom_append_sample( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_sample_t
*sample
)
7378 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
7379 if( !trak
|| !trak
->root
|| !trak
->cache
|| !trak
->mdia
7380 || !trak
->mdia
->mdhd
|| !trak
->mdia
->mdhd
->timescale
7381 || !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
7382 || !trak
->mdia
->minf
->stbl
->stsd
|| !trak
->mdia
->minf
->stbl
->stsd
->list
7383 || !trak
->mdia
->minf
->stbl
->stsc
|| !trak
->mdia
->minf
->stbl
->stsc
->list
)
7385 /* If there is no available Media Data Box to write samples, add and write a new one before any chunk offset is decided. */
7388 if( isom_new_mdat( root
, 0 ) )
7390 /* Add the size of the Media Data Box and the placeholder. */
7391 root
->size
+= 2 * ISOM_BASEBOX_COMMON_SIZE
;
7393 isom_sample_entry_t
*sample_entry
= (isom_sample_entry_t
*)lsmash_get_entry_data( trak
->mdia
->minf
->stbl
->stsd
->list
, sample
->index
);
7396 if( isom_is_lpcm_audio( sample_entry
) )
7398 uint32_t frame_size
= ((isom_audio_entry_t
*)sample_entry
)->constBytesPerAudioPacket
;
7399 if( sample
->length
== frame_size
)
7400 return isom_append_sample_internal( trak
, sample
);
7401 else if( sample
->length
< frame_size
)
7403 /* Append samples splitted into each LPCMFrame. */
7404 uint64_t dts
= sample
->dts
;
7405 uint64_t cts
= sample
->cts
;
7406 for( uint32_t offset
= 0; offset
< sample
->length
; offset
+= frame_size
)
7408 lsmash_sample_t
*lpcm_sample
= lsmash_create_sample( frame_size
);
7411 memcpy( lpcm_sample
->data
, sample
->data
+ offset
, frame_size
);
7412 lpcm_sample
->dts
= dts
++;
7413 lpcm_sample
->cts
= cts
++;
7414 lpcm_sample
->prop
= sample
->prop
;
7415 lpcm_sample
->index
= sample
->index
;
7416 if( isom_append_sample_internal( trak
, lpcm_sample
) )
7418 lsmash_delete_sample( lpcm_sample
);
7422 lsmash_delete_sample( sample
);
7425 return isom_append_sample_internal( trak
, sample
);
7428 static int isom_output_cache( isom_trak_entry_t
*trak
)
7430 if( trak
->cache
->chunk
.pool
&& trak
->cache
->chunk
.pool
->sample_count
7431 && isom_output_cached_chunk( trak
) )
7433 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
7434 if( !stbl
->sgpd_list
)
7436 for( lsmash_entry_t
*entry
= stbl
->sgpd_list
->head
; entry
; entry
= entry
->next
)
7438 isom_sgpd_entry_t
*sgpd
= (isom_sgpd_entry_t
*)entry
->data
;
7441 switch( sgpd
->grouping_type
)
7443 case ISOM_GROUP_TYPE_RAP
:
7445 isom_rap_group_t
*group
= trak
->cache
->rap
;
7448 if( trak
->root
->fragment
)
7453 if( !group
->random_access
)
7455 group
->random_access
->num_leading_samples_known
= 1;
7458 case ISOM_GROUP_TYPE_ROLL
:
7459 if( !trak
->cache
->roll
.pool
)
7461 if( trak
->root
->fragment
)
7466 for( lsmash_entry_t
*roll_entry
= trak
->cache
->roll
.pool
->head
; roll_entry
; roll_entry
= roll_entry
->next
)
7468 isom_roll_group_t
*group
= (isom_roll_group_t
*)roll_entry
->data
;
7471 group
->described
= 1;
7472 group
->delimited
= 1;
7474 isom_sbgp_entry_t
*sbgp
= isom_get_sample_to_group( stbl
, ISOM_GROUP_TYPE_ROLL
);
7475 if( isom_flush_roll_pool( sbgp
, trak
->cache
->roll
.pool
) )
7485 static int isom_flush_fragment_pooled_samples( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t last_sample_duration
)
7487 isom_traf_entry_t
*traf
= isom_get_traf( root
->fragment
->movie
, track_ID
);
7489 return 0; /* no samples */
7490 if( !traf
->cache
|| !traf
->cache
->fragment
)
7492 if( traf
->trun_list
&& traf
->trun_list
->entry_count
&& traf
->trun_list
->tail
&& traf
->trun_list
->tail
->data
)
7494 /* Media Data Box preceded by Movie Fragment Box could change base_data_offsets in each track fragments later.
7495 * We can't consider this here because the length of Movie Fragment Box is unknown at this step yet. */
7496 isom_trun_entry_t
*trun
= (isom_trun_entry_t
*)traf
->trun_list
->tail
->data
;
7497 if( root
->fragment
->pool_size
)
7498 trun
->flags
|= ISOM_TR_FLAGS_DATA_OFFSET_PRESENT
;
7499 trun
->data_offset
= root
->fragment
->pool_size
;
7501 if( isom_append_fragment_track_run( root
, &traf
->cache
->chunk
) )
7503 return isom_set_fragment_last_duration( traf
, last_sample_duration
);
7506 int lsmash_flush_pooled_samples( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t last_sample_delta
)
7510 if( root
->fragment
&& root
->fragment
->movie
)
7511 return isom_flush_fragment_pooled_samples( root
, track_ID
, last_sample_delta
);
7512 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
7513 if( !trak
|| !trak
->cache
|| !trak
->mdia
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
7514 || !trak
->mdia
->minf
->stbl
->stsc
|| !trak
->mdia
->minf
->stbl
->stsc
->list
)
7516 if( isom_output_cache( trak
) )
7518 return lsmash_set_last_sample_delta( root
, track_ID
, last_sample_delta
);
7521 /* This function doesn't update sample_duration of the last sample in the previous movie fragment.
7522 * Instead of this, isom_finish_movie_fragment undertakes this task. */
7523 static int isom_update_fragment_previous_sample_duration( isom_traf_entry_t
*traf
, isom_trex_entry_t
*trex
, uint32_t duration
)
7525 isom_tfhd_t
*tfhd
= traf
->tfhd
;
7526 isom_trun_entry_t
*trun
= (isom_trun_entry_t
*)traf
->trun_list
->tail
->data
;
7527 int previous_run_has_previous_sample
= 0;
7528 if( trun
->sample_count
== 1 )
7530 if( traf
->trun_list
->entry_count
== 1 )
7531 return 0; /* The previous track run belongs to the previous movie fragment if it exists. */
7532 if( !traf
->trun_list
->tail
->prev
|| !traf
->trun_list
->tail
->prev
->data
)
7534 /* OK. The previous sample exists in the previous track run in the same track fragment. */
7535 trun
= (isom_trun_entry_t
*)traf
->trun_list
->tail
->prev
->data
;
7536 previous_run_has_previous_sample
= 1;
7538 /* Update default_sample_duration of the Track Fragment Header Box
7539 * if this duration is what the first sample in the current track fragment owns. */
7540 if( (trun
->sample_count
== 2 && traf
->trun_list
->entry_count
== 1)
7541 || (trun
->sample_count
== 1 && traf
->trun_list
->entry_count
== 2) )
7543 if( duration
!= trex
->default_sample_duration
)
7544 tfhd
->flags
|= ISOM_TF_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT
;
7545 tfhd
->default_sample_duration
= duration
;
7547 /* Update the previous sample_duration if needed. */
7548 if( duration
!= tfhd
->default_sample_duration
)
7549 trun
->flags
|= ISOM_TR_FLAGS_SAMPLE_DURATION_PRESENT
;
7552 uint32_t sample_number
= trun
->sample_count
- !previous_run_has_previous_sample
;
7553 isom_trun_optional_row_t
*row
= isom_request_trun_optional_row( trun
, tfhd
, sample_number
);
7556 row
->sample_duration
= duration
;
7558 traf
->cache
->fragment
->last_duration
= duration
;
7562 static isom_sample_flags_t
isom_generate_fragment_sample_flags( lsmash_sample_t
*sample
)
7564 isom_sample_flags_t flags
;
7566 flags
.is_leading
= sample
->prop
.leading
& 0x3;
7567 flags
.sample_depends_on
= sample
->prop
.independent
& 0x3;
7568 flags
.sample_is_depended_on
= sample
->prop
.disposable
& 0x3;
7569 flags
.sample_has_redundancy
= sample
->prop
.redundant
& 0x3;
7570 flags
.sample_padding_value
= 0;
7571 flags
.sample_is_non_sync_sample
= !(sample
->prop
.ra_flags
& ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC
);
7572 flags
.sample_degradation_priority
= 0;
7576 static int isom_update_fragment_sample_tables( isom_traf_entry_t
*traf
, lsmash_sample_t
*sample
)
7578 isom_tfhd_t
*tfhd
= traf
->tfhd
;
7579 isom_trex_entry_t
*trex
= isom_get_trex( traf
->root
->moov
->mvex
, tfhd
->track_ID
);
7582 lsmash_root_t
*root
= traf
->root
;
7583 isom_cache_t
*cache
= traf
->cache
;
7584 isom_chunk_t
*current
= &cache
->chunk
;
7585 if( !current
->pool
)
7587 /* Very initial settings, just once per track */
7588 current
->pool
= isom_create_sample_pool( 0 );
7589 if( !current
->pool
)
7592 /* Create a new track run if the duration exceeds max_chunk_duration.
7593 * Old one will be appended to the pool of this movie fragment. */
7594 int delimit
= (root
->max_chunk_duration
< ((double)(sample
->dts
- current
->first_dts
) / lsmash_get_media_timescale( root
, tfhd
->track_ID
)))
7595 || (root
->max_chunk_size
< (current
->pool
->size
+ sample
->length
));
7596 isom_trun_entry_t
*trun
= NULL
;
7597 if( !traf
->trun_list
|| !traf
->trun_list
->entry_count
|| delimit
)
7599 if( delimit
&& traf
->trun_list
&& traf
->trun_list
->entry_count
&& traf
->trun_list
->tail
&& traf
->trun_list
->tail
->data
)
7601 /* Media Data Box preceded by Movie Fragment Box could change base data offsets in each track fragments later.
7602 * We can't consider this here because the length of Movie Fragment Box is unknown at this step yet. */
7603 trun
= (isom_trun_entry_t
*)traf
->trun_list
->tail
->data
;
7604 if( root
->fragment
->pool_size
)
7605 trun
->flags
|= ISOM_TR_FLAGS_DATA_OFFSET_PRESENT
;
7606 trun
->data_offset
= root
->fragment
->pool_size
;
7608 trun
= isom_add_trun( traf
);
7614 if( !traf
->trun_list
->tail
|| !traf
->trun_list
->tail
->data
)
7616 trun
= (isom_trun_entry_t
*)traf
->trun_list
->tail
->data
;
7618 isom_sample_flags_t sample_flags
= isom_generate_fragment_sample_flags( sample
);
7619 if( ++trun
->sample_count
== 1 )
7621 if( traf
->trun_list
->entry_count
== 1 )
7623 /* This track fragment isn't empty-duration-fragment any more. */
7624 tfhd
->flags
&= ~ISOM_TF_FLAGS_DURATION_IS_EMPTY
;
7625 /* Set up sample_description_index in this track fragment. */
7626 if( sample
->index
!= trex
->default_sample_description_index
)
7627 tfhd
->flags
|= ISOM_TF_FLAGS_SAMPLE_DESCRIPTION_INDEX_PRESENT
;
7628 tfhd
->sample_description_index
= current
->sample_description_index
= sample
->index
;
7629 /* Set up default_sample_size used in this track fragment. */
7630 tfhd
->default_sample_size
= sample
->length
;
7631 /* Set up default_sample_flags used in this track fragment.
7632 * Note: we decide an appropriate default value at the end of this movie fragment. */
7633 tfhd
->default_sample_flags
= sample_flags
;
7634 /* Set up random access information if this sample is a sync sample.
7635 * We inform only the first sample in each movie fragment. */
7636 if( root
->bs
->stream
!= stdout
&& (sample
->prop
.ra_flags
& ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC
) )
7638 isom_tfra_entry_t
*tfra
= isom_get_tfra( root
->mfra
, tfhd
->track_ID
);
7641 tfra
= isom_add_tfra( root
->mfra
);
7644 tfra
->track_ID
= tfhd
->track_ID
;
7648 tfra
->list
= lsmash_create_entry_list();
7652 isom_tfra_location_time_entry_t
*rap
= malloc( sizeof(isom_tfra_location_time_entry_t
) );
7655 rap
->time
= sample
->cts
; /* Set composition timestamp temporally.
7656 * At the end of the whole movie, this will be reset as presentation time. */
7657 rap
->moof_offset
= root
->size
; /* We place Movie Fragment Box in the head of each movie fragment. */
7658 rap
->traf_number
= cache
->fragment
->traf_number
;
7659 rap
->trun_number
= traf
->trun_list
->entry_count
;
7660 rap
->sample_number
= trun
->sample_count
;
7661 if( lsmash_add_entry( tfra
->list
, rap
) )
7666 tfra
->number_of_entry
= tfra
->list
->entry_count
;
7668 for( length
= 1; rap
->traf_number
>> (length
* 8); length
++ );
7669 tfra
->length_size_of_traf_num
= LSMASH_MAX( length
- 1, tfra
->length_size_of_traf_num
);
7670 for( length
= 1; rap
->traf_number
>> (length
* 8); length
++ );
7671 tfra
->length_size_of_trun_num
= LSMASH_MAX( length
- 1, tfra
->length_size_of_trun_num
);
7672 for( length
= 1; rap
->sample_number
>> (length
* 8); length
++ );
7673 tfra
->length_size_of_sample_num
= LSMASH_MAX( length
- 1, tfra
->length_size_of_sample_num
);
7675 /* Set up the base media decode time of this track fragment.
7676 * This feature is available under ISO Base Media version 6 or later. */
7677 if( root
->max_isom_version
>= 6 )
7679 assert( !traf
->tfdt
);
7680 if( isom_add_tfdt( traf
) )
7682 if( sample
->dts
> UINT32_MAX
)
7683 traf
->tfdt
->version
= 1;
7684 traf
->tfdt
->baseMediaDecodeTime
= sample
->dts
;
7687 trun
->first_sample_flags
= sample_flags
;
7688 current
->first_dts
= sample
->dts
;
7690 /* Update the optional rows in the current track run except for sample_duration if needed. */
7691 if( sample
->length
!= tfhd
->default_sample_size
)
7692 trun
->flags
|= ISOM_TR_FLAGS_SAMPLE_SIZE_PRESENT
;
7693 if( isom_compare_sample_flags( &sample_flags
, &tfhd
->default_sample_flags
) )
7694 trun
->flags
|= ISOM_TR_FLAGS_SAMPLE_FLAGS_PRESENT
;
7695 uint32_t sample_composition_time_offset
= sample
->cts
- sample
->dts
;
7696 if( sample_composition_time_offset
)
7698 trun
->flags
|= ISOM_TR_FLAGS_SAMPLE_COMPOSITION_TIME_OFFSET_PRESENT
;
7699 /* Check if negative composition time offset is present. */
7700 isom_timestamp_t
*ts_cache
= &cache
->timestamp
;
7701 if( (sample
->cts
+ ts_cache
->ctd_shift
) < sample
->dts
)
7703 if( root
->max_isom_version
< 6 )
7704 return -1; /* Negative composition time offset is not supported. */
7705 if( (sample
->dts
- sample
->cts
) > INT32_MAX
)
7706 return -1; /* Overflow */
7707 ts_cache
->ctd_shift
= sample
->dts
- sample
->cts
;
7708 if( trun
->version
== 0 && root
->max_isom_version
>= 6 )
7714 isom_trun_optional_row_t
*row
= isom_request_trun_optional_row( trun
, tfhd
, trun
->sample_count
);
7717 row
->sample_size
= sample
->length
;
7718 row
->sample_flags
= sample_flags
;
7719 row
->sample_composition_time_offset
= sample_composition_time_offset
;
7721 /* Set up the previous sample_duration if this sample is not the first sample in the overall movie. */
7722 if( cache
->fragment
->has_samples
)
7724 /* Note: when using for live streaming, it is not good idea to return error (-1) by sample->dts < prev_dts
7725 * since that's trivial for such semi-permanent presentation. */
7726 uint64_t prev_dts
= cache
->timestamp
.dts
;
7727 if( sample
->dts
<= prev_dts
|| sample
->dts
> prev_dts
+ UINT32_MAX
)
7729 uint32_t sample_duration
= sample
->dts
- prev_dts
;
7730 if( isom_update_fragment_previous_sample_duration( traf
, trex
, sample_duration
) )
7733 cache
->timestamp
.dts
= sample
->dts
;
7734 cache
->fragment
->largest_cts
= LSMASH_MAX( sample
->cts
, cache
->fragment
->largest_cts
);
7738 static int isom_append_fragment_sample_internal_initial( isom_trak_entry_t
*trak
, lsmash_sample_t
*sample
)
7741 /* Update the sample tables of this track fragment.
7742 * If a new chunk was created, append the previous one to the pool of this movie fragment. */
7743 delimit
= isom_update_sample_tables( trak
, sample
);
7746 else if( delimit
== 1 )
7747 isom_append_fragment_track_run( trak
->root
, &trak
->cache
->chunk
);
7748 /* Add a new sample into the pool of this track fragment. */
7749 if( isom_pool_sample( trak
->cache
->chunk
.pool
, sample
) )
7751 trak
->cache
->fragment
->has_samples
= 1;
7755 static int isom_append_fragment_sample_internal( isom_traf_entry_t
*traf
, lsmash_sample_t
*sample
)
7758 /* Update the sample tables of this track fragment.
7759 * If a new track run was created, append the previous one to the pool of this movie fragment. */
7760 delimit
= isom_update_fragment_sample_tables( traf
, sample
);
7763 else if( delimit
== 1 )
7764 isom_append_fragment_track_run( traf
->root
, &traf
->cache
->chunk
);
7765 /* Add a new sample into the pool of this track fragment. */
7766 if( isom_pool_sample( traf
->cache
->chunk
.pool
, sample
) )
7768 traf
->cache
->fragment
->has_samples
= 1;
7772 static int isom_append_fragment_sample( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_sample_t
*sample
)
7774 isom_fragment_manager_t
*fragment
= root
->fragment
;
7775 if( !fragment
|| !fragment
->pool
)
7777 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
7778 if( !trak
|| !trak
->root
|| !trak
->cache
|| !trak
->cache
->fragment
|| !trak
->tkhd
|| !trak
->mdia
7779 || !trak
->mdia
->mdhd
|| !trak
->mdia
->mdhd
->timescale
7780 || !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
7781 || !trak
->mdia
->minf
->stbl
->stsd
|| !trak
->mdia
->minf
->stbl
->stsd
->list
7782 || !trak
->mdia
->minf
->stbl
->stsc
|| !trak
->mdia
->minf
->stbl
->stsc
->list
)
7784 int (*append_sample_func
)( void *, lsmash_sample_t
* ) = NULL
;
7785 void *track_fragment
= NULL
;
7786 if( !fragment
->movie
)
7788 append_sample_func
= (int (*)( void *, lsmash_sample_t
* ))isom_append_fragment_sample_internal_initial
;
7789 track_fragment
= trak
;
7793 isom_traf_entry_t
*traf
= isom_get_traf( fragment
->movie
, track_ID
);
7796 traf
= isom_add_traf( root
, fragment
->movie
);
7797 if( isom_add_tfhd( traf
) )
7799 traf
->tfhd
->flags
= ISOM_TF_FLAGS_DURATION_IS_EMPTY
; /* no samples for this track fragment yet */
7800 traf
->tfhd
->track_ID
= trak
->tkhd
->track_ID
;
7801 traf
->cache
= trak
->cache
;
7802 traf
->cache
->fragment
->traf_number
= fragment
->movie
->traf_list
->entry_count
;
7804 else if( !traf
->root
|| !traf
->root
->moov
|| !traf
->root
->moov
->mvex
|| !traf
->cache
|| !traf
->tfhd
)
7806 append_sample_func
= (int (*)( void *, lsmash_sample_t
* ))isom_append_fragment_sample_internal
;
7807 track_fragment
= traf
;
7809 isom_sample_entry_t
*sample_entry
= (isom_sample_entry_t
*)lsmash_get_entry_data( trak
->mdia
->minf
->stbl
->stsd
->list
, sample
->index
);
7812 if( isom_is_lpcm_audio( sample_entry
) )
7814 uint32_t frame_size
= ((isom_audio_entry_t
*)sample_entry
)->constBytesPerAudioPacket
;
7815 if( sample
->length
== frame_size
)
7816 return append_sample_func( track_fragment
, sample
);
7817 else if( sample
->length
< frame_size
)
7819 /* Append samples splitted into each LPCMFrame. */
7820 uint64_t dts
= sample
->dts
;
7821 uint64_t cts
= sample
->cts
;
7822 for( uint32_t offset
= 0; offset
< sample
->length
; offset
+= frame_size
)
7824 lsmash_sample_t
*lpcm_sample
= lsmash_create_sample( frame_size
);
7827 memcpy( lpcm_sample
->data
, sample
->data
+ offset
, frame_size
);
7828 lpcm_sample
->dts
= dts
++;
7829 lpcm_sample
->cts
= cts
++;
7830 lpcm_sample
->prop
= sample
->prop
;
7831 lpcm_sample
->index
= sample
->index
;
7832 if( append_sample_func( track_fragment
, lpcm_sample
) )
7834 lsmash_delete_sample( lpcm_sample
);
7838 lsmash_delete_sample( sample
);
7841 return append_sample_func( track_fragment
, sample
);
7844 int lsmash_append_sample( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_sample_t
*sample
)
7846 /* We think max_chunk_duration == 0, which means all samples will be cached on memory, should be prevented.
7847 * This means removal of a feature that we used to have, but anyway very alone chunk does not make sense. */
7848 if( !root
|| !root
->bs
|| !sample
|| !sample
->data
|| !track_ID
7849 || root
->max_chunk_duration
== 0 || root
->max_async_tolerance
== 0 )
7851 /* Write File Type Box here if it was not written yet. */
7852 if( !root
->file_type_written
&& isom_write_ftyp( root
) )
7854 if( root
->fragment
&& root
->fragment
->pool
)
7855 return isom_append_fragment_sample( root
, track_ID
, sample
);
7856 return isom_append_sample( root
, track_ID
, sample
);
7859 /*---- misc functions ----*/
7861 int lsmash_delete_explicit_timeline_map( lsmash_root_t
*root
, uint32_t track_ID
)
7863 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
7866 isom_remove_edts( trak
->edts
);
7868 return isom_update_tkhd_duration( trak
);
7871 void lsmash_delete_tyrant_chapter( lsmash_root_t
*root
)
7873 if( !root
|| !root
->moov
|| !root
->moov
->udta
)
7875 isom_remove_chpl( root
->moov
->udta
->chpl
);
7876 root
->moov
->udta
->chpl
= NULL
;
7879 int lsmash_set_copyright( lsmash_root_t
*root
, uint32_t track_ID
, uint16_t ISO_language
, char *notice
)
7881 if( !root
|| !root
->moov
|| !root
->isom_compatible
|| (ISO_language
&& ISO_language
< 0x800) || !notice
)
7886 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
7887 if( !trak
|| (!trak
->udta
&& isom_add_udta( root
, track_ID
)) )
7893 if( !root
->moov
->udta
&& isom_add_udta( root
, 0 ) )
7895 udta
= root
->moov
->udta
;
7898 if( udta
->cprt_list
)
7899 for( lsmash_entry_t
*entry
= udta
->cprt_list
->head
; entry
; entry
= entry
->next
)
7901 isom_cprt_t
*cprt
= (isom_cprt_t
*)entry
->data
;
7902 if( !cprt
|| cprt
->language
== ISO_language
)
7905 if( isom_add_cprt( udta
) )
7907 isom_cprt_t
*cprt
= (isom_cprt_t
*)udta
->cprt_list
->tail
->data
;
7908 cprt
->language
= ISO_language
;
7909 cprt
->notice_length
= strlen( notice
) + 1;
7910 cprt
->notice
= lsmash_memdup( notice
, cprt
->notice_length
);