1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2011 L-SMASH project
6 * Authors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 *****************************************************************************/
21 /* This file is available under an ISC license. */
23 #ifdef LSMASH_DEMUXER_ENABLED
25 #include "internal.h" /* must be placed first */
42 } isom_portable_chunk_t
;
51 isom_portable_chunk_t
*chunk
;
52 lsmash_sample_property_t prop
;
58 uint32_t movie_timescale
;
59 uint32_t media_timescale
;
60 int32_t ctd_shift
; /* shift from composition to decode timeline */
61 uint32_t last_accessed_sample_number
;
62 uint32_t last_accessed_chunk_number
;
63 uint64_t last_accessed_sample_dts
;
64 uint64_t last_accessed_offset
;
65 uint64_t last_read_size
;
66 void *last_accessed_chunk_data
;
67 lsmash_entry_list_t edit_list
[1]; /* list of edits */
68 lsmash_entry_list_t description_list
[1]; /* list of descriptions */
69 lsmash_entry_list_t chunk_list
[1]; /* list of chunks */
70 lsmash_entry_list_t info_list
[1]; /* list of sample info */
73 static isom_timeline_t
*isom_get_timeline( lsmash_root_t
*root
, uint32_t track_ID
)
75 if( !track_ID
|| !root
|| !root
->timeline
)
77 for( lsmash_entry_t
*entry
= root
->timeline
->head
; entry
; entry
= entry
->next
)
79 isom_timeline_t
*timeline
= (isom_timeline_t
*)entry
->data
;
82 if( timeline
->track_ID
== track_ID
)
88 static isom_timeline_t
*isom_create_timeline( void )
90 isom_timeline_t
*timeline
= malloc( sizeof(isom_timeline_t
) );
93 timeline
->track_ID
= 0;
94 timeline
->ctd_shift
= 0;
95 timeline
->last_accessed_sample_number
= 0;
96 timeline
->last_accessed_chunk_number
= 0;
97 timeline
->last_accessed_sample_dts
= 0;
98 timeline
->last_accessed_offset
= 0;
99 timeline
->last_read_size
= 0;
100 timeline
->last_accessed_chunk_data
= NULL
;
101 lsmash_init_entry_list( timeline
->edit_list
);
102 lsmash_init_entry_list( timeline
->description_list
);
103 lsmash_init_entry_list( timeline
->chunk_list
);
104 lsmash_init_entry_list( timeline
->info_list
);
108 static void isom_destruct_timeline_direct( isom_timeline_t
*timeline
)
112 if( timeline
->last_accessed_chunk_data
)
113 free( timeline
->last_accessed_chunk_data
);
114 lsmash_remove_entries( timeline
->edit_list
, NULL
);
115 lsmash_remove_entries( timeline
->description_list
, isom_remove_sample_description
);
116 lsmash_remove_entries( timeline
->chunk_list
, NULL
); /* chunk data must be already freed. */
117 lsmash_remove_entries( timeline
->info_list
, NULL
);
121 void isom_remove_timelines( lsmash_root_t
*root
)
123 if( !root
|| !root
->timeline
)
125 lsmash_remove_list( root
->timeline
, isom_destruct_timeline_direct
);
128 void lsmash_destruct_timeline( lsmash_root_t
*root
, uint32_t track_ID
)
130 if( !track_ID
|| !root
|| !root
->timeline
)
132 for( lsmash_entry_t
*entry
= root
->timeline
->head
; entry
; entry
= entry
->next
)
134 isom_timeline_t
*timeline
= (isom_timeline_t
*)entry
->data
;
137 if( timeline
->track_ID
== track_ID
)
138 lsmash_remove_entry_direct( root
->timeline
, entry
, isom_destruct_timeline_direct
);
143 static lsmash_video_summary_t
*isom_create_video_summary_from_description( isom_visual_entry_t
*visual
)
145 isom_visual_entry_t
*visual
;
146 lsmash_video_summary_t
*summary
= malloc( sizeof(lsmash_video_summary_t
) );
149 memset( summary
, 0, sizeof(lsmash_video_summary_t
) );
150 summary
->width
= visual
->width
;
151 summary
->height
= visual
->height
;
154 double cleanApertureWidth
= (double)clap
->cleanApertureWidthN
/ cleanApertureWidthD
;
155 double cleanApertureHeight
= (double)clap
->cleanApertureHeightN
/ cleanApertureHeightD
;
156 double horizOff
= (double)clap
->horizOffN
/ clap
->horizOffD
;
157 double vertOff
= (double)clap
->vertOffN
/ clap
->vertOffD
;
158 summary
->crop_top
= (summary
->height
- cleanApertureHeight
+ vertOff
) / 2;
159 summary
->crop_left
= (summary
->width
- cleanApertureWidth
+ horizOff
) / 2;
160 summary
->crop_bottom
= (summary
->height
- cleanApertureHeight
- vertOff
) / 2;
161 summary
->crop_right
= (summary
->width
- cleanApertureWidth
- horizOff
) / 2;
165 summary
->par_h
= visual
->pasp
->hSpacing
;
166 summary
->par_v
= visual
->pasp
->vSpacing
;
169 summary
->scaling_method
= visual
->stsl
->scale_method
;
172 summary
->primaries
= visual
->colr
->primaries_index
;
173 summary
->transfer
= visual
->colr
->transfer_function_index
;
174 summary
->matrix
= visual
->colr
->matrix_index
;
180 static isom_esds_t
*isom_duplicate_esds( isom_box_t
*dst_parent
, isom_esds_t
*src
)
182 if( !src
|| !src
->ES
)
184 isom_esds_t
*dst
= malloc( sizeof(isom_esds_t
) );
187 isom_init_box_common( dst
, dst_parent
, ISOM_BOX_TYPE_ESDS
);
188 dst
->ES
= mp4sys_duplicate_ES_Descriptor( src
->ES
);
197 static int isom_copy_clap( isom_visual_entry_t
*dst
, isom_visual_entry_t
*src
)
201 if( !src
|| !src
->clap
)
203 isom_remove_clap( dst
->clap
);
206 if( !dst
->clap
&& isom_add_clap( dst
) )
208 isom_copy_fields( dst
, src
, clap
);
212 static int isom_copy_pasp( isom_visual_entry_t
*dst
, isom_visual_entry_t
*src
)
216 if( !src
|| !src
->pasp
)
218 isom_remove_pasp( dst
->pasp
);
221 if( !dst
->pasp
&& isom_add_pasp( dst
) )
223 isom_copy_fields( dst
, src
, pasp
);
227 static int isom_copy_colr( isom_visual_entry_t
*dst
, isom_visual_entry_t
*src
)
231 if( !src
|| !src
->colr
)
233 isom_remove_colr( dst
->colr
);
236 if( !dst
->colr
&& isom_add_colr( dst
) )
238 isom_copy_fields( dst
, src
, colr
);
242 static int isom_copy_stsl( isom_visual_entry_t
*dst
, isom_visual_entry_t
*src
)
246 if( !src
|| !src
->stsl
)
248 isom_remove_stsl( dst
->stsl
);
251 if( !dst
->stsl
&& isom_add_stsl( dst
) )
253 isom_copy_fields( dst
, src
, stsl
);
257 static int isom_copy_ps_entries( lsmash_entry_list_t
*dst
, lsmash_entry_list_t
*src
)
261 for( lsmash_entry_t
*entry
= src
->head
; entry
; entry
= entry
->next
)
263 isom_avcC_ps_entry_t
*src_ps
= (isom_avcC_ps_entry_t
*)entry
->data
;
266 isom_avcC_ps_entry_t
*dst_ps
= isom_create_ps_entry( src_ps
->parameterSetNALUnit
, src_ps
->parameterSetLength
);
269 if( lsmash_add_entry( dst
, dst_ps
) )
271 isom_remove_avcC_ps( dst_ps
);
278 static int isom_copy_avcC( isom_visual_entry_t
*dst
, isom_visual_entry_t
*src
)
282 isom_remove_avcC( dst
->avcC
);
283 if( !src
|| !src
->avcC
)
285 if( isom_add_avcC( dst
) )
287 isom_avcC_t temp
= *dst
->avcC
; /* Hold created lists. */
288 isom_copy_fields( dst
, src
, avcC
);
289 dst
->avcC
->sequenceParameterSets
= temp
.sequenceParameterSets
;
290 dst
->avcC
->pictureParameterSets
= temp
.pictureParameterSets
;
291 dst
->avcC
->sequenceParameterSetExt
= temp
.sequenceParameterSetExt
;
292 if( isom_copy_ps_entries( dst
->avcC
->sequenceParameterSets
, src
->avcC
->sequenceParameterSets
)
293 || isom_copy_ps_entries( dst
->avcC
->pictureParameterSets
, src
->avcC
->pictureParameterSets
)
294 || isom_copy_ps_entries( dst
->avcC
->sequenceParameterSetExt
, src
->avcC
->sequenceParameterSetExt
) )
299 static int isom_copy_btrt( isom_visual_entry_t
*dst
, isom_visual_entry_t
*src
)
303 if( !src
|| !src
->btrt
)
305 isom_remove_btrt( dst
->btrt
);
308 if( !dst
->btrt
&& isom_add_btrt( dst
) )
310 isom_copy_fields( dst
, src
, btrt
);
314 static isom_visual_entry_t
*isom_duplicate_visual_description( isom_visual_entry_t
*src
)
316 isom_visual_entry_t
*dst
= lsmash_memdup( src
, sizeof(isom_visual_entry_t
) );
327 dst
->esds
= isom_duplicate_esds( (isom_box_t
*)dst
, src
->esds
);
328 if( (src
->esds
&& !dst
->esds
) /* Check if copying failed. */
329 || isom_copy_clap( dst
, src
)
330 || isom_copy_pasp( dst
, src
)
331 || isom_copy_colr( dst
, src
)
332 || isom_copy_stsl( dst
, src
)
333 || isom_copy_avcC( dst
, src
)
334 || isom_copy_btrt( dst
, src
) )
336 isom_remove_sample_description( (isom_sample_entry_t
*)dst
);
342 static int isom_copy_frma( isom_wave_t
*dst
, isom_wave_t
*src
)
346 if( !src
|| !src
->frma
)
348 isom_remove_frma( dst
->frma
);
351 if( !dst
->frma
&& isom_add_frma( dst
) )
353 isom_copy_fields( dst
, src
, frma
);
357 static int isom_copy_enda( isom_wave_t
*dst
, isom_wave_t
*src
)
361 if( !src
|| !src
->enda
)
363 isom_remove_enda( dst
->enda
);
366 if( !dst
->enda
&& isom_add_enda( dst
) )
368 isom_copy_fields( dst
, src
, enda
);
372 static int isom_copy_mp4a( isom_wave_t
*dst
, isom_wave_t
*src
)
376 if( !src
|| !src
->mp4a
)
378 isom_remove_mp4a( dst
->mp4a
);
381 if( !dst
->mp4a
&& isom_add_mp4a( dst
) )
383 isom_copy_fields( dst
, src
, mp4a
);
387 static int isom_copy_terminator( isom_wave_t
*dst
, isom_wave_t
*src
)
391 if( !src
|| !src
->terminator
)
393 isom_remove_terminator( dst
->terminator
);
396 if( dst
->terminator
)
398 return isom_add_terminator( dst
);
401 static int isom_copy_wave( isom_audio_entry_t
*dst
, isom_audio_entry_t
*src
)
405 isom_remove_wave( dst
->wave
);
406 if( !src
|| !src
->wave
)
408 if( isom_add_wave( dst
) )
410 if( src
->wave
->exdata
&& src
->wave
->exdata_length
)
412 dst
->wave
->exdata
= lsmash_memdup( src
->wave
->exdata
, src
->wave
->exdata_length
);
413 if( !dst
->wave
->exdata
)
415 dst
->wave
->exdata_length
= src
->wave
->exdata_length
;
418 dst
->wave
->esds
= isom_duplicate_esds( (isom_box_t
*)dst
->wave
, src
->wave
->esds
);
419 if( (src
->wave
->esds
&& !dst
->wave
->esds
) /* Check if copying failed. */
420 || isom_copy_frma( dst
->wave
, src
->wave
)
421 || isom_copy_enda( dst
->wave
, src
->wave
)
422 || isom_copy_mp4a( dst
->wave
, src
->wave
)
423 || isom_copy_terminator( dst
->wave
, src
->wave
) )
428 static int isom_copy_chan( isom_audio_entry_t
*dst
, isom_audio_entry_t
*src
)
432 isom_remove_chan( dst
->chan
);
433 if( !src
|| !src
->chan
)
435 if( isom_add_chan( dst
) )
437 dst
->chan
->channelLayoutTag
= src
->chan
->channelLayoutTag
;
438 dst
->chan
->channelBitmap
= src
->chan
->channelBitmap
;
439 dst
->chan
->numberChannelDescriptions
= src
->chan
->numberChannelDescriptions
;
440 if( src
->chan
->numberChannelDescriptions
&& src
->chan
->channelDescriptions
)
442 uint32_t numberChannelDescriptions
= src
->chan
->numberChannelDescriptions
;
443 dst
->chan
->channelDescriptions
= malloc( numberChannelDescriptions
* sizeof(isom_channel_description_t
) );
444 if( !dst
->chan
->channelDescriptions
)
446 for( uint32_t i
= 0; i
< numberChannelDescriptions
; i
++ )
448 dst
->chan
->channelDescriptions
[i
].channelLabel
= src
->chan
->channelDescriptions
[i
].channelLabel
;
449 dst
->chan
->channelDescriptions
[i
].channelFlags
= src
->chan
->channelDescriptions
[i
].channelFlags
;
450 dst
->chan
->channelDescriptions
[i
].coordinates
[0] = src
->chan
->channelDescriptions
[i
].coordinates
[0];
451 dst
->chan
->channelDescriptions
[i
].coordinates
[1] = src
->chan
->channelDescriptions
[i
].coordinates
[1];
452 dst
->chan
->channelDescriptions
[i
].coordinates
[2] = src
->chan
->channelDescriptions
[i
].coordinates
[2];
454 dst
->chan
->numberChannelDescriptions
= src
->chan
->numberChannelDescriptions
;
458 if( dst
->chan
->channelDescriptions
)
459 free( dst
->chan
->channelDescriptions
);
460 dst
->chan
->channelDescriptions
= NULL
;
461 dst
->chan
->numberChannelDescriptions
= 0;
466 static isom_audio_entry_t
*isom_duplicate_audio_description( isom_audio_entry_t
*src
)
468 isom_audio_entry_t
*dst
= lsmash_memdup( src
, sizeof(isom_audio_entry_t
) );
474 if( isom_is_lpcm_audio( src
->type
) )
477 dst
->constBytesPerAudioPacket
= (src
->samplesize
* src
->channelcount
) / 8;
478 else if( src
->version
== 1 )
479 dst
->constBytesPerAudioPacket
= src
->bytesPerFrame
;
481 if( src
->exdata
&& src
->exdata_length
)
483 dst
->exdata
= lsmash_memdup( src
->exdata
, src
->exdata_length
);
486 isom_remove_sample_description( (isom_sample_entry_t
*)dst
);
489 dst
->exdata_length
= src
->exdata_length
;
492 dst
->esds
= isom_duplicate_esds( (isom_box_t
*)dst
, src
->esds
);
493 if( (src
->esds
&& !dst
->esds
) /* Check if copying failed. */
494 || isom_copy_wave( dst
, src
)
495 || isom_copy_chan( dst
, src
) )
497 isom_remove_sample_description( (isom_sample_entry_t
*)dst
);
503 static int isom_copy_ftab( isom_tx3g_entry_t
*dst
, isom_tx3g_entry_t
*src
)
507 isom_remove_ftab( dst
->ftab
);
508 if( !src
|| !src
->ftab
)
510 if( isom_add_ftab( dst
) )
512 if( src
->ftab
->list
)
514 dst
->ftab
->list
= lsmash_create_entry_list();
515 if( !dst
->ftab
->list
)
517 for( lsmash_entry_t
*entry
= src
->ftab
->list
->head
; entry
; entry
= entry
->next
)
519 isom_font_record_t
*src_record
= (isom_font_record_t
*)entry
->data
;
522 isom_font_record_t
*dst_record
= lsmash_memdup( src_record
, sizeof(isom_font_record_t
) );
523 dst_record
->font_name
= lsmash_memdup( src_record
->font_name
, src_record
->font_name_length
);
524 if( lsmash_add_entry( dst
->ftab
->list
, dst_record
) )
526 free( dst_record
->font_name
);
535 static isom_tx3g_entry_t
*isom_duplicate_tx3g_description( isom_tx3g_entry_t
*src
)
537 isom_tx3g_entry_t
*dst
= lsmash_memdup( src
, sizeof(isom_tx3g_entry_t
) );
541 if( isom_copy_ftab( dst
, src
) )
543 isom_remove_sample_description( (isom_sample_entry_t
*)dst
);
549 static isom_text_entry_t
*isom_duplicate_text_description( isom_text_entry_t
*src
)
551 isom_text_entry_t
*dst
= lsmash_memdup( src
, sizeof(isom_text_entry_t
) );
554 dst
->font_name
= NULL
;
555 dst
->font_name_length
= 0;
556 if( src
->font_name
&& src
->font_name_length
)
558 dst
->font_name
= lsmash_memdup( src
->font_name
, src
->font_name_length
);
559 if( !dst
->font_name
)
561 isom_remove_sample_description( (isom_sample_entry_t
*)dst
);
564 dst
->font_name_length
= src
->font_name_length
;
569 static isom_sample_entry_t
*isom_duplicate_description( isom_sample_entry_t
*entry
, isom_stsd_t
*dst_parent
)
573 void *description
= NULL
;
574 switch( entry
->type
)
576 case ISOM_CODEC_TYPE_AVC1_VIDEO
:
577 case ISOM_CODEC_TYPE_MP4V_VIDEO
:
578 description
= isom_duplicate_visual_description( (isom_visual_entry_t
*)entry
);
580 case ISOM_CODEC_TYPE_MP4A_AUDIO
:
581 case ISOM_CODEC_TYPE_AC_3_AUDIO
:
582 case ISOM_CODEC_TYPE_ALAC_AUDIO
:
583 case ISOM_CODEC_TYPE_EC_3_AUDIO
:
584 case ISOM_CODEC_TYPE_SAMR_AUDIO
:
585 case ISOM_CODEC_TYPE_SAWB_AUDIO
:
586 case QT_CODEC_TYPE_23NI_AUDIO
:
587 case QT_CODEC_TYPE_NONE_AUDIO
:
588 case QT_CODEC_TYPE_LPCM_AUDIO
:
589 case QT_CODEC_TYPE_RAW_AUDIO
:
590 case QT_CODEC_TYPE_SOWT_AUDIO
:
591 case QT_CODEC_TYPE_TWOS_AUDIO
:
592 case QT_CODEC_TYPE_FL32_AUDIO
:
593 case QT_CODEC_TYPE_FL64_AUDIO
:
594 case QT_CODEC_TYPE_IN24_AUDIO
:
595 case QT_CODEC_TYPE_IN32_AUDIO
:
596 case QT_CODEC_TYPE_NOT_SPECIFIED
:
597 description
= isom_duplicate_audio_description( (isom_audio_entry_t
*)entry
);
599 case ISOM_CODEC_TYPE_TX3G_TEXT
:
600 description
= isom_duplicate_tx3g_description( (isom_tx3g_entry_t
*)entry
);
602 case QT_CODEC_TYPE_TEXT_TEXT
:
603 description
= isom_duplicate_text_description( (isom_text_entry_t
*)entry
);
609 ((isom_sample_entry_t
*)description
)->parent
= (isom_box_t
*)dst_parent
;
610 return (isom_sample_entry_t
*)description
;
613 #define INCREMENT_SAMPLE_NUMBER_IN_ENTRY( sample_number_in_entry, entry, entry_data ) \
614 if( sample_number_in_entry == entry_data->sample_count ) \
616 sample_number_in_entry = 1; \
617 entry = entry->next; \
620 ++sample_number_in_entry
622 int lsmash_construct_timeline( lsmash_root_t
*root
, uint32_t track_ID
)
624 if( !root
|| !root
->moov
|| !root
->moov
->mvhd
|| !root
->moov
->mvhd
->timescale
)
626 /* Get track by track_ID. */
627 isom_trak_entry_t
*trak
= isom_get_trak( root
, track_ID
);
628 if( !trak
|| !trak
->mdia
|| !trak
->mdia
->mdhd
|| !trak
->mdia
->mdhd
->timescale
|| !trak
->mdia
->minf
|| !trak
->mdia
->minf
->stbl
)
630 /* Create a timeline list if it doesn't exist. */
631 if( !root
->timeline
)
633 root
->timeline
= lsmash_create_entry_list();
634 if( !root
->timeline
)
637 /* Create a timeline. */
638 isom_timeline_t
*timeline
= isom_create_timeline();
641 timeline
->track_ID
= track_ID
;
642 timeline
->movie_timescale
= root
->moov
->mvhd
->timescale
;
643 timeline
->media_timescale
= trak
->mdia
->mdhd
->timescale
;
644 /* Preparation for construction. */
645 isom_elst_t
*elst
= trak
->edts
? trak
->edts
->elst
: NULL
;
646 isom_stbl_t
*stbl
= trak
->mdia
->minf
->stbl
;
647 isom_stsd_t
*stsd
= stbl
->stsd
;
648 isom_stts_t
*stts
= stbl
->stts
;
649 isom_ctts_t
*ctts
= stbl
->ctts
;
650 isom_stss_t
*stss
= stbl
->stss
;
651 isom_stps_t
*stps
= stbl
->stps
;
652 isom_sdtp_t
*sdtp
= stbl
->sdtp
;
653 isom_stsc_t
*stsc
= stbl
->stsc
;
654 isom_stsz_t
*stsz
= stbl
->stsz
;
655 isom_stco_t
*stco
= stbl
->stco
;
656 isom_sgpd_entry_t
*sgpd_roll
= isom_get_sample_group_description( stbl
, ISOM_GROUP_TYPE_ROLL
);
657 isom_sgpd_entry_t
*sgpd_rap
= isom_get_sample_group_description( stbl
, ISOM_GROUP_TYPE_RAP
);
658 isom_sbgp_entry_t
*sbgp_roll
= isom_get_sample_to_group( stbl
, ISOM_GROUP_TYPE_ROLL
);
659 isom_sbgp_entry_t
*sbgp_rap
= isom_get_sample_to_group( stbl
, ISOM_GROUP_TYPE_RAP
);
660 lsmash_entry_t
*elst_entry
= elst
&& elst
->list
? elst
->list
->head
: NULL
;
661 lsmash_entry_t
*stsd_entry
= stsd
&& stsd
->list
? stsd
->list
->head
: NULL
;
662 lsmash_entry_t
*stts_entry
= stts
&& stts
->list
? stts
->list
->head
: NULL
;
663 lsmash_entry_t
*ctts_entry
= ctts
&& ctts
->list
? ctts
->list
->head
: NULL
;
664 lsmash_entry_t
*stss_entry
= stss
&& stss
->list
? stss
->list
->head
: NULL
;
665 lsmash_entry_t
*stps_entry
= stps
&& stps
->list
? stps
->list
->head
: NULL
;
666 lsmash_entry_t
*sdtp_entry
= sdtp
&& sdtp
->list
? sdtp
->list
->head
: NULL
;
667 lsmash_entry_t
*stsz_entry
= stsz
&& stsz
->list
? stsz
->list
->head
: NULL
;
668 lsmash_entry_t
*stsc_entry
= stsc
&& stsc
->list
? stsc
->list
->head
: NULL
;
669 lsmash_entry_t
*stco_entry
= stco
&& stco
->list
? stco
->list
->head
: NULL
;
670 lsmash_entry_t
*sbgp_roll_entry
= sbgp_roll
&& sbgp_roll
->list
? sbgp_roll
->list
->head
: NULL
;
671 lsmash_entry_t
*sbgp_rap_entry
= sbgp_rap
&& sbgp_rap
->list
? sbgp_rap
->list
->head
: NULL
;
672 lsmash_entry_t
*next_stsc_entry
= stsc_entry
? stsc_entry
->next
: NULL
;
673 isom_stsc_entry_t
*stsc_data
= stsc_entry
? (isom_stsc_entry_t
*)stsc_entry
->data
: NULL
;
674 isom_sample_entry_t
*description
= stsd_entry
? (isom_sample_entry_t
*)stsd_entry
->data
: NULL
;
675 isom_sample_info_t
*info
= NULL
; /* shut up 'uninitialized' warning */
676 isom_portable_chunk_t
*chunk
= NULL
; /* shut up 'uninitialized' warning */
677 if( !description
|| !stts_entry
|| !stsc_entry
|| !stco_entry
|| !stco_entry
->data
)
679 chunk
= malloc( sizeof(isom_portable_chunk_t
) );
680 if( !chunk
|| lsmash_add_entry( timeline
->chunk_list
, chunk
) )
684 int all_sync
= !stss
;
685 int large_presentation
= stco
->large_presentation
;
686 int is_lpcm_audio
= isom_is_lpcm_audio( description
->type
);
687 int iso_sdtp
= root
->max_isom_version
>= 4;
688 int allow_negative_sample_offset
= ctts
&& ((root
->max_isom_version
>= 4 && ctts
->version
== 1) || root
->qt_compatible
);
689 uint32_t sample_number
= 1;
690 uint32_t sample_number_in_stts_entry
= 1;
691 uint32_t sample_number_in_ctts_entry
= 1;
692 uint32_t sample_number_in_sbgp_roll_entry
= 1;
693 uint32_t sample_number_in_sbgp_rap_entry
= 1;
694 uint32_t sample_number_in_chunk
= 1;
697 uint32_t chunk_number
= 1;
698 uint64_t offset_from_chunk
= 0;
699 uint64_t data_offset
= chunk
->data_offset
701 ? ((isom_co64_entry_t
*)stco_entry
->data
)->chunk_offset
702 : ((isom_stco_entry_t
*)stco_entry
->data
)->chunk_offset
;
703 uint32_t constant_sample_size
= is_lpcm_audio
704 ? ((isom_audio_entry_t
*)description
)->constBytesPerAudioPacket
709 isom_elst_entry_t
*edit
= (isom_elst_entry_t
*)lsmash_memdup( elst_entry
->data
, sizeof(isom_elst_entry_t
) );
711 || lsmash_add_entry( timeline
->edit_list
, edit
) )
713 elst_entry
= elst_entry
->next
;
715 /* Copy sample descriptions. */
718 description
= isom_duplicate_description( (isom_sample_entry_t
*)stsd_entry
->data
, NULL
);
720 || lsmash_add_entry( timeline
->description_list
, description
) )
722 stsd_entry
= stsd_entry
->next
;
724 stsd_entry
= stsd
->list
->head
;
725 description
= (isom_sample_entry_t
*)stsd_entry
->data
;
726 /* Check what the first 2-bits of sample dependency means.
727 * This check is for chimera of ISO Base Media and QTFF. */
728 if( iso_sdtp
&& sdtp_entry
)
732 isom_sdtp_entry_t
*sdtp_data
= (isom_sdtp_entry_t
*)sdtp_entry
->data
;
735 if( sdtp_data
->is_leading
> 1 )
736 break; /* Apparently, it's defined under ISO Base Media. */
737 if( (sdtp_data
->is_leading
== 1) && (sdtp_data
->sample_depends_on
== ISOM_SAMPLE_IS_INDEPENDENT
) )
739 /* Obviously, it's not defined under ISO Base Media. */
743 sdtp_entry
= sdtp_entry
->next
;
745 sdtp_entry
= sdtp
->list
->head
;
747 /* Construct media timeline. */
748 while( sample_number
<= stsz
->sample_count
)
750 info
= malloc( sizeof(isom_sample_info_t
) );
753 memset( info
, 0, sizeof(isom_sample_info_t
) );
754 /* Get sample duration and sample offset. */
755 isom_stts_entry_t
*stts_data
= (isom_stts_entry_t
*)stts_entry
->data
;
758 INCREMENT_SAMPLE_NUMBER_IN_ENTRY( sample_number_in_stts_entry
, stts_entry
, stts_data
);
759 info
->duration
= stts_data
->sample_delta
;
762 isom_ctts_entry_t
*ctts_data
= (isom_ctts_entry_t
*)ctts_entry
->data
;
765 INCREMENT_SAMPLE_NUMBER_IN_ENTRY( sample_number_in_ctts_entry
, ctts_entry
, ctts_data
);
766 info
->offset
= ctts_data
->sample_offset
;
770 if( allow_negative_sample_offset
)
772 cts
= dts
+ (int32_t)info
->offset
;
773 if( (cts
+ timeline
->ctd_shift
) < dts
)
774 timeline
->ctd_shift
= dts
- cts
;
777 cts
= dts
+ info
->offset
;
778 dts
+= info
->duration
;
781 /* Check whether sync sample or not. */
784 isom_stss_entry_t
*stss_data
= (isom_stss_entry_t
*)stss_entry
->data
;
787 if( sample_number
== stss_data
->sample_number
)
789 info
->prop
.random_access_type
= ISOM_SAMPLE_RANDOM_ACCESS_TYPE_SYNC
;
790 stss_entry
= stss_entry
->next
;
794 info
->prop
.random_access_type
= ISOM_SAMPLE_RANDOM_ACCESS_TYPE_SYNC
;
795 /* Check whether partial sync sample or not. */
798 isom_stps_entry_t
*stps_data
= (isom_stps_entry_t
*)stps_entry
->data
;
801 if( sample_number
== stps_data
->sample_number
)
803 info
->prop
.random_access_type
= QT_SAMPLE_RANDOM_ACCESS_TYPE_PARTIAL_SYNC
;
804 stps_entry
= stps_entry
->next
;
807 /* Get sample dependency info. */
810 isom_sdtp_entry_t
*sdtp_data
= (isom_sdtp_entry_t
*)sdtp_entry
->data
;
814 info
->prop
.leading
= sdtp_data
->is_leading
;
816 info
->prop
.allow_earlier
= sdtp_data
->is_leading
;
817 info
->prop
.independent
= sdtp_data
->sample_depends_on
;
818 info
->prop
.disposable
= sdtp_data
->sample_is_depended_on
;
819 info
->prop
.redundant
= sdtp_data
->sample_has_redundancy
;
820 sdtp_entry
= sdtp_entry
->next
;
822 /* Get roll recovery grouping info. */
823 if( sbgp_roll_entry
)
825 isom_group_assignment_entry_t
*assignment
= (isom_group_assignment_entry_t
*)sbgp_roll_entry
->data
;
828 if( sample_number_in_sbgp_roll_entry
== 1 && assignment
->group_description_index
)
830 isom_roll_entry_t
*roll_data
= (isom_roll_entry_t
*)lsmash_get_entry_data( sgpd_roll
->list
, assignment
->group_description_index
);
833 info
->prop
.random_access_type
= ISOM_SAMPLE_RANDOM_ACCESS_TYPE_RECOVERY
;
834 info
->prop
.recovery
.complete
= sample_number
+ roll_data
->roll_distance
;
836 INCREMENT_SAMPLE_NUMBER_IN_ENTRY( sample_number_in_sbgp_roll_entry
, sbgp_roll_entry
, assignment
);
838 info
->prop
.recovery
.identifier
= sample_number
;
839 /* Get random access point grouping info. */
842 isom_group_assignment_entry_t
*assignment
= (isom_group_assignment_entry_t
*)sbgp_rap_entry
->data
;
845 if( assignment
->group_description_index
&& (info
->prop
.random_access_type
== ISOM_SAMPLE_RANDOM_ACCESS_TYPE_NONE
) )
847 isom_rap_entry_t
*rap_data
= (isom_rap_entry_t
*)lsmash_get_entry_data( sgpd_rap
->list
, assignment
->group_description_index
);
850 /* If this is not an open RAP, we treat it as an unknown RAP since non-IDR sample could make a closed GOP. */
851 info
->prop
.random_access_type
= (rap_data
->num_leading_samples_known
&& !!rap_data
->num_leading_samples
)
852 ? ISOM_SAMPLE_RANDOM_ACCESS_TYPE_OPEN_RAP
853 : ISOM_SAMPLE_RANDOM_ACCESS_TYPE_UNKNOWN_RAP
;
855 INCREMENT_SAMPLE_NUMBER_IN_ENTRY( sample_number_in_sbgp_rap_entry
, sbgp_rap_entry
, assignment
);
858 else /* All LPCMFrame is sync sample. */
859 info
->prop
.random_access_type
= ISOM_SAMPLE_RANDOM_ACCESS_TYPE_SYNC
;
860 /* Get size of sample in the stream. */
861 if( is_lpcm_audio
|| !stsz_entry
)
862 info
->length
= constant_sample_size
;
865 if( !stsz_entry
->data
)
867 info
->length
= ((isom_stsz_entry_t
*)stsz_entry
->data
)->entry_size
;
868 stsz_entry
= stsz_entry
->next
;
870 /* Get chunk info. */
871 info
->pos
= data_offset
;
872 info
->index
= stsc_data
->sample_description_index
;
874 offset_from_chunk
+= info
->length
;
875 if( sample_number_in_chunk
== stsc_data
->samples_per_chunk
)
877 /* Move the next chunk. */
878 sample_number_in_chunk
= 1;
879 stco_entry
= stco_entry
->next
;
880 if( stco_entry
&& stco_entry
->data
)
881 data_offset
= large_presentation
882 ? ((isom_co64_entry_t
*)stco_entry
->data
)->chunk_offset
883 : ((isom_stco_entry_t
*)stco_entry
->data
)->chunk_offset
;
884 chunk
->length
= offset_from_chunk
; /* the length of the previous chunk */
885 chunk
= malloc( sizeof(isom_portable_chunk_t
) );
888 chunk
->number
= ++chunk_number
;
889 chunk
->data_offset
= data_offset
;
891 offset_from_chunk
= 0;
892 if( lsmash_add_entry( timeline
->chunk_list
, chunk
) )
895 && chunk_number
== ((isom_stsc_entry_t
*)next_stsc_entry
->data
)->first_chunk
)
897 stsc_entry
= next_stsc_entry
;
898 next_stsc_entry
= stsc_entry
->next
;
899 if( !stsc_entry
->data
)
901 stsc_data
= (isom_stsc_entry_t
*)stsc_entry
->data
;
902 /* Update sample description. */
903 description
= (isom_sample_entry_t
*)lsmash_get_entry_data( stsd
->list
, stsc_data
->sample_description_index
);
904 is_lpcm_audio
= isom_is_lpcm_audio( description
->type
);
906 constant_sample_size
= ((isom_audio_entry_t
*)description
)->constBytesPerAudioPacket
;
911 ++sample_number_in_chunk
;
912 data_offset
+= info
->length
;
914 /* OK. Let's add its info. */
915 if( lsmash_add_entry( timeline
->info_list
, info
) )
919 chunk
->length
= offset_from_chunk
;
920 if( lsmash_add_entry( root
->timeline
, timeline
) )
922 isom_destruct_timeline_direct( timeline
);
927 isom_destruct_timeline_direct( timeline
);
935 static int isom_get_dts_from_media_timeline_internal( isom_timeline_t
*timeline
, uint32_t sample_number
, uint64_t *dts
)
937 if( !timeline
|| !sample_number
|| !dts
)
939 if( sample_number
> timeline
->info_list
->entry_count
)
941 if( sample_number
== timeline
->last_accessed_sample_number
)
942 *dts
= timeline
->last_accessed_sample_dts
;
943 else if( sample_number
== 1 )
945 else if( sample_number
== timeline
->last_accessed_sample_number
+ 1 )
947 isom_sample_info_t
*info
= (isom_sample_info_t
*)lsmash_get_entry_data( timeline
->info_list
, timeline
->last_accessed_sample_number
);
950 *dts
= timeline
->last_accessed_sample_dts
+ info
->duration
;
952 else if( sample_number
== timeline
->last_accessed_sample_number
- 1 )
954 isom_sample_info_t
*info
= (isom_sample_info_t
*)lsmash_get_entry_data( timeline
->info_list
, timeline
->last_accessed_sample_number
- 1 );
957 *dts
= timeline
->last_accessed_sample_dts
- info
->duration
;
962 uint32_t distance
= sample_number
- 1;
963 lsmash_entry_t
*entry
;
964 for( entry
= timeline
->info_list
->head
; entry
; entry
= entry
->next
)
966 isom_sample_info_t
*info
= (isom_sample_info_t
*)entry
->data
;
971 *dts
+= info
->duration
;
976 timeline
->last_accessed_sample_dts
= *dts
;
977 timeline
->last_accessed_sample_number
= sample_number
;
981 int lsmash_get_dts_from_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t sample_number
, uint64_t *dts
)
983 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
984 return isom_get_dts_from_media_timeline_internal( timeline
, sample_number
, dts
);
987 lsmash_sample_t
*lsmash_get_sample_from_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t sample_number
)
990 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
991 if( isom_get_dts_from_media_timeline_internal( timeline
, sample_number
, &dts
) )
993 isom_sample_info_t
*info
= (isom_sample_info_t
*)lsmash_get_entry_data( timeline
->info_list
, sample_number
);
996 /* Get data of a sample from a chunk. */
997 isom_portable_chunk_t
*chunk
= info
->chunk
;
998 lsmash_bs_t
*bs
= root
->bs
;
999 if( (timeline
->last_accessed_chunk_number
!= chunk
->number
)
1000 || (timeline
->last_accessed_offset
> info
->pos
)
1001 || (timeline
->last_read_size
< (info
->pos
+ info
->length
- timeline
->last_accessed_offset
)) )
1003 /* Read data of a chunk in the stream. */
1006 if( root
->max_read_size
>= chunk
->length
)
1008 read_size
= chunk
->length
;
1009 seek_pos
= chunk
->data_offset
;
1013 read_size
= LSMASH_MAX( root
->max_read_size
, info
->length
);
1014 seek_pos
= info
->pos
;
1016 lsmash_fseek( bs
->stream
, seek_pos
, SEEK_SET
);
1017 lsmash_bs_empty( bs
);
1018 if( lsmash_bs_read_data( bs
, read_size
) )
1020 chunk
->data
= lsmash_bs_export_data( bs
, NULL
);
1023 lsmash_bs_empty( bs
);
1024 if( timeline
->last_accessed_chunk_data
)
1026 free( timeline
->last_accessed_chunk_data
);
1027 timeline
->last_accessed_chunk_data
= NULL
;
1029 timeline
->last_accessed_chunk_number
= chunk
->number
;
1030 timeline
->last_accessed_chunk_data
= chunk
->data
;
1031 timeline
->last_accessed_offset
= seek_pos
;
1032 timeline
->last_read_size
= read_size
;
1034 lsmash_sample_t
*sample
= lsmash_create_sample( 0 );
1037 uint64_t offset_from_seek
= info
->pos
- timeline
->last_accessed_offset
;
1038 sample
->data
= lsmash_memdup( chunk
->data
+ offset_from_seek
, info
->length
);
1041 lsmash_delete_sample( sample
);
1044 /* Get sample info. */
1046 sample
->cts
= timeline
->ctd_shift
? (dts
+ (int32_t)info
->offset
) : (dts
+ info
->offset
);
1047 sample
->length
= info
->length
;
1048 sample
->index
= info
->index
;
1049 sample
->prop
= info
->prop
;
1053 int lsmash_check_sample_existence_in_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t sample_number
)
1055 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1058 return !!lsmash_get_entry_data( timeline
->info_list
, sample_number
);
1061 int lsmash_get_last_sample_delta_from_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t *last_sample_delta
)
1063 if( !last_sample_delta
)
1065 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1066 if( !timeline
|| !timeline
->info_list
1067 || !timeline
->info_list
->tail
|| !timeline
->info_list
->tail
->data
)
1069 *last_sample_delta
= ((isom_sample_info_t
*)timeline
->info_list
->tail
->data
)->duration
;
1073 int lsmash_copy_timeline_map( lsmash_root_t
*dst
, uint32_t dst_track_ID
, lsmash_root_t
*src
, uint32_t src_track_ID
)
1075 isom_trak_entry_t
*dst_trak
= isom_get_trak( dst
, dst_track_ID
);
1076 if( !dst
->moov
|| !dst
->moov
->mvhd
|| !dst
->moov
->mvhd
->timescale
1077 || !dst_trak
|| !dst_trak
->mdia
|| !dst_trak
->mdia
->mdhd
|| !dst_trak
->mdia
->mdhd
->timescale
1078 || !dst_trak
->mdia
->minf
|| !dst_trak
->mdia
->minf
->stbl
)
1080 if( dst_trak
->edts
&& dst_trak
->edts
->elst
)
1081 lsmash_remove_entries( dst_trak
->edts
->elst
->list
, NULL
);
1082 uint32_t src_movie_timescale
;
1083 uint32_t src_media_timescale
;
1084 int32_t src_ctd_shift
; /* Add timeline shift difference between src and dst to each media_time.
1085 * Therefore, call this function as later as possible. */
1086 lsmash_entry_t
*src_entry
;
1087 isom_trak_entry_t
*src_trak
= isom_get_trak( src
, src_track_ID
);
1088 if( !src_trak
|| !src_trak
->edts
|| !src_trak
->edts
->elst
|| !src_trak
->edts
->elst
->list
)
1090 /* Get from timeline instead of boxes. */
1091 isom_timeline_t
*src_timeline
= isom_get_timeline( src
, src_track_ID
);
1092 if( !src_timeline
||!src_timeline
->movie_timescale
|| !src_timeline
->media_timescale
|| !src_timeline
->edit_list
)
1094 src_movie_timescale
= src_timeline
->movie_timescale
;
1095 src_media_timescale
= src_timeline
->media_timescale
;
1096 src_ctd_shift
= src_timeline
->ctd_shift
;
1097 src_entry
= src_timeline
->edit_list
->head
;
1101 if( !src
->moov
|| !src
->moov
->mvhd
|| !src
->moov
->mvhd
->timescale
1102 || !src_trak
->mdia
|| !src_trak
->mdia
->mdhd
|| !src_trak
->mdia
->mdhd
->timescale
1103 || !src_trak
->mdia
->minf
|| !src_trak
->mdia
->minf
->stbl
)
1105 src_movie_timescale
= src
->moov
->mvhd
->timescale
;
1106 src_media_timescale
= src_trak
->mdia
->mdhd
->timescale
;
1107 src_ctd_shift
= src_trak
->mdia
->minf
->stbl
->cslg
? src_trak
->mdia
->minf
->stbl
->cslg
->compositionToDTSShift
: 0;
1108 src_entry
= src_trak
->edts
->elst
->list
->head
;
1112 /* Generate edit list if absent in destination. */
1113 if( (!dst_trak
->edts
&& isom_add_edts( dst_trak
))
1114 || (!dst_trak
->edts
->elst
&& isom_add_elst( dst_trak
->edts
)) )
1116 uint32_t dst_movie_timescale
= dst
->moov
->mvhd
->timescale
;
1117 uint32_t dst_media_timescale
= dst_trak
->mdia
->mdhd
->timescale
;
1118 int32_t dst_ctd_shift
= dst_trak
->mdia
->minf
->stbl
->cslg
? dst_trak
->mdia
->minf
->stbl
->cslg
->compositionToDTSShift
: 0;
1119 int32_t media_time_shift
= src_ctd_shift
- dst_ctd_shift
;
1120 lsmash_entry_list_t
*dst_list
= dst_trak
->edts
->elst
->list
;
1123 isom_elst_entry_t
*src_data
= (isom_elst_entry_t
*)src_entry
->data
;
1126 isom_elst_entry_t
*dst_data
= (isom_elst_entry_t
*)malloc( sizeof(isom_elst_entry_t
) );
1129 dst_data
->segment_duration
= src_data
->segment_duration
* ((double)dst_movie_timescale
/ src_movie_timescale
) + 0.5;
1130 dst_data
->media_time
= (src_data
->media_time
+ media_time_shift
) * ((double)dst_media_timescale
/ src_media_timescale
) + 0.5;
1131 dst_data
->media_rate
= src_data
->media_rate
;
1132 if( lsmash_add_entry( dst_list
, dst_data
) )
1137 src_entry
= src_entry
->next
;
1142 int lsmash_copy_decoder_specific_info( lsmash_root_t
*dst
, uint32_t dst_track_ID
, lsmash_root_t
*src
, uint32_t src_track_ID
)
1144 isom_trak_entry_t
*dst_trak
= isom_get_trak( dst
, dst_track_ID
);
1145 if( !dst_trak
|| !dst_trak
->mdia
|| !dst_trak
->mdia
->minf
|| !dst_trak
->mdia
->minf
->stbl
1146 || !dst_trak
->mdia
->minf
->stbl
->stsd
|| !dst_trak
->mdia
->minf
->stbl
->stsd
->list
)
1148 isom_stsd_t
*dst_stsd
= dst_trak
->mdia
->minf
->stbl
->stsd
;
1149 lsmash_remove_entries( dst_stsd
->list
, isom_remove_sample_description
);
1150 lsmash_entry_t
*src_entry
= NULL
;
1151 isom_trak_entry_t
*src_trak
= isom_get_trak( src
, src_track_ID
);
1152 if( !src_trak
|| !src_trak
->mdia
|| !src_trak
->mdia
->minf
|| !src_trak
->mdia
->minf
->stbl
1153 || !src_trak
->mdia
->minf
->stbl
->stsd
|| !src_trak
->mdia
->minf
->stbl
->stsd
->list
)
1155 /* Get source entry from media timeline instead of Sample Description Box. */
1156 isom_timeline_t
*src_timeline
= isom_get_timeline( src
, src_track_ID
);
1157 if( !src_timeline
|| !src_timeline
->description_list
)
1159 src_entry
= src_timeline
->description_list
->head
;
1162 src_entry
= src_trak
->mdia
->minf
->stbl
->stsd
->list
->head
;
1164 return -1; /* Required at least one entry. */
1167 isom_sample_entry_t
*src_data
= (isom_sample_entry_t
*)src_entry
->data
;
1170 isom_sample_entry_t
*dst_data
= isom_duplicate_description( src_data
, dst_stsd
);
1173 if( lsmash_add_entry( dst_stsd
->list
, dst_data
) )
1175 isom_remove_sample_description( dst_data
);
1178 src_entry
= src_entry
->next
;
1180 /* Check if needed Track Aperture Modes. */
1181 if( dst_trak
->mdia
->minf
->vmhd
)
1183 isom_tapt_t
*tapt
= dst_trak
->tapt
;
1184 isom_visual_entry_t
*visual
= (isom_visual_entry_t
*)dst_stsd
->list
->head
->data
;
1185 if( dst_trak
->root
->qt_compatible
/* Track Aperture Modes is only available under QuickTime file format. */
1186 && !visual
->stsl
/* Sample scaling method might conflict with this feature. */
1187 && visual
->clap
&& visual
->pasp
/* Check if required boxes exist. */
1188 && tapt
&& tapt
->clef
&& tapt
->prof
&& tapt
->enof
/* */
1189 && dst_stsd
->list
->entry_count
== 1 ) /* Multiple sample description might conflict with this. */
1191 uint32_t width
= visual
->width
<< 16;
1192 uint32_t height
= visual
->height
<< 16;
1193 double clap_width
= ((double)visual
->clap
->cleanApertureWidthN
/ visual
->clap
->cleanApertureWidthD
) * (1<<16);
1194 double clap_height
= ((double)visual
->clap
->cleanApertureHeightN
/ visual
->clap
->cleanApertureHeightD
) * (1<<16);
1195 double par
= (double)visual
->pasp
->hSpacing
/ visual
->pasp
->vSpacing
;
1198 tapt
->clef
->width
= clap_width
* par
;
1199 tapt
->clef
->height
= clap_height
;
1200 tapt
->prof
->width
= width
* par
;
1201 tapt
->prof
->height
= height
;
1205 tapt
->clef
->width
= clap_width
;
1206 tapt
->clef
->height
= clap_height
/ par
;
1207 tapt
->prof
->width
= width
;
1208 tapt
->prof
->height
= height
/ par
;
1210 tapt
->enof
->width
= width
;
1211 tapt
->enof
->height
= height
;
1214 isom_remove_tapt( dst_trak
->tapt
);
1219 int lsmash_set_media_timestamps( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_media_ts_list_t
*ts_list
)
1223 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1226 if( ts_list
->sample_count
!= timeline
->info_list
->entry_count
)
1227 return -1; /* Number of samples must be same. */
1228 lsmash_media_ts_t
*ts
= ts_list
->timestamp
;
1230 return -1; /* DTS must start from value zero. */
1232 uint32_t sample_count
= ts_list
->sample_count
;
1234 if( timeline
->info_list
->entry_count
> 1 )
1237 lsmash_entry_t
*entry
= timeline
->info_list
->head
;
1238 isom_sample_info_t
*info
;
1239 while( i
< sample_count
)
1241 info
= (isom_sample_info_t
*)entry
->data
;
1242 if( !info
|| (ts
[i
].dts
< ts
[i
- 1].dts
) )
1244 info
->duration
= ts
[i
].dts
- ts
[i
- 1].dts
;
1245 entry
= entry
->next
;
1250 if( !entry
|| !entry
->data
)
1252 /* Copy the previous duration. */
1253 ((isom_sample_info_t
*)entry
->data
)->duration
= info
->duration
;
1256 return -1; /* Irregular case: sample_count this timeline has is incorrect. */
1258 else /* still image */
1259 ((isom_sample_info_t
*)timeline
->info_list
->head
->data
)->duration
= UINT32_MAX
;
1261 * ToDo: hint track must not have any sample_offset. */
1263 timeline
->ctd_shift
= 0;
1264 for( lsmash_entry_t
*entry
= timeline
->info_list
->head
; entry
; entry
= entry
->next
)
1266 isom_sample_info_t
*info
= (isom_sample_info_t
*)entry
->data
;
1267 if( (ts
[i
].cts
+ timeline
->ctd_shift
) < ts
[i
].dts
)
1268 timeline
->ctd_shift
= ts
[i
].dts
- ts
[i
].cts
;
1269 info
->offset
= ts
[i
].cts
- ts
[i
].dts
;
1272 if( timeline
->ctd_shift
&& (!root
->qt_compatible
|| root
->max_isom_version
< 4) )
1273 return -1; /* Don't allow composition to decode timeline shift. */
1277 int lsmash_get_media_timestamps( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_media_ts_list_t
*ts_list
)
1281 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1284 uint32_t sample_count
= timeline
->info_list
->entry_count
;
1287 ts_list
->sample_count
= 0;
1288 ts_list
->timestamp
= NULL
;
1291 lsmash_media_ts_t
*ts
= malloc( sample_count
* sizeof(lsmash_media_ts_t
) );
1296 for( lsmash_entry_t
*entry
= timeline
->info_list
->head
; entry
; entry
= entry
->next
)
1298 isom_sample_info_t
*info
= (isom_sample_info_t
*)entry
->data
;
1305 ts
[i
].cts
= timeline
->ctd_shift
? (dts
+ (int32_t)info
->offset
) : (dts
+ info
->offset
);
1306 dts
+= info
->duration
;
1309 ts_list
->sample_count
= sample_count
;
1310 ts_list
->timestamp
= ts
;
1314 int lsmash_get_media_timeline_shift( lsmash_root_t
*root
, uint32_t track_ID
, int32_t *timeline_shift
)
1316 if( !timeline_shift
)
1318 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1321 *timeline_shift
= timeline
->ctd_shift
;
1325 #endif /* LSMASH_DEMUXER_ENABLED */