1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2011-2014 L-SMASH project
6 * Authors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 *****************************************************************************/
21 /* This file is available under an ISC license. */
23 #ifdef LSMASH_DEMUXER_ENABLED
25 #include "common/internal.h" /* must be placed first */
33 #include "codecs/mp4a.h"
34 #include "codecs/mp4sys.h"
35 #include "codecs/description.h"
37 #define NO_RANDOM_ACCESS_POINT 0xffffffff
43 uint32_t number
; /* useless at present */
45 } isom_portable_chunk_t
;
54 isom_portable_chunk_t
*chunk
;
55 lsmash_sample_property_t prop
;
60 uint64_t pos
; /* position of the first sample in this bunch */
61 uint32_t duration
; /* duration in media timescale each sample has */
62 uint32_t offset
; /* offset between composition time and decoding time each sample has */
63 uint32_t length
; /* data size each sample has */
64 uint32_t index
; /* sample_description_index applied to each sample */
65 isom_portable_chunk_t
*chunk
; /* chunk samples belong to */
66 lsmash_sample_property_t prop
; /* property applied to each sample */
67 uint32_t sample_count
; /* number of samples in this bunch */
70 static const lsmash_class_t lsmash_timeline_class
=
75 typedef struct isom_timeline_tag isom_timeline_t
;
77 struct isom_timeline_tag
79 const lsmash_class_t
*class;
81 uint32_t movie_timescale
;
82 uint32_t media_timescale
;
83 uint32_t sample_count
;
84 uint32_t max_sample_size
;
85 uint32_t ctd_shift
; /* shift from composition to decode timeline */
86 uint64_t media_duration
;
87 uint64_t track_duration
;
88 uint32_t last_accessed_sample_number
;
89 uint64_t last_accessed_sample_dts
;
90 uint32_t last_accessed_lpcm_bunch_number
;
91 uint32_t last_accessed_lpcm_bunch_duration
;
92 uint32_t last_accessed_lpcm_bunch_sample_count
;
93 uint32_t last_accessed_lpcm_bunch_first_sample_number
;
94 uint64_t last_accessed_lpcm_bunch_dts
;
95 lsmash_entry_list_t edit_list
[1]; /* list of edits */
96 lsmash_entry_list_t chunk_list
[1]; /* list of chunks */
97 lsmash_entry_list_t info_list
[1]; /* list of sample info */
98 lsmash_entry_list_t bunch_list
[1]; /* list of LPCM bunch */
99 int (*get_dts
)( isom_timeline_t
*timeline
, uint32_t sample_number
, uint64_t *dts
);
100 int (*get_cts
)( isom_timeline_t
*timeline
, uint32_t sample_number
, uint64_t *cts
);
101 int (*get_sample_duration
)( isom_timeline_t
*timeline
, uint32_t sample_number
, uint32_t *sample_duration
);
102 lsmash_sample_t
*(*get_sample
)( isom_timeline_t
*timeline
, uint32_t sample_number
);
103 int (*get_sample_info
)( isom_timeline_t
*timeline
, uint32_t sample_number
, lsmash_sample_t
*sample
);
104 int (*get_sample_property
)( isom_timeline_t
*timeline
, uint32_t sample_number
, lsmash_sample_property_t
*prop
);
105 int (*check_sample_existence
)( isom_timeline_t
*timeline
, uint32_t sample_number
);
108 static isom_timeline_t
*isom_get_timeline( lsmash_root_t
*root
, uint32_t track_ID
)
110 if( !track_ID
|| !root
|| !root
->file
|| !root
->file
->timeline
)
112 for( lsmash_entry_t
*entry
= root
->file
->timeline
->head
; entry
; entry
= entry
->next
)
114 isom_timeline_t
*timeline
= (isom_timeline_t
*)entry
->data
;
117 if( timeline
->track_ID
== track_ID
)
123 static isom_timeline_t
*isom_create_timeline( void )
125 isom_timeline_t
*timeline
= lsmash_malloc_zero( sizeof(isom_timeline_t
) );
128 timeline
->class = &lsmash_timeline_class
;
129 lsmash_init_entry_list( timeline
->edit_list
);
130 lsmash_init_entry_list( timeline
->chunk_list
);
131 lsmash_init_entry_list( timeline
->info_list
);
132 lsmash_init_entry_list( timeline
->bunch_list
);
136 static void isom_destruct_timeline_direct( isom_timeline_t
*timeline
)
140 lsmash_remove_entries( timeline
->edit_list
, NULL
);
141 lsmash_remove_entries( timeline
->chunk_list
, NULL
); /* chunk data must be already freed. */
142 lsmash_remove_entries( timeline
->info_list
, NULL
);
143 lsmash_remove_entries( timeline
->bunch_list
, NULL
);
144 lsmash_free( timeline
);
147 void isom_remove_timelines( lsmash_file_t
*file
)
152 lsmash_remove_list( file
->timeline
, isom_destruct_timeline_direct
);
155 void lsmash_destruct_timeline( lsmash_root_t
*root
, uint32_t track_ID
)
160 || !root
->file
->timeline
)
162 for( lsmash_entry_t
*entry
= root
->file
->timeline
->head
; entry
; entry
= entry
->next
)
164 isom_timeline_t
*timeline
= (isom_timeline_t
*)entry
->data
;
167 if( timeline
->track_ID
== track_ID
)
169 lsmash_remove_entry_direct( root
->file
->timeline
, entry
, isom_destruct_timeline_direct
);
175 static void isom_get_qt_fixed_comp_audio_sample_quants
177 isom_timeline_t
*timeline
,
178 isom_sample_entry_t
*description
,
179 uint32_t *samples_per_packet
,
180 uint32_t *constant_sample_size
183 isom_audio_entry_t
*audio
= (isom_audio_entry_t
*)description
;
184 if( audio
->version
== 0 )
187 if( !isom_get_implicit_qt_fixed_comp_audio_sample_quants( audio
, samples_per_packet
, constant_sample_size
, &dummy
) )
190 if( !isom_is_lpcm_audio( audio
) )
191 lsmash_log( timeline
, LSMASH_LOG_WARNING
, "unsupported implicit sample table!\n" );
192 *samples_per_packet
= 1;
193 *constant_sample_size
= (audio
->samplesize
* audio
->channelcount
) / 8;
196 else if( audio
->version
== 1 )
198 *samples_per_packet
= audio
->samplesPerPacket
;
199 *constant_sample_size
= audio
->bytesPerFrame
;
201 else /* if( audio->version == 2 ) */
203 *samples_per_packet
= audio
->constLPCMFramesPerAudioPacket
;
204 *constant_sample_size
= audio
->constBytesPerAudioPacket
;
208 static int isom_is_qt_fixed_compressed_audio
210 isom_sample_entry_t
*description
213 if( (description
->manager
& LSMASH_VIDEO_DESCRIPTION
) || !isom_is_qt_audio( description
->type
) )
215 /* LPCM is a special case of fixed compression. */
216 return (((isom_audio_entry_t
*)description
)->compression_ID
!= QT_AUDIO_COMPRESSION_ID_VARIABLE_COMPRESSION
);
219 static int isom_add_sample_info_entry( isom_timeline_t
*timeline
, isom_sample_info_t
*src_info
)
221 isom_sample_info_t
*dst_info
= lsmash_malloc( sizeof(isom_sample_info_t
) );
224 if( lsmash_add_entry( timeline
->info_list
, dst_info
) )
226 lsmash_free( dst_info
);
229 *dst_info
= *src_info
;
233 static int isom_add_lpcm_bunch_entry( isom_timeline_t
*timeline
, isom_lpcm_bunch_t
*src_bunch
)
235 isom_lpcm_bunch_t
*dst_bunch
= lsmash_malloc( sizeof(isom_lpcm_bunch_t
) );
238 if( lsmash_add_entry( timeline
->bunch_list
, dst_bunch
) )
240 lsmash_free( dst_bunch
);
243 *dst_bunch
= *src_bunch
;
247 static int isom_add_portable_chunk_entry( isom_timeline_t
*timeline
, isom_portable_chunk_t
*src_chunk
)
249 isom_portable_chunk_t
*dst_chunk
= lsmash_malloc( sizeof(isom_portable_chunk_t
) );
252 if( lsmash_add_entry( timeline
->chunk_list
, dst_chunk
) )
254 lsmash_free( dst_chunk
);
257 *dst_chunk
= *src_chunk
;
261 static int isom_compare_lpcm_sample_info( isom_lpcm_bunch_t
*bunch
, isom_sample_info_t
*info
)
263 return info
->duration
!= bunch
->duration
264 || info
->offset
!= bunch
->offset
265 || info
->length
!= bunch
->length
266 || info
->index
!= bunch
->index
267 || info
->chunk
!= bunch
->chunk
;
270 static void isom_update_bunch( isom_lpcm_bunch_t
*bunch
, isom_sample_info_t
*info
)
272 bunch
->pos
= info
->pos
;
273 bunch
->duration
= info
->duration
;
274 bunch
->offset
= info
->offset
;
275 bunch
->length
= info
->length
;
276 bunch
->index
= info
->index
;
277 bunch
->chunk
= info
->chunk
;
278 bunch
->prop
= info
->prop
;
279 bunch
->sample_count
= 1;
282 static isom_lpcm_bunch_t
*isom_get_bunch( isom_timeline_t
*timeline
, uint32_t sample_number
)
284 if( sample_number
>= timeline
->last_accessed_lpcm_bunch_first_sample_number
285 && sample_number
< timeline
->last_accessed_lpcm_bunch_first_sample_number
+ timeline
->last_accessed_lpcm_bunch_sample_count
)
286 /* Get from the last accessed LPCM bunch. */
287 return (isom_lpcm_bunch_t
*)lsmash_get_entry_data( timeline
->bunch_list
, timeline
->last_accessed_lpcm_bunch_number
);
288 uint32_t first_sample_number_in_next_bunch
;
289 uint32_t bunch_number
= 1;
291 if( timeline
->last_accessed_lpcm_bunch_first_sample_number
292 && timeline
->last_accessed_lpcm_bunch_first_sample_number
<= sample_number
)
294 first_sample_number_in_next_bunch
= timeline
->last_accessed_lpcm_bunch_first_sample_number
+ timeline
->last_accessed_lpcm_bunch_sample_count
;
295 bunch_number
+= timeline
->last_accessed_lpcm_bunch_number
;
296 bunch_dts
= timeline
->last_accessed_lpcm_bunch_dts
297 + timeline
->last_accessed_lpcm_bunch_duration
* timeline
->last_accessed_lpcm_bunch_sample_count
;
301 /* Seek from the first LPCM bunch. */
302 first_sample_number_in_next_bunch
= 1;
305 isom_lpcm_bunch_t
*bunch
= (isom_lpcm_bunch_t
*)lsmash_get_entry_data( timeline
->bunch_list
, bunch_number
++ );
308 first_sample_number_in_next_bunch
+= bunch
->sample_count
;
309 while( sample_number
>= first_sample_number_in_next_bunch
)
311 bunch_dts
+= bunch
->duration
* bunch
->sample_count
;
312 bunch
= (isom_lpcm_bunch_t
*)lsmash_get_entry_data( timeline
->bunch_list
, bunch_number
++ );
315 first_sample_number_in_next_bunch
+= bunch
->sample_count
;
317 timeline
->last_accessed_lpcm_bunch_dts
= bunch_dts
;
318 timeline
->last_accessed_lpcm_bunch_number
= bunch_number
- 1;
319 timeline
->last_accessed_lpcm_bunch_duration
= bunch
->duration
;
320 timeline
->last_accessed_lpcm_bunch_sample_count
= bunch
->sample_count
;
321 timeline
->last_accessed_lpcm_bunch_first_sample_number
= first_sample_number_in_next_bunch
- bunch
->sample_count
;
325 static int isom_get_dts_from_info_list( isom_timeline_t
*timeline
, uint32_t sample_number
, uint64_t *dts
)
327 if( sample_number
== timeline
->last_accessed_sample_number
)
328 *dts
= timeline
->last_accessed_sample_dts
;
329 else if( sample_number
== 1 )
331 else if( sample_number
== timeline
->last_accessed_sample_number
+ 1 )
333 isom_sample_info_t
*info
= (isom_sample_info_t
*)lsmash_get_entry_data( timeline
->info_list
, timeline
->last_accessed_sample_number
);
336 *dts
= timeline
->last_accessed_sample_dts
+ info
->duration
;
338 else if( sample_number
== timeline
->last_accessed_sample_number
- 1 )
340 isom_sample_info_t
*info
= (isom_sample_info_t
*)lsmash_get_entry_data( timeline
->info_list
, timeline
->last_accessed_sample_number
- 1 );
343 *dts
= timeline
->last_accessed_sample_dts
- info
->duration
;
348 uint32_t distance
= sample_number
- 1;
349 lsmash_entry_t
*entry
;
350 for( entry
= timeline
->info_list
->head
; entry
; entry
= entry
->next
)
352 isom_sample_info_t
*info
= (isom_sample_info_t
*)entry
->data
;
355 if( distance
-- == 0 )
357 *dts
+= info
->duration
;
362 /* Note: last_accessed_sample_number is always updated together with last_accessed_sample_dts, and vice versa. */
363 timeline
->last_accessed_sample_dts
= *dts
;
364 timeline
->last_accessed_sample_number
= sample_number
;
368 static int isom_get_cts_from_info_list( isom_timeline_t
*timeline
, uint32_t sample_number
, uint64_t *cts
)
370 if( isom_get_dts_from_info_list( timeline
, sample_number
, cts
) )
372 isom_sample_info_t
*info
= (isom_sample_info_t
*)lsmash_get_entry_data( timeline
->info_list
, sample_number
);
375 *cts
= timeline
->ctd_shift
? (*cts
+ (int32_t)info
->offset
) : (*cts
+ info
->offset
);
379 static int isom_get_dts_from_bunch_list( isom_timeline_t
*timeline
, uint32_t sample_number
, uint64_t *dts
)
381 isom_lpcm_bunch_t
*bunch
= isom_get_bunch( timeline
, sample_number
);
384 *dts
= timeline
->last_accessed_lpcm_bunch_dts
+ (sample_number
- timeline
->last_accessed_lpcm_bunch_first_sample_number
) * bunch
->duration
;
388 static int isom_get_cts_from_bunch_list( isom_timeline_t
*timeline
, uint32_t sample_number
, uint64_t *cts
)
390 isom_lpcm_bunch_t
*bunch
= isom_get_bunch( timeline
, sample_number
);
393 *cts
= timeline
->last_accessed_lpcm_bunch_dts
+ (sample_number
- timeline
->last_accessed_lpcm_bunch_first_sample_number
) * bunch
->duration
+ bunch
->offset
;
397 static int isom_get_sample_duration_from_info_list( isom_timeline_t
*timeline
, uint32_t sample_number
, uint32_t *sample_duration
)
399 isom_sample_info_t
*info
= (isom_sample_info_t
*)lsmash_get_entry_data( timeline
->info_list
, sample_number
);
402 *sample_duration
= info
->duration
;
406 static int isom_get_sample_duration_from_bunch_list( isom_timeline_t
*timeline
, uint32_t sample_number
, uint32_t *sample_duration
)
408 isom_lpcm_bunch_t
*bunch
= isom_get_bunch( timeline
, sample_number
);
411 *sample_duration
= bunch
->duration
;
415 static int isom_check_sample_existence_in_info_list( isom_timeline_t
*timeline
, uint32_t sample_number
)
417 isom_sample_info_t
*info
= (isom_sample_info_t
*)lsmash_get_entry_data( timeline
->info_list
, sample_number
);
418 if( !info
|| !info
->chunk
)
420 return !!info
->chunk
->file
;
423 static int isom_check_sample_existence_in_bunch_list( isom_timeline_t
*timeline
, uint32_t sample_number
)
425 isom_lpcm_bunch_t
*bunch
= isom_get_bunch( timeline
, sample_number
);
426 if( !bunch
|| !bunch
->chunk
)
428 return !!bunch
->chunk
->file
;
431 static lsmash_sample_t
*isom_read_sample_data_from_stream
434 isom_timeline_t
*timeline
,
435 uint32_t sample_length
,
439 lsmash_sample_t
*sample
= lsmash_create_sample( 0 );
442 lsmash_bs_t
*bs
= file
->bs
;
443 lsmash_bs_read_seek( bs
, sample_pos
, SEEK_SET
);
444 sample
->data
= lsmash_bs_get_bytes( bs
, sample_length
);
447 lsmash_delete_sample( sample
);
453 static lsmash_sample_t
*isom_get_lpcm_sample_from_media_timeline( isom_timeline_t
*timeline
, uint32_t sample_number
)
455 isom_lpcm_bunch_t
*bunch
= isom_get_bunch( timeline
, sample_number
);
459 /* Get data of a sample from the stream. */
460 uint64_t sample_number_offset
= sample_number
- timeline
->last_accessed_lpcm_bunch_first_sample_number
;
461 uint64_t sample_pos
= bunch
->pos
+ sample_number_offset
* bunch
->length
;
462 lsmash_sample_t
*sample
= isom_read_sample_data_from_stream( bunch
->chunk
->file
, timeline
, bunch
->length
, sample_pos
);
465 /* Get sample info. */
466 sample
->dts
= timeline
->last_accessed_lpcm_bunch_dts
+ sample_number_offset
* bunch
->duration
;
467 sample
->cts
= timeline
->ctd_shift
? (sample
->dts
+ (int32_t)bunch
->offset
) : (sample
->dts
+ bunch
->offset
);
468 sample
->pos
= sample_pos
;
469 sample
->length
= bunch
->length
;
470 sample
->index
= bunch
->index
;
471 sample
->prop
= bunch
->prop
;
475 static lsmash_sample_t
*isom_get_sample_from_media_timeline( isom_timeline_t
*timeline
, uint32_t sample_number
)
478 if( isom_get_dts_from_info_list( timeline
, sample_number
, &dts
) )
480 isom_sample_info_t
*info
= (isom_sample_info_t
*)lsmash_get_entry_data( timeline
->info_list
, sample_number
);
484 /* Get data of a sample from the stream. */
485 lsmash_sample_t
*sample
= isom_read_sample_data_from_stream( info
->chunk
->file
, timeline
, info
->length
, info
->pos
);
488 /* Get sample info. */
490 sample
->cts
= timeline
->ctd_shift
? (dts
+ (int32_t)info
->offset
) : (dts
+ info
->offset
);
491 sample
->pos
= info
->pos
;
492 sample
->length
= info
->length
;
493 sample
->index
= info
->index
;
494 sample
->prop
= info
->prop
;
498 static int isom_get_lpcm_sample_info_from_media_timeline( isom_timeline_t
*timeline
, uint32_t sample_number
, lsmash_sample_t
*sample
)
500 isom_lpcm_bunch_t
*bunch
= isom_get_bunch( timeline
, sample_number
);
503 uint64_t sample_number_offset
= sample_number
- timeline
->last_accessed_lpcm_bunch_first_sample_number
;
504 sample
->dts
= timeline
->last_accessed_lpcm_bunch_dts
+ sample_number_offset
* bunch
->duration
;
505 sample
->cts
= timeline
->ctd_shift
? (sample
->dts
+ (int32_t)bunch
->offset
) : (sample
->dts
+ bunch
->offset
);
506 sample
->pos
= bunch
->pos
+ sample_number_offset
* bunch
->length
;
507 sample
->length
= bunch
->length
;
508 sample
->index
= bunch
->index
;
509 sample
->prop
= bunch
->prop
;
513 static int isom_get_sample_info_from_media_timeline( isom_timeline_t
*timeline
, uint32_t sample_number
, lsmash_sample_t
*sample
)
516 if( isom_get_dts_from_info_list( timeline
, sample_number
, &dts
) )
518 isom_sample_info_t
*info
= (isom_sample_info_t
*)lsmash_get_entry_data( timeline
->info_list
, sample_number
);
522 sample
->cts
= timeline
->ctd_shift
? (dts
+ (int32_t)info
->offset
) : (dts
+ info
->offset
);
523 sample
->pos
= info
->pos
;
524 sample
->length
= info
->length
;
525 sample
->index
= info
->index
;
526 sample
->prop
= info
->prop
;
530 static int isom_get_lpcm_sample_property_from_media_timeline( isom_timeline_t
*timeline
, uint32_t sample_number
, lsmash_sample_property_t
*prop
)
532 memset( prop
, 0, sizeof(lsmash_sample_property_t
) );
533 prop
->ra_flags
= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC
;
537 static int isom_get_sample_property_from_media_timeline( isom_timeline_t
*timeline
, uint32_t sample_number
, lsmash_sample_property_t
*prop
)
539 isom_sample_info_t
*info
= (isom_sample_info_t
*)lsmash_get_entry_data( timeline
->info_list
, sample_number
);
546 static inline void isom_increment_sample_number_in_entry
548 uint32_t *sample_number_in_entry
,
549 lsmash_entry_t
**entry
,
550 uint32_t sample_count
553 if( *sample_number_in_entry
== sample_count
)
555 *sample_number_in_entry
= 1;
556 *entry
= (*entry
)->next
;
559 *sample_number_in_entry
+= 1;
562 static inline isom_sgpd_t
*isom_select_appropriate_sgpd
565 isom_sgpd_t
*sgpd_frag
,
566 uint32_t *group_description_index
569 if( sgpd_frag
&& *group_description_index
>= 0x10000 )
571 /* The specification doesn't define 0x10000 explicitly, however says that there must be fewer than
572 * 65536 group definitions for this track and grouping type in the sample table in the Movie Box.
573 * So, we assume 0x10000 is equivalent to 0. */
574 *group_description_index
-= 0x10000;
581 static int isom_get_roll_recovery_grouping_info
583 isom_timeline_t
*timeline
,
584 lsmash_entry_t
**sbgp_roll_entry
,
585 isom_sgpd_t
*sgpd_roll
,
586 isom_sgpd_t
*sgpd_frag_roll
,
587 uint32_t *sample_number_in_sbgp_roll_entry
,
588 isom_sample_info_t
*info
,
589 uint32_t sample_number
592 isom_group_assignment_entry_t
*assignment
= (isom_group_assignment_entry_t
*)(*sbgp_roll_entry
)->data
;
595 if( assignment
->group_description_index
)
597 uint32_t group_description_index
= assignment
->group_description_index
;
598 isom_sgpd_t
*sgpd
= isom_select_appropriate_sgpd( sgpd_roll
, sgpd_frag_roll
, &group_description_index
);
599 isom_roll_entry_t
*roll_data
= (isom_roll_entry_t
*)lsmash_get_entry_data( sgpd
->list
, group_description_index
);
602 if( roll_data
->roll_distance
> 0 )
605 info
->prop
.post_roll
.complete
= sample_number
+ roll_data
->roll_distance
;
606 if( info
->prop
.ra_flags
== ISOM_SAMPLE_RANDOM_ACCESS_FLAG_NONE
)
607 info
->prop
.ra_flags
|= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_POST_ROLL_START
;
609 else if( roll_data
->roll_distance
< 0 )
612 info
->prop
.pre_roll
.distance
= -roll_data
->roll_distance
;
613 if( info
->prop
.ra_flags
== ISOM_SAMPLE_RANDOM_ACCESS_FLAG_NONE
)
614 info
->prop
.ra_flags
|= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_PRE_ROLL_END
;
617 else if( *sample_number_in_sbgp_roll_entry
== 1 && group_description_index
)
618 lsmash_log( timeline
, LSMASH_LOG_WARNING
, "a description of roll recoveries is not found in the Sample Group Description Box.\n" );
620 isom_increment_sample_number_in_entry( sample_number_in_sbgp_roll_entry
, sbgp_roll_entry
, assignment
->sample_count
);
624 static int isom_get_random_access_point_grouping_info
626 isom_timeline_t
*timeline
,
627 lsmash_entry_t
**sbgp_rap_entry
,
628 isom_sgpd_t
*sgpd_rap
,
629 isom_sgpd_t
*sgpd_frag_rap
,
630 uint32_t *sample_number_in_sbgp_rap_entry
,
631 isom_sample_info_t
*info
,
635 isom_group_assignment_entry_t
*assignment
= (isom_group_assignment_entry_t
*)(*sbgp_rap_entry
)->data
;
638 if( assignment
->group_description_index
&& (info
->prop
.ra_flags
== ISOM_SAMPLE_RANDOM_ACCESS_FLAG_NONE
) )
640 uint32_t group_description_index
= assignment
->group_description_index
;
641 isom_sgpd_t
*sgpd
= isom_select_appropriate_sgpd( sgpd_rap
, sgpd_frag_rap
, &group_description_index
);
642 isom_rap_entry_t
*rap_data
= (isom_rap_entry_t
*)lsmash_get_entry_data( sgpd
->list
, group_description_index
);
645 /* If this is not an open RAP, we treat it as an unknown RAP since non-IDR sample could make a closed GOP. */
646 info
->prop
.ra_flags
|= (rap_data
->num_leading_samples_known
&& !!rap_data
->num_leading_samples
)
647 ? ISOM_SAMPLE_RANDOM_ACCESS_FLAG_OPEN_RAP
648 : ISOM_SAMPLE_RANDOM_ACCESS_FLAG_RAP
;
651 else if( *sample_number_in_sbgp_rap_entry
== 1 && group_description_index
)
652 lsmash_log( timeline
, LSMASH_LOG_WARNING
, "a description of random access points is not found in the Sample Group Description Box.\n" );
654 isom_increment_sample_number_in_entry( sample_number_in_sbgp_rap_entry
, sbgp_rap_entry
, assignment
->sample_count
);
658 int lsmash_construct_timeline( lsmash_root_t
*root
, uint32_t track_ID
)
662 lsmash_file_t
*file
= root
->file
;
666 || file
->moov
->mvhd
->timescale
== 0 )
668 /* Get track by track_ID. */
669 isom_trak_t
*trak
= isom_get_trak( file
, track_ID
);
674 || trak
->mdia
->mdhd
->timescale
== 0
676 || !trak
->mdia
->minf
->stbl
)
678 /* Create a timeline list if it doesn't exist. */
679 if( !file
->timeline
)
681 file
->timeline
= lsmash_create_entry_list();
682 if( !file
->timeline
)
685 /* Create a timeline. */
686 isom_timeline_t
*timeline
= isom_create_timeline();
689 timeline
->track_ID
= track_ID
;
690 timeline
->movie_timescale
= file
->moov
->mvhd
->timescale
;
691 timeline
->media_timescale
= trak
->mdia
->mdhd
->timescale
;
692 timeline
->track_duration
= trak
->tkhd
->duration
;
693 /* Preparation for construction. */
694 isom_elst_t
*elst
= trak
->edts
? trak
->edts
->elst
: NULL
;
695 isom_minf_t
*minf
= trak
->mdia
->minf
;
696 isom_dref_t
*dref
= minf
->dinf
->dref
;
697 isom_stbl_t
*stbl
= minf
->stbl
;
698 isom_stsd_t
*stsd
= stbl
->stsd
;
699 isom_stts_t
*stts
= stbl
->stts
;
700 isom_ctts_t
*ctts
= stbl
->ctts
;
701 isom_stss_t
*stss
= stbl
->stss
;
702 isom_stps_t
*stps
= stbl
->stps
;
703 isom_sdtp_t
*sdtp
= stbl
->sdtp
;
704 isom_stsc_t
*stsc
= stbl
->stsc
;
705 isom_stsz_t
*stsz
= stbl
->stsz
;
706 isom_stco_t
*stco
= stbl
->stco
;
707 isom_sgpd_t
*sgpd_rap
= isom_get_sample_group_description( stbl
, ISOM_GROUP_TYPE_RAP
);
708 isom_sbgp_t
*sbgp_rap
= isom_get_sample_to_group ( stbl
, ISOM_GROUP_TYPE_RAP
);
709 isom_sgpd_t
*sgpd_roll
= isom_get_roll_recovery_sample_group_description( &stbl
->sgpd_list
);
710 isom_sbgp_t
*sbgp_roll
= isom_get_roll_recovery_sample_to_group ( &stbl
->sbgp_list
);
711 lsmash_entry_t
*elst_entry
= elst
&& elst
->list
? elst
->list
->head
: NULL
;
712 lsmash_entry_t
*stts_entry
= stts
&& stts
->list
? stts
->list
->head
: NULL
;
713 lsmash_entry_t
*ctts_entry
= ctts
&& ctts
->list
? ctts
->list
->head
: NULL
;
714 lsmash_entry_t
*stss_entry
= stss
&& stss
->list
? stss
->list
->head
: NULL
;
715 lsmash_entry_t
*stps_entry
= stps
&& stps
->list
? stps
->list
->head
: NULL
;
716 lsmash_entry_t
*sdtp_entry
= sdtp
&& sdtp
->list
? sdtp
->list
->head
: NULL
;
717 lsmash_entry_t
*stsz_entry
= stsz
&& stsz
->list
? stsz
->list
->head
: NULL
;
718 lsmash_entry_t
*stsc_entry
= stsc
&& stsc
->list
? stsc
->list
->head
: NULL
;
719 lsmash_entry_t
*stco_entry
= stco
&& stco
->list
? stco
->list
->head
: NULL
;
720 lsmash_entry_t
*sbgp_roll_entry
= sbgp_roll
&& sbgp_roll
->list
? sbgp_roll
->list
->head
: NULL
;
721 lsmash_entry_t
*sbgp_rap_entry
= sbgp_rap
&& sbgp_rap
->list
? sbgp_rap
->list
->head
: NULL
;
722 lsmash_entry_t
*next_stsc_entry
= stsc_entry
? stsc_entry
->next
: NULL
;
723 isom_stsc_entry_t
*stsc_data
= stsc_entry
? (isom_stsc_entry_t
*)stsc_entry
->data
: NULL
;
724 int movie_framemts_present
= (file
->moov
->mvex
&& file
->moof_list
.head
);
725 if( !movie_framemts_present
&& (!stts_entry
|| !stsc_entry
|| !stco_entry
|| !stco_entry
->data
|| (next_stsc_entry
&& !next_stsc_entry
->data
)) )
727 isom_sample_entry_t
*description
= (isom_sample_entry_t
*)lsmash_get_entry_data( &stsd
->list
, stsc_data
? stsc_data
->sample_description_index
: 1 );
730 isom_dref_entry_t
*dref_entry
= (isom_dref_entry_t
*)lsmash_get_entry_data( &dref
->list
, description
->data_reference_index
);
731 int all_sync
= !stss
;
732 int large_presentation
= stco
->large_presentation
|| lsmash_check_box_type_identical( stco
->type
, ISOM_BOX_TYPE_CO64
);
733 int is_lpcm_audio
= isom_is_lpcm_audio( description
);
734 int is_qt_fixed_comp_audio
= isom_is_qt_fixed_compressed_audio( description
);
735 int iso_sdtp
= file
->max_isom_version
>= 2 || file
->avc_extensions
;
736 int allow_negative_sample_offset
= ctts
&& ((file
->max_isom_version
>= 4 && ctts
->version
== 1) || file
->qt_compatible
);
737 uint32_t sample_number_in_stts_entry
= 1;
738 uint32_t sample_number_in_ctts_entry
= 1;
739 uint32_t sample_number_in_sbgp_roll_entry
= 1;
740 uint32_t sample_number_in_sbgp_rap_entry
= 1;
742 uint32_t chunk_number
= 1;
743 uint64_t offset_from_chunk
= 0;
744 uint64_t data_offset
= stco_entry
&& stco_entry
->data
746 ? ((isom_co64_entry_t
*)stco_entry
->data
)->chunk_offset
747 : ((isom_stco_entry_t
*)stco_entry
->data
)->chunk_offset
749 uint32_t samples_per_packet
;
750 uint32_t constant_sample_size
;
751 if( is_qt_fixed_comp_audio
)
752 isom_get_qt_fixed_comp_audio_sample_quants( timeline
, description
, &samples_per_packet
, &constant_sample_size
);
755 samples_per_packet
= 1;
756 constant_sample_size
= stsz
->sample_size
;
758 uint32_t sample_number
= samples_per_packet
;
759 uint32_t sample_number_in_chunk
= samples_per_packet
;
763 isom_elst_entry_t
*edit
= (isom_elst_entry_t
*)lsmash_memdup( elst_entry
->data
, sizeof(isom_elst_entry_t
) );
765 || lsmash_add_entry( timeline
->edit_list
, edit
) )
767 elst_entry
= elst_entry
->next
;
769 /* Check what the first 2-bits of sample dependency means.
770 * This check is for chimera of ISO Base Media and QTFF. */
771 if( iso_sdtp
&& sdtp_entry
)
775 isom_sdtp_entry_t
*sdtp_data
= (isom_sdtp_entry_t
*)sdtp_entry
->data
;
778 if( sdtp_data
->is_leading
> 1 )
779 break; /* Apparently, it's defined under ISO Base Media. */
780 if( (sdtp_data
->is_leading
== 1) && (sdtp_data
->sample_depends_on
== ISOM_SAMPLE_IS_INDEPENDENT
) )
782 /* Obviously, it's not defined under ISO Base Media. */
786 sdtp_entry
= sdtp_entry
->next
;
788 sdtp_entry
= sdtp
->list
->head
;
790 /**--- Construct media timeline. ---**/
791 isom_portable_chunk_t chunk
;
792 chunk
.data_offset
= data_offset
;
794 chunk
.number
= chunk_number
;
795 chunk
.file
= (!dref_entry
|| !dref_entry
->ref_file
) ? NULL
: dref_entry
->ref_file
;
796 if( isom_add_portable_chunk_entry( timeline
, &chunk
) < 0 )
798 uint32_t distance
= NO_RANDOM_ACCESS_POINT
;
799 uint32_t last_duration
= UINT32_MAX
;
800 uint32_t packet_number
= 1;
801 isom_lpcm_bunch_t bunch
= { 0 };
802 while( sample_number
<= stsz
->sample_count
)
804 isom_sample_info_t info
= { 0 };
805 /* Get sample duration and sample offset. */
806 for( uint32_t i
= 0; i
< samples_per_packet
; i
++ )
808 /* sample duration */
811 isom_stts_entry_t
*stts_data
= (isom_stts_entry_t
*)stts_entry
->data
;
814 isom_increment_sample_number_in_entry( &sample_number_in_stts_entry
, &stts_entry
, stts_data
->sample_count
);
815 last_duration
= stts_data
->sample_delta
;
817 info
.duration
+= last_duration
;
818 dts
+= last_duration
;
820 uint32_t sample_offset
;
823 isom_ctts_entry_t
*ctts_data
= (isom_ctts_entry_t
*)ctts_entry
->data
;
826 isom_increment_sample_number_in_entry( &sample_number_in_ctts_entry
, &ctts_entry
, ctts_data
->sample_count
);
827 sample_offset
= ctts_data
->sample_offset
;
828 if( allow_negative_sample_offset
)
830 uint64_t cts
= dts
+ (int32_t)sample_offset
;
831 if( (cts
+ timeline
->ctd_shift
) < dts
)
832 timeline
->ctd_shift
= dts
- cts
;
838 info
.offset
= sample_offset
;
840 timeline
->media_duration
+= info
.duration
;
841 if( !is_qt_fixed_comp_audio
)
843 /* Check whether sync sample or not. */
846 isom_stss_entry_t
*stss_data
= (isom_stss_entry_t
*)stss_entry
->data
;
849 if( sample_number
== stss_data
->sample_number
)
851 info
.prop
.ra_flags
|= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC
;
852 stss_entry
= stss_entry
->next
;
857 /* Don't reset distance as 0 since MDCT-based audio frames need pre-roll for correct presentation
858 * though all of them could be marked as a sync sample. */
859 info
.prop
.ra_flags
|= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC
;
860 /* Check whether partial sync sample or not. */
863 isom_stps_entry_t
*stps_data
= (isom_stps_entry_t
*)stps_entry
->data
;
866 if( sample_number
== stps_data
->sample_number
)
868 info
.prop
.ra_flags
|= QT_SAMPLE_RANDOM_ACCESS_FLAG_PARTIAL_SYNC
| QT_SAMPLE_RANDOM_ACCESS_FLAG_RAP
;
869 stps_entry
= stps_entry
->next
;
873 /* Get sample dependency info. */
876 isom_sdtp_entry_t
*sdtp_data
= (isom_sdtp_entry_t
*)sdtp_entry
->data
;
880 info
.prop
.leading
= sdtp_data
->is_leading
;
882 info
.prop
.allow_earlier
= sdtp_data
->is_leading
;
883 info
.prop
.independent
= sdtp_data
->sample_depends_on
;
884 info
.prop
.disposable
= sdtp_data
->sample_is_depended_on
;
885 info
.prop
.redundant
= sdtp_data
->sample_has_redundancy
;
886 sdtp_entry
= sdtp_entry
->next
;
888 /* Get roll recovery grouping info. */
890 && isom_get_roll_recovery_grouping_info( timeline
,
891 &sbgp_roll_entry
, sgpd_roll
, NULL
,
892 &sample_number_in_sbgp_roll_entry
,
893 &info
, sample_number
) < 0 )
895 info
.prop
.post_roll
.identifier
= sample_number
;
896 /* Get random access point grouping info. */
898 && isom_get_random_access_point_grouping_info( timeline
,
899 &sbgp_rap_entry
, sgpd_rap
, NULL
,
900 &sample_number_in_sbgp_rap_entry
,
901 &info
, &distance
) < 0 )
903 /* Set up distance from the previous random access point. */
904 if( distance
!= NO_RANDOM_ACCESS_POINT
)
906 if( info
.prop
.pre_roll
.distance
== 0 )
907 info
.prop
.pre_roll
.distance
= distance
;
912 /* All uncompressed and non-variable compressed audio frame is a sync sample. */
913 info
.prop
.ra_flags
= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC
;
914 /* Get size of sample in the stream. */
915 if( is_qt_fixed_comp_audio
|| !stsz_entry
)
916 info
.length
= constant_sample_size
;
919 if( !stsz_entry
->data
)
921 info
.length
= ((isom_stsz_entry_t
*)stsz_entry
->data
)->entry_size
;
922 stsz_entry
= stsz_entry
->next
;
924 timeline
->max_sample_size
= LSMASH_MAX( timeline
->max_sample_size
, info
.length
);
925 /* Get chunk info. */
926 info
.pos
= data_offset
;
927 info
.index
= stsc_data
->sample_description_index
;
928 info
.chunk
= (isom_portable_chunk_t
*)timeline
->chunk_list
->tail
->data
;
929 offset_from_chunk
+= info
.length
;
930 if( sample_number_in_chunk
== stsc_data
->samples_per_chunk
)
932 /* Set the length of the last chunk. */
934 info
.chunk
->length
= offset_from_chunk
;
935 /* Move the next chunk. */
937 stco_entry
= stco_entry
->next
;
939 && stco_entry
->data
)
940 data_offset
= large_presentation
941 ? ((isom_co64_entry_t
*)stco_entry
->data
)->chunk_offset
942 : ((isom_stco_entry_t
*)stco_entry
->data
)->chunk_offset
;
943 chunk
.data_offset
= data_offset
;
945 chunk
.number
= ++chunk_number
;
946 offset_from_chunk
= 0;
947 /* Check if the next entry is broken. */
948 while( next_stsc_entry
&& chunk_number
> ((isom_stsc_entry_t
*)next_stsc_entry
->data
)->first_chunk
)
950 /* Just skip broken next entry. */
951 lsmash_log( timeline
, LSMASH_LOG_WARNING
, "ignore broken entry in Sample To Chunk Box.\n" );
952 lsmash_log( timeline
, LSMASH_LOG_WARNING
, "timeline might be corrupted.\n" );
953 next_stsc_entry
= next_stsc_entry
->next
;
955 && !next_stsc_entry
->data
)
958 /* Check if the next chunk belongs to the next sequence of chunks. */
959 if( next_stsc_entry
&& chunk_number
== ((isom_stsc_entry_t
*)next_stsc_entry
->data
)->first_chunk
)
961 stsc_entry
= next_stsc_entry
;
962 next_stsc_entry
= next_stsc_entry
->next
;
964 && !next_stsc_entry
->data
)
966 stsc_data
= (isom_stsc_entry_t
*)stsc_entry
->data
;
967 /* Update sample description. */
968 description
= (isom_sample_entry_t
*)lsmash_get_entry_data( &stsd
->list
, stsc_data
->sample_description_index
);
969 is_lpcm_audio
= isom_is_lpcm_audio( description
);
970 is_qt_fixed_comp_audio
= isom_is_qt_fixed_compressed_audio( description
);
971 if( is_qt_fixed_comp_audio
)
972 isom_get_qt_fixed_comp_audio_sample_quants( timeline
, description
, &samples_per_packet
, &constant_sample_size
);
975 samples_per_packet
= 1;
976 constant_sample_size
= stsz
->sample_size
;
978 /* Reference media data. */
979 dref_entry
= (isom_dref_entry_t
*)lsmash_get_entry_data( &dref
->list
, description
->data_reference_index
);
980 chunk
.file
= (!dref_entry
|| !dref_entry
->ref_file
) ? NULL
: dref_entry
->ref_file
;
982 sample_number_in_chunk
= samples_per_packet
;
983 if( isom_add_portable_chunk_entry( timeline
, &chunk
) < 0 )
988 data_offset
+= info
.length
;
989 sample_number_in_chunk
+= samples_per_packet
;
991 /* OK. Let's add its info. */
994 if( sample_number
== samples_per_packet
)
995 isom_update_bunch( &bunch
, &info
);
996 else if( isom_compare_lpcm_sample_info( &bunch
, &info
) )
998 if( isom_add_lpcm_bunch_entry( timeline
, &bunch
) )
1000 isom_update_bunch( &bunch
, &info
);
1003 ++ bunch
.sample_count
;
1005 else if( isom_add_sample_info_entry( timeline
, &info
) )
1007 if( timeline
->info_list
->entry_count
&& timeline
->bunch_list
->entry_count
)
1009 lsmash_log( timeline
, LSMASH_LOG_ERROR
, "LPCM + non-LPCM track is not supported.\n" );
1012 sample_number
+= samples_per_packet
;
1015 isom_portable_chunk_t
*last_chunk
= lsmash_get_entry_data( timeline
->chunk_list
, timeline
->chunk_list
->entry_count
);
1018 if( offset_from_chunk
)
1019 last_chunk
->length
= offset_from_chunk
;
1022 /* Remove the last invalid chunk. */
1023 lsmash_remove_entry( timeline
->chunk_list
, timeline
->chunk_list
->entry_count
, NULL
);
1027 uint32_t sample_count
= packet_number
- 1;
1028 if( movie_framemts_present
)
1030 isom_tfra_t
*tfra
= isom_get_tfra( file
->mfra
, track_ID
);
1031 lsmash_entry_t
*tfra_entry
= tfra
&& tfra
->list
? tfra
->list
->head
: NULL
;
1032 isom_tfra_location_time_entry_t
*rap
= tfra_entry
? (isom_tfra_location_time_entry_t
*)tfra_entry
->data
: NULL
;
1033 chunk
.data_offset
= 0;
1035 /* Movie fragments */
1036 for( lsmash_entry_t
*moof_entry
= file
->moof_list
.head
; moof_entry
; moof_entry
= moof_entry
->next
)
1038 isom_moof_t
*moof
= (isom_moof_t
*)moof_entry
->data
;
1041 uint64_t last_sample_end_pos
= 0;
1042 /* Track fragments */
1043 uint32_t traf_number
= 1;
1044 for( lsmash_entry_t
*traf_entry
= moof
->traf_list
.head
; traf_entry
; traf_entry
= traf_entry
->next
)
1046 isom_traf_t
*traf
= (isom_traf_t
*)traf_entry
->data
;
1049 isom_tfhd_t
*tfhd
= traf
->tfhd
;
1052 isom_trex_t
*trex
= isom_get_trex( file
->moov
->mvex
, tfhd
->track_ID
);
1055 /* Ignore ISOM_TF_FLAGS_DURATION_IS_EMPTY flag even if set. */
1056 if( !traf
->trun_list
.head
)
1061 /* Get base_data_offset. */
1062 uint64_t base_data_offset
;
1063 if( tfhd
->flags
& ISOM_TF_FLAGS_BASE_DATA_OFFSET_PRESENT
)
1064 base_data_offset
= tfhd
->base_data_offset
;
1065 else if( (tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_BASE_IS_MOOF
) || traf_entry
== moof
->traf_list
.head
)
1066 base_data_offset
= moof
->pos
;
1068 base_data_offset
= last_sample_end_pos
;
1069 /* sample grouping */
1070 isom_sgpd_t
*sgpd_frag_rap
;
1071 isom_sgpd_t
*sgpd_frag_roll
;
1072 sgpd_frag_rap
= isom_get_fragment_sample_group_description( traf
, ISOM_GROUP_TYPE_RAP
);
1073 sbgp_rap
= isom_get_fragment_sample_to_group ( traf
, ISOM_GROUP_TYPE_RAP
);
1074 sbgp_rap_entry
= sbgp_rap
&& sbgp_rap
->list
? sbgp_rap
->list
->head
: NULL
;
1075 sgpd_frag_roll
= isom_get_roll_recovery_sample_group_description( &traf
->sgpd_list
);
1076 sbgp_roll
= isom_get_roll_recovery_sample_to_group ( &traf
->sbgp_list
);
1077 sbgp_roll_entry
= sbgp_roll
&& sbgp_roll
->list
? sbgp_roll
->list
->head
: NULL
;
1078 int need_data_offset_only
= (tfhd
->track_ID
!= track_ID
);
1080 uint32_t trun_number
= 1;
1081 for( lsmash_entry_t
*trun_entry
= traf
->trun_list
.head
; trun_entry
; trun_entry
= trun_entry
->next
)
1083 isom_trun_t
*trun
= (isom_trun_t
*)trun_entry
->data
;
1086 if( trun
->sample_count
== 0 )
1091 /* Get data_offset. */
1092 if( trun
->flags
& ISOM_TR_FLAGS_DATA_OFFSET_PRESENT
)
1093 data_offset
= trun
->data_offset
+ base_data_offset
;
1094 else if( trun_entry
== traf
->trun_list
.head
)
1095 data_offset
= base_data_offset
;
1097 data_offset
= last_sample_end_pos
;
1099 uint32_t sample_description_index
= 0;
1100 isom_sdtp_entry_t
*sdtp_data
= NULL
;
1101 if( !need_data_offset_only
)
1103 /* Get sample_description_index of this track fragment. */
1104 if( tfhd
->flags
& ISOM_TF_FLAGS_SAMPLE_DESCRIPTION_INDEX_PRESENT
)
1105 sample_description_index
= tfhd
->sample_description_index
;
1107 sample_description_index
= trex
->default_sample_description_index
;
1108 description
= (isom_sample_entry_t
*)lsmash_get_entry_data( &stsd
->list
, sample_description_index
);
1109 is_lpcm_audio
= isom_is_lpcm_audio( description
);
1110 /* Reference media data. */
1111 dref_entry
= (isom_dref_entry_t
*)lsmash_get_entry_data( &dref
->list
, description
->data_reference_index
);
1112 lsmash_file_t
*ref_file
= (!dref_entry
|| !dref_entry
->ref_file
) ? NULL
: dref_entry
->ref_file
;
1113 /* Each track run can be considered as a chunk.
1114 * Here, we consider physically consecutive track runs as one chunk. */
1115 if( chunk
.data_offset
+ chunk
.length
!= data_offset
|| chunk
.file
!= ref_file
)
1117 chunk
.data_offset
= data_offset
;
1119 chunk
.number
= ++chunk_number
;
1120 chunk
.file
= ref_file
;
1121 if( isom_add_portable_chunk_entry( timeline
, &chunk
) < 0 )
1124 /* Get dependency info for this track fragment. */
1125 sdtp_entry
= traf
->sdtp
&& traf
->sdtp
->list
? traf
->sdtp
->list
->head
: NULL
;
1126 sdtp_data
= sdtp_entry
&& sdtp_entry
->data
? (isom_sdtp_entry_t
*)sdtp_entry
->data
: NULL
;
1128 /* Get info of each sample. */
1129 lsmash_entry_t
*row_entry
= trun
->optional
&& trun
->optional
->head
? trun
->optional
->head
: NULL
;
1131 while( sample_number
<= trun
->sample_count
)
1133 isom_sample_info_t info
= { 0 };
1134 isom_trun_optional_row_t
*row
= row_entry
&& row_entry
->data
? (isom_trun_optional_row_t
*)row_entry
->data
: NULL
;
1135 /* Get sample_size */
1136 if( row
&& (trun
->flags
& ISOM_TR_FLAGS_SAMPLE_SIZE_PRESENT
) )
1137 info
.length
= row
->sample_size
;
1138 else if( tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_SAMPLE_SIZE_PRESENT
)
1139 info
.length
= tfhd
->default_sample_size
;
1141 info
.length
= trex
->default_sample_size
;
1142 if( !need_data_offset_only
)
1144 info
.pos
= data_offset
;
1145 info
.index
= sample_description_index
;
1146 info
.chunk
= (isom_portable_chunk_t
*)timeline
->chunk_list
->tail
->data
;
1147 info
.chunk
->length
+= info
.length
;
1148 /* Get sample_duration. */
1149 if( row
&& (trun
->flags
& ISOM_TR_FLAGS_SAMPLE_DURATION_PRESENT
) )
1150 info
.duration
= row
->sample_duration
;
1151 else if( tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT
)
1152 info
.duration
= tfhd
->default_sample_duration
;
1154 info
.duration
= trex
->default_sample_duration
;
1155 /* Get composition time offset. */
1156 if( row
&& (trun
->flags
& ISOM_TR_FLAGS_SAMPLE_COMPOSITION_TIME_OFFSET_PRESENT
) )
1158 info
.offset
= row
->sample_composition_time_offset
;
1159 /* Check composition to decode timeline shift. */
1160 if( file
->max_isom_version
>= 6 && trun
->version
!= 0 )
1162 uint64_t cts
= dts
+ (int32_t)info
.offset
;
1163 if( (cts
+ timeline
->ctd_shift
) < dts
)
1164 timeline
->ctd_shift
= dts
- cts
;
1169 dts
+= info
.duration
;
1170 /* Update media duration and maximun sample size. */
1171 timeline
->media_duration
+= info
.duration
;
1172 timeline
->max_sample_size
= LSMASH_MAX( timeline
->max_sample_size
, info
.length
);
1173 if( !is_lpcm_audio
)
1175 /* Get sample_flags. */
1176 isom_sample_flags_t sample_flags
;
1177 if( sample_number
== 1 && (trun
->flags
& ISOM_TR_FLAGS_FIRST_SAMPLE_FLAGS_PRESENT
) )
1178 sample_flags
= trun
->first_sample_flags
;
1179 else if( row
&& (trun
->flags
& ISOM_TR_FLAGS_SAMPLE_FLAGS_PRESENT
) )
1180 sample_flags
= row
->sample_flags
;
1181 else if( tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_SAMPLE_FLAGS_PRESENT
)
1182 sample_flags
= tfhd
->default_sample_flags
;
1184 sample_flags
= trex
->default_sample_flags
;
1187 /* Independent and Disposable Samples Box overrides the information from sample_flags.
1188 * There is no description in the specification about this, but the intention should be such a thing.
1189 * The ground is that sample_flags is placed in media layer
1190 * while Independent and Disposable Samples Box is placed in track or presentation layer. */
1191 info
.prop
.leading
= sdtp_data
->is_leading
;
1192 info
.prop
.independent
= sdtp_data
->sample_depends_on
;
1193 info
.prop
.disposable
= sdtp_data
->sample_is_depended_on
;
1194 info
.prop
.redundant
= sdtp_data
->sample_has_redundancy
;
1196 sdtp_entry
= sdtp_entry
->next
;
1197 sdtp_data
= sdtp_entry
? (isom_sdtp_entry_t
*)sdtp_entry
->data
: NULL
;
1201 info
.prop
.leading
= sample_flags
.is_leading
;
1202 info
.prop
.independent
= sample_flags
.sample_depends_on
;
1203 info
.prop
.disposable
= sample_flags
.sample_is_depended_on
;
1204 info
.prop
.redundant
= sample_flags
.sample_has_redundancy
;
1206 /* Check this sample is a sync sample or not.
1207 * Note: all sync sample shall be independent. */
1208 if( !sample_flags
.sample_is_non_sync_sample
1209 && info
.prop
.independent
!= ISOM_SAMPLE_IS_NOT_INDEPENDENT
)
1211 info
.prop
.ra_flags
|= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC
;
1214 /* Get roll recovery grouping info. */
1215 uint32_t roll_id
= sample_count
+ sample_number
;
1217 && isom_get_roll_recovery_grouping_info( timeline
,
1218 &sbgp_roll_entry
, sgpd_roll
, sgpd_frag_roll
,
1219 &sample_number_in_sbgp_roll_entry
,
1220 &info
, roll_id
) < 0 )
1222 info
.prop
.post_roll
.identifier
= roll_id
;
1223 /* Get random access point grouping info. */
1225 && isom_get_random_access_point_grouping_info( timeline
,
1226 &sbgp_rap_entry
, sgpd_rap
, sgpd_frag_rap
,
1227 &sample_number_in_sbgp_rap_entry
,
1228 &info
, &distance
) < 0 )
1230 /* Get the location of the sync sample from 'tfra' if it is not set up yet.
1231 * Note: there is no guarantee that its entries are placed in a specific order. */
1234 if( tfra
->number_of_entry
== 0
1235 && info
.prop
.ra_flags
== ISOM_SAMPLE_RANDOM_ACCESS_FLAG_NONE
)
1236 info
.prop
.ra_flags
|= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC
;
1238 && rap
->moof_offset
== moof
->pos
1239 && rap
->traf_number
== traf_number
1240 && rap
->trun_number
== trun_number
1241 && rap
->sample_number
== sample_number
)
1243 if( info
.prop
.ra_flags
== ISOM_SAMPLE_RANDOM_ACCESS_FLAG_NONE
)
1244 info
.prop
.ra_flags
|= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC
;
1246 tfra_entry
= tfra_entry
->next
;
1247 rap
= tfra_entry
? (isom_tfra_location_time_entry_t
*)tfra_entry
->data
: NULL
;
1250 /* Set up distance from the previous random access point. */
1251 if( distance
!= NO_RANDOM_ACCESS_POINT
)
1253 if( info
.prop
.pre_roll
.distance
== 0 )
1254 info
.prop
.pre_roll
.distance
= distance
;
1257 /* OK. Let's add its info. */
1258 if( isom_add_sample_info_entry( timeline
, &info
) )
1263 /* All LPCMFrame is a sync sample. */
1264 info
.prop
.ra_flags
= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC
;
1265 /* OK. Let's add its info. */
1266 if( sample_count
== 0 && sample_number
== 1 )
1267 isom_update_bunch( &bunch
, &info
);
1268 else if( isom_compare_lpcm_sample_info( &bunch
, &info
) )
1270 if( isom_add_lpcm_bunch_entry( timeline
, &bunch
) )
1272 isom_update_bunch( &bunch
, &info
);
1275 ++ bunch
.sample_count
;
1277 if( timeline
-> info_list
->entry_count
1278 && timeline
->bunch_list
->entry_count
)
1280 lsmash_log( timeline
, LSMASH_LOG_ERROR
, "LPCM + non-LPCM track is not supported.\n" );
1284 data_offset
+= info
.length
;
1285 last_sample_end_pos
= data_offset
;
1287 row_entry
= row_entry
->next
;
1290 if( !need_data_offset_only
)
1291 sample_count
+= sample_number
- 1;
1295 } /* Track fragments */
1296 } /* Movie fragments */
1298 else if( timeline
->chunk_list
->entry_count
== 0 )
1299 goto fail
; /* No samples in this track. */
1300 if( bunch
.sample_count
&& isom_add_lpcm_bunch_entry( timeline
, &bunch
) )
1302 if( lsmash_add_entry( file
->timeline
, timeline
) )
1304 /* Finish timeline construction. */
1305 timeline
->sample_count
= sample_count
;
1306 if( timeline
->info_list
->entry_count
)
1308 timeline
->get_dts
= isom_get_dts_from_info_list
;
1309 timeline
->get_cts
= isom_get_cts_from_info_list
;
1310 timeline
->get_sample_duration
= isom_get_sample_duration_from_info_list
;
1311 timeline
->check_sample_existence
= isom_check_sample_existence_in_info_list
;
1312 timeline
->get_sample
= isom_get_sample_from_media_timeline
;
1313 timeline
->get_sample_info
= isom_get_sample_info_from_media_timeline
;
1314 timeline
->get_sample_property
= isom_get_sample_property_from_media_timeline
;
1318 timeline
->get_dts
= isom_get_dts_from_bunch_list
;
1319 timeline
->get_cts
= isom_get_cts_from_bunch_list
;
1320 timeline
->get_sample_duration
= isom_get_sample_duration_from_bunch_list
;
1321 timeline
->check_sample_existence
= isom_check_sample_existence_in_bunch_list
;
1322 timeline
->get_sample
= isom_get_lpcm_sample_from_media_timeline
;
1323 timeline
->get_sample_info
= isom_get_lpcm_sample_info_from_media_timeline
;
1324 timeline
->get_sample_property
= isom_get_lpcm_sample_property_from_media_timeline
;
1328 isom_destruct_timeline_direct( timeline
);
1332 int lsmash_get_dts_from_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t sample_number
, uint64_t *dts
)
1334 if( !sample_number
|| !dts
)
1336 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1337 if( !timeline
|| sample_number
> timeline
->sample_count
)
1339 return timeline
->get_dts( timeline
, sample_number
, dts
);
1342 int lsmash_get_cts_from_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t sample_number
, uint64_t *cts
)
1344 if( !sample_number
|| !cts
)
1346 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1347 if( !timeline
|| sample_number
> timeline
->sample_count
)
1349 return timeline
->get_cts( timeline
, sample_number
, cts
);
1352 lsmash_sample_t
*lsmash_get_sample_from_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t sample_number
)
1354 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1355 return timeline
? timeline
->get_sample( timeline
, sample_number
) : NULL
;
1358 int lsmash_get_sample_info_from_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t sample_number
, lsmash_sample_t
*sample
)
1362 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1363 return timeline
? timeline
->get_sample_info( timeline
, sample_number
, sample
) : -1;
1366 int lsmash_get_sample_property_from_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t sample_number
, lsmash_sample_property_t
*prop
)
1370 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1371 return timeline
? timeline
->get_sample_property( timeline
, sample_number
, prop
) : -1;
1374 int lsmash_get_composition_to_decode_shift_from_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t *ctd_shift
)
1378 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1381 *ctd_shift
= timeline
->ctd_shift
;
1385 static inline int isom_get_closest_past_random_accessible_point_from_media_timeline( isom_timeline_t
*timeline
, uint32_t sample_number
, uint32_t *rap_number
)
1387 lsmash_entry_t
*entry
= lsmash_get_entry( timeline
->info_list
, sample_number
-- );
1391 isom_sample_info_t
*info
= (isom_sample_info_t
*)entry
->data
;
1392 while( info
->prop
.ra_flags
== ISOM_SAMPLE_RANDOM_ACCESS_FLAG_NONE
)
1394 entry
= entry
->prev
;
1398 info
= (isom_sample_info_t
*)entry
->data
;
1401 *rap_number
= sample_number
+ 1;
1405 static inline int isom_get_closest_future_random_accessible_point_from_media_timeline( isom_timeline_t
*timeline
, uint32_t sample_number
, uint32_t *rap_number
)
1407 lsmash_entry_t
*entry
= lsmash_get_entry( timeline
->info_list
, sample_number
++ );
1411 isom_sample_info_t
*info
= (isom_sample_info_t
*)entry
->data
;
1412 while( info
->prop
.ra_flags
== ISOM_SAMPLE_RANDOM_ACCESS_FLAG_NONE
)
1414 entry
= entry
->next
;
1418 info
= (isom_sample_info_t
*)entry
->data
;
1421 *rap_number
= sample_number
- 1;
1425 static int isom_get_closest_random_accessible_point_from_media_timeline_internal( isom_timeline_t
*timeline
, uint32_t sample_number
, uint32_t *rap_number
)
1429 if( isom_get_closest_past_random_accessible_point_from_media_timeline( timeline
, sample_number
, rap_number
)
1430 && isom_get_closest_future_random_accessible_point_from_media_timeline( timeline
, sample_number
+ 1, rap_number
) )
1435 int lsmash_get_closest_random_accessible_point_from_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t sample_number
, uint32_t *rap_number
)
1437 if( sample_number
== 0 || !rap_number
)
1439 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1440 if( timeline
->info_list
->entry_count
== 0 )
1442 *rap_number
= sample_number
; /* All LPCM is sync sample. */
1445 return isom_get_closest_random_accessible_point_from_media_timeline_internal( timeline
, sample_number
, rap_number
);
1448 int lsmash_get_closest_random_accessible_point_detail_from_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t sample_number
,
1449 uint32_t *rap_number
, lsmash_random_access_flag
*ra_flags
, uint32_t *leading
, uint32_t *distance
)
1451 if( sample_number
== 0 )
1453 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1454 if( timeline
->info_list
->entry_count
== 0 )
1456 /* All LPCM is sync sample. */
1457 *rap_number
= sample_number
;
1459 *ra_flags
= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC
;
1466 if( isom_get_closest_random_accessible_point_from_media_timeline_internal( timeline
, sample_number
, rap_number
) )
1468 isom_sample_info_t
*info
= (isom_sample_info_t
*)lsmash_get_entry_data( timeline
->info_list
, *rap_number
);
1472 *ra_flags
= info
->prop
.ra_flags
;
1477 if( sample_number
< *rap_number
)
1478 /* Impossible to desire to decode the sample of given number correctly. */
1480 else if( !(info
->prop
.ra_flags
& ISOM_SAMPLE_RANDOM_ACCESS_FLAG_GDR
) )
1484 /* Count leading samples. */
1485 uint32_t current_sample_number
= *rap_number
+ 1;
1487 if( isom_get_dts_from_info_list( timeline
, *rap_number
, &dts
) )
1489 uint64_t rap_cts
= timeline
->ctd_shift
? (dts
+ (int32_t)info
->offset
+ timeline
->ctd_shift
) : (dts
+ info
->offset
);
1492 dts
+= info
->duration
;
1493 if( rap_cts
<= dts
)
1494 break; /* leading samples of this random accessible point must not be present more. */
1495 info
= (isom_sample_info_t
*)lsmash_get_entry_data( timeline
->info_list
, current_sample_number
++ );
1498 uint64_t cts
= timeline
->ctd_shift
? (dts
+ (int32_t)info
->offset
+ timeline
->ctd_shift
) : (dts
+ info
->offset
);
1503 if( !distance
|| sample_number
== *rap_number
)
1505 /* Measure distance from the first closest non-recovery random accessible point to the second. */
1506 uint32_t prev_rap_number
= *rap_number
;
1509 if( isom_get_closest_past_random_accessible_point_from_media_timeline( timeline
, prev_rap_number
- 1, &prev_rap_number
) )
1510 /* The previous random accessible point is not present. */
1512 info
= (isom_sample_info_t
*)lsmash_get_entry_data( timeline
->info_list
, prev_rap_number
);
1515 if( !(info
->prop
.ra_flags
& ISOM_SAMPLE_RANDOM_ACCESS_FLAG_GDR
) )
1517 /* Decode shall already complete at the first closest non-recovery random accessible point if starting to decode from the second. */
1518 *distance
= *rap_number
- prev_rap_number
;
1525 /* Calculate roll-distance. */
1526 if( info
->prop
.pre_roll
.distance
)
1528 /* Pre-roll recovery */
1529 uint32_t prev_rap_number
= *rap_number
;
1532 if( isom_get_closest_past_random_accessible_point_from_media_timeline( timeline
, prev_rap_number
- 1, &prev_rap_number
)
1533 && *rap_number
< info
->prop
.pre_roll
.distance
)
1535 /* The previous random accessible point is not present.
1536 * And sample of given number might be not able to decoded correctly. */
1540 if( prev_rap_number
+ info
->prop
.pre_roll
.distance
<= *rap_number
)
1543 * |<---- pre-roll distance ---->|
1544 * |<--------- distance -------->|
1545 * media +++++++++++++++++++++++++ *** +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1547 * random accessible point starting point random accessible point given sample
1550 *distance
= info
->prop
.pre_roll
.distance
;
1553 else if( !(info
->prop
.ra_flags
& ISOM_SAMPLE_RANDOM_ACCESS_FLAG_GDR
) )
1556 * |<------------ pre-roll distance ------------------>|
1557 * |<------ distance ------->|
1558 * media ++++++++++++++++ *** ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1560 * random accessible point random accessible point given sample
1561 * (starting point) (complete)
1563 *distance
= *rap_number
- prev_rap_number
;
1568 /* Post-roll recovery */
1569 if( sample_number
>= info
->prop
.post_roll
.complete
)
1571 * |<----- post-roll distance ----->|
1573 * media +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1575 * random accessible point complete given sample
1579 uint32_t prev_rap_number
= *rap_number
;
1582 if( isom_get_closest_past_random_accessible_point_from_media_timeline( timeline
, prev_rap_number
- 1, &prev_rap_number
) )
1583 /* The previous random accessible point is not present. */
1585 info
= (isom_sample_info_t
*)lsmash_get_entry_data( timeline
->info_list
, prev_rap_number
);
1588 if( !(info
->prop
.ra_flags
& ISOM_SAMPLE_RANDOM_ACCESS_FLAG_GDR
) || sample_number
>= info
->prop
.post_roll
.complete
)
1590 *distance
= *rap_number
- prev_rap_number
;
1596 int lsmash_check_sample_existence_in_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t sample_number
)
1598 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1599 return timeline
? timeline
->check_sample_existence( timeline
, sample_number
) : 0;
1602 int lsmash_get_last_sample_delta_from_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t *last_sample_delta
)
1604 if( !last_sample_delta
)
1606 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1607 return timeline
? timeline
->get_sample_duration( timeline
, timeline
->sample_count
, last_sample_delta
) : -1;
1610 int lsmash_get_sample_delta_from_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t sample_number
, uint32_t *sample_delta
)
1614 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1615 return timeline
? timeline
->get_sample_duration( timeline
, sample_number
, sample_delta
) : -1;
1618 uint32_t lsmash_get_sample_count_in_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
)
1620 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1623 return timeline
->sample_count
;
1626 uint32_t lsmash_get_max_sample_size_in_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
)
1628 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1631 return timeline
->max_sample_size
;
1634 uint64_t lsmash_get_media_duration_from_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
)
1636 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1639 return timeline
->media_duration
;
1642 int lsmash_copy_timeline_map( lsmash_root_t
*dst
, uint32_t dst_track_ID
, lsmash_root_t
*src
, uint32_t src_track_ID
)
1646 lsmash_file_t
*dst_file
= dst
->file
;
1647 isom_trak_t
*dst_trak
= isom_get_trak( dst_file
, dst_track_ID
);
1649 || !dst_file
->moov
->mvhd
1650 || dst_file
->moov
->mvhd
->timescale
== 0
1653 || !dst_trak
->mdia
->mdhd
1654 || dst_trak
->mdia
->mdhd
->timescale
== 0
1655 || !dst_trak
->mdia
->minf
1656 || !dst_trak
->mdia
->minf
->stbl
)
1659 && dst_trak
->edts
->elst
)
1660 lsmash_remove_entries( dst_trak
->edts
->elst
->list
, NULL
);
1661 uint32_t src_movie_timescale
;
1662 uint32_t src_media_timescale
;
1663 uint64_t src_track_duration
;
1664 uint64_t src_media_duration
;
1665 int32_t src_ctd_shift
; /* Add timeline shift difference between src and dst to each media_time.
1666 * Therefore, call this function as later as possible. */
1667 lsmash_entry_t
*src_entry
;
1668 lsmash_file_t
*src_file
= src
->file
;
1669 isom_trak_t
*src_trak
= isom_get_trak( src_file
, src_track_ID
);
1672 || !src_trak
->edts
->elst
1673 || !src_trak
->edts
->elst
->list
)
1675 /* Get from timeline instead of boxes. */
1676 isom_timeline_t
*src_timeline
= isom_get_timeline( src
, src_track_ID
);
1678 || src_timeline
->movie_timescale
== 0
1679 || src_timeline
->media_timescale
== 0
1680 || !src_timeline
->edit_list
)
1682 src_movie_timescale
= src_timeline
->movie_timescale
;
1683 src_media_timescale
= src_timeline
->media_timescale
;
1684 src_track_duration
= src_timeline
->track_duration
;
1685 src_media_duration
= src_timeline
->media_duration
;
1686 src_ctd_shift
= src_timeline
->ctd_shift
;
1687 src_entry
= src_timeline
->edit_list
->head
;
1692 || !src_file
->moov
->mvhd
1693 || src_file
->moov
->mvhd
->timescale
== 0
1696 || !src_trak
->mdia
->mdhd
1697 || src_trak
->mdia
->mdhd
->timescale
== 0
1698 || !src_trak
->mdia
->minf
1699 || !src_trak
->mdia
->minf
->stbl
)
1701 src_movie_timescale
= src_file
->moov
->mvhd
->timescale
;
1702 src_media_timescale
= src_trak
->mdia
->mdhd
->timescale
;
1703 src_track_duration
= src_trak
->tkhd
->duration
;
1704 src_media_duration
= src_trak
->mdia
->mdhd
->duration
;
1705 src_ctd_shift
= src_trak
->mdia
->minf
->stbl
->cslg
? src_trak
->mdia
->minf
->stbl
->cslg
->compositionToDTSShift
: 0;
1706 src_entry
= src_trak
->edts
->elst
->list
->head
;
1710 /* Generate edit list if absent in destination. */
1711 if( (!dst_trak
->edts
&& !isom_add_edts( dst_trak
))
1712 || (!dst_trak
->edts
->elst
&& !isom_add_elst( dst_trak
->edts
)) )
1714 uint32_t dst_movie_timescale
= dst_file
->moov
->mvhd
->timescale
;
1715 uint32_t dst_media_timescale
= dst_trak
->mdia
->mdhd
->timescale
;
1716 int32_t dst_ctd_shift
= dst_trak
->mdia
->minf
->stbl
->cslg
? dst_trak
->mdia
->minf
->stbl
->cslg
->compositionToDTSShift
: 0;
1717 int32_t media_time_shift
= src_ctd_shift
- dst_ctd_shift
;
1718 lsmash_entry_list_t
*dst_list
= dst_trak
->edts
->elst
->list
;
1719 lsmash_entry_t
*src_head
= src_entry
;
1722 isom_elst_entry_t
*src_data
= (isom_elst_entry_t
*)src_entry
->data
;
1725 uint64_t segment_duration
;
1726 if( src_data
->segment_duration
== 0 && !dst_file
->fragment
)
1728 /* The 0-duration edit makes no sence for non-fragmented movie file. */
1729 if( src_entry
== src_head
)
1730 /* Set an appropriate duration from the source track. */
1731 segment_duration
= src_track_duration
1732 ? src_track_duration
1733 : src_media_duration
* ((double)src_movie_timescale
/ src_media_timescale
);
1735 /* Two or more 0-duration edits make no sence. Just skip them. */
1739 segment_duration
= src_data
->segment_duration
;
1740 isom_elst_entry_t
*dst_data
= (isom_elst_entry_t
*)lsmash_malloc( sizeof(isom_elst_entry_t
) );
1743 dst_data
->segment_duration
= segment_duration
* ((double)dst_movie_timescale
/ src_movie_timescale
) + 0.5;
1744 dst_data
->media_rate
= src_data
->media_rate
;
1745 if( src_data
->media_time
!= ISOM_EDIT_MODE_EMPTY
)
1746 dst_data
->media_time
= (src_data
->media_time
+ media_time_shift
) * ((double)dst_media_timescale
/ src_media_timescale
) + 0.5;
1748 dst_data
->media_time
= ISOM_EDIT_MODE_EMPTY
;
1749 if( lsmash_add_entry( dst_list
, dst_data
) < 0 )
1751 lsmash_free( dst_data
);
1754 src_entry
= src_entry
->next
;
1759 int lsmash_set_media_timestamps( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_media_ts_list_t
*ts_list
)
1761 if( !root
|| !root
->file
|| !ts_list
)
1763 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1766 if( timeline
->info_list
->entry_count
== 0 )
1768 lsmash_log( timeline
, LSMASH_LOG_ERROR
, "Changing timestamps of LPCM track is not supported.\n" );
1771 if( ts_list
->sample_count
!= timeline
->info_list
->entry_count
)
1772 return -1; /* Number of samples must be same. */
1773 lsmash_media_ts_t
*ts
= ts_list
->timestamp
;
1775 return -1; /* DTS must start from value zero. */
1777 uint32_t sample_count
= ts_list
->sample_count
;
1779 if( timeline
->info_list
->entry_count
> 1 )
1782 lsmash_entry_t
*entry
= timeline
->info_list
->head
;
1783 isom_sample_info_t
*info
;
1784 while( i
< sample_count
)
1786 info
= (isom_sample_info_t
*)entry
->data
;
1787 if( !info
|| (ts
[i
].dts
< ts
[i
- 1].dts
) )
1789 info
->duration
= ts
[i
].dts
- ts
[i
- 1].dts
;
1790 entry
= entry
->next
;
1798 /* Copy the previous duration. */
1799 ((isom_sample_info_t
*)entry
->data
)->duration
= info
->duration
;
1802 return -1; /* Irregular case: sample_count this timeline has is incorrect. */
1804 else /* still image */
1805 ((isom_sample_info_t
*)timeline
->info_list
->head
->data
)->duration
= UINT32_MAX
;
1807 * ToDo: hint track must not have any sample_offset. */
1809 timeline
->ctd_shift
= 0;
1810 for( lsmash_entry_t
*entry
= timeline
->info_list
->head
; entry
; entry
= entry
->next
)
1812 isom_sample_info_t
*info
= (isom_sample_info_t
*)entry
->data
;
1813 if( (ts
[i
].cts
+ timeline
->ctd_shift
) < ts
[i
].dts
)
1814 timeline
->ctd_shift
= ts
[i
].dts
- ts
[i
].cts
;
1815 info
->offset
= ts
[i
].cts
- ts
[i
].dts
;
1818 if( timeline
->ctd_shift
&& (!root
->file
->qt_compatible
|| root
->file
->max_isom_version
< 4) )
1819 return -1; /* Don't allow composition to decode timeline shift. */
1823 int lsmash_get_media_timestamps( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_media_ts_list_t
*ts_list
)
1827 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1830 uint32_t sample_count
= timeline
->info_list
->entry_count
;
1833 ts_list
->sample_count
= 0;
1834 ts_list
->timestamp
= NULL
;
1837 lsmash_media_ts_t
*ts
= lsmash_malloc( sample_count
* sizeof(lsmash_media_ts_t
) );
1842 if( timeline
->info_list
->entry_count
)
1843 for( lsmash_entry_t
*entry
= timeline
->info_list
->head
; entry
; entry
= entry
->next
)
1845 isom_sample_info_t
*info
= (isom_sample_info_t
*)entry
->data
;
1852 ts
[i
].cts
= timeline
->ctd_shift
? (dts
+ (int32_t)info
->offset
) : (dts
+ info
->offset
);
1853 dts
+= info
->duration
;
1857 for( lsmash_entry_t
*entry
= timeline
->bunch_list
->head
; entry
; entry
= entry
->next
)
1859 isom_lpcm_bunch_t
*bunch
= (isom_lpcm_bunch_t
*)entry
->data
;
1865 for( uint32_t j
= 0; j
< bunch
->sample_count
; j
++ )
1868 ts
[i
].cts
= timeline
->ctd_shift
? (dts
+ (int32_t)bunch
->offset
) : (dts
+ bunch
->offset
);
1869 dts
+= bunch
->duration
;
1873 ts_list
->sample_count
= sample_count
;
1874 ts_list
->timestamp
= ts
;
1878 void lsmash_delete_media_timestamps( lsmash_media_ts_list_t
*ts_list
)
1882 if( ts_list
->timestamp
)
1884 lsmash_free( ts_list
->timestamp
);
1885 ts_list
->timestamp
= NULL
;
1887 ts_list
->sample_count
= 0;
1890 static int isom_compare_dts( const lsmash_media_ts_t
*a
, const lsmash_media_ts_t
*b
)
1892 int64_t diff
= (int64_t)(a
->dts
- b
->dts
);
1893 return diff
> 0 ? 1 : (diff
== 0 ? 0 : -1);
1896 void lsmash_sort_timestamps_decoding_order( lsmash_media_ts_list_t
*ts_list
)
1900 qsort( ts_list
->timestamp
, ts_list
->sample_count
, sizeof(lsmash_media_ts_t
), (int(*)( const void *, const void * ))isom_compare_dts
);
1903 static int isom_compare_cts( const lsmash_media_ts_t
*a
, const lsmash_media_ts_t
*b
)
1905 int64_t diff
= (int64_t)(a
->cts
- b
->cts
);
1906 return diff
> 0 ? 1 : (diff
== 0 ? 0 : -1);
1909 void lsmash_sort_timestamps_composition_order( lsmash_media_ts_list_t
*ts_list
)
1913 qsort( ts_list
->timestamp
, ts_list
->sample_count
, sizeof(lsmash_media_ts_t
), (int(*)( const void *, const void * ))isom_compare_cts
);
1916 int lsmash_get_max_sample_delay( lsmash_media_ts_list_t
*ts_list
, uint32_t *max_sample_delay
)
1918 if( !ts_list
|| !max_sample_delay
)
1920 lsmash_media_ts_t
*orig_ts
= ts_list
->timestamp
;
1921 lsmash_media_ts_t
*ts
= lsmash_malloc( ts_list
->sample_count
* sizeof(lsmash_media_ts_t
) );
1924 ts_list
->timestamp
= ts
;
1925 *max_sample_delay
= 0;
1926 for( uint32_t i
= 0; i
< ts_list
->sample_count
; i
++ )
1928 ts
[i
].cts
= orig_ts
[i
].cts
; /* for sorting */
1931 lsmash_sort_timestamps_composition_order( ts_list
);
1932 for( uint32_t i
= 0; i
< ts_list
->sample_count
; i
++ )
1935 uint32_t sample_delay
= ts
[i
].dts
- i
;
1936 *max_sample_delay
= LSMASH_MAX( *max_sample_delay
, sample_delay
);
1939 ts_list
->timestamp
= orig_ts
;
1943 #endif /* LSMASH_DEMUXER_ENABLED */