1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2011-2017 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 #include "common/internal.h" /* must be placed first */
32 #include "codecs/mp4a.h"
33 #include "codecs/mp4sys.h"
34 #include "codecs/description.h"
36 #include "importer/importer.h"
38 #define NO_RANDOM_ACCESS_POINT 0xffffffff
47 isom_portable_chunk_t
*chunk
;
48 lsmash_sample_property_t prop
;
51 static const lsmash_class_t lsmash_timeline_class
=
56 struct isom_timeline_tag
58 const lsmash_class_t
*class;
60 uint32_t movie_timescale
;
61 uint32_t media_timescale
;
62 uint32_t sample_count
;
63 uint32_t max_sample_size
;
64 uint32_t ctd_shift
; /* shift from composition to decode timeline */
65 uint64_t media_duration
;
66 uint64_t track_duration
;
67 uint32_t last_accessed_sample_number
;
68 uint64_t last_accessed_sample_dts
;
69 uint32_t last_accessed_lpcm_bunch_number
;
70 uint32_t last_accessed_lpcm_bunch_duration
;
71 uint32_t last_accessed_lpcm_bunch_sample_count
;
72 uint32_t last_accessed_lpcm_bunch_first_sample_number
;
73 uint64_t last_accessed_lpcm_bunch_dts
;
74 lsmash_entry_list_t edit_list
[1]; /* list of edits */
75 lsmash_entry_list_t chunk_list
[1]; /* list of chunks */
76 lsmash_entry_list_t info_list
[1]; /* list of sample info */
77 lsmash_entry_list_t bunch_list
[1]; /* list of LPCM bunch */
78 int (*get_dts
)( isom_timeline_t
*timeline
, uint32_t sample_number
, uint64_t *dts
);
79 int (*get_cts
)( isom_timeline_t
*timeline
, uint32_t sample_number
, uint64_t *cts
);
80 int (*get_sample_duration
)( isom_timeline_t
*timeline
, uint32_t sample_number
, uint32_t *sample_duration
);
81 lsmash_sample_t
*(*get_sample
)( isom_timeline_t
*timeline
, uint32_t sample_number
);
82 int (*get_sample_info
)( isom_timeline_t
*timeline
, uint32_t sample_number
, lsmash_sample_t
*sample
);
83 int (*get_sample_property
)( isom_timeline_t
*timeline
, uint32_t sample_number
, lsmash_sample_property_t
*prop
);
84 int (*check_sample_existence
)( isom_timeline_t
*timeline
, uint32_t sample_number
);
87 isom_timeline_t
*isom_get_timeline( lsmash_root_t
*root
, uint32_t track_ID
)
89 if( isom_check_initializer_present( root
) < 0
91 || !root
->file
->timeline
)
93 for( lsmash_entry_t
*entry
= root
->file
->timeline
->head
; entry
; entry
= entry
->next
)
95 isom_timeline_t
*timeline
= (isom_timeline_t
*)entry
->data
;
98 if( timeline
->track_ID
== track_ID
)
104 isom_timeline_t
*isom_timeline_create( void )
106 isom_timeline_t
*timeline
= lsmash_malloc_zero( sizeof(isom_timeline_t
) );
109 timeline
->class = &lsmash_timeline_class
;
110 lsmash_list_init_simple( timeline
->edit_list
);
111 lsmash_list_init_simple( timeline
->chunk_list
);
112 lsmash_list_init_simple( timeline
->info_list
);
113 lsmash_list_init_simple( timeline
->bunch_list
);
117 void isom_timeline_destroy( isom_timeline_t
*timeline
)
121 lsmash_list_remove_entries( timeline
->edit_list
);
122 lsmash_list_remove_entries( timeline
->chunk_list
); /* chunk data must be already freed. */
123 lsmash_list_remove_entries( timeline
->info_list
);
124 lsmash_list_remove_entries( timeline
->bunch_list
);
125 lsmash_free( timeline
);
128 void isom_remove_timelines( lsmash_file_t
*file
)
130 if( LSMASH_IS_NON_EXISTING_BOX( file
) || !file
->timeline
)
132 lsmash_list_destroy( file
->timeline
);
135 void lsmash_destruct_timeline( lsmash_root_t
*root
, uint32_t track_ID
)
137 if( LSMASH_IS_NON_EXISTING_BOX( root
)
139 || !root
->file
->timeline
)
141 for( lsmash_entry_t
*entry
= root
->file
->timeline
->head
; entry
; entry
= entry
->next
)
143 isom_timeline_t
*timeline
= (isom_timeline_t
*)entry
->data
;
146 if( timeline
->track_ID
== track_ID
)
148 lsmash_list_remove_entry_direct( root
->file
->timeline
, entry
);
154 int isom_timeline_set_track_ID
156 isom_timeline_t
*timeline
,
160 if( !timeline
|| track_ID
== 0 )
161 return LSMASH_ERR_FUNCTION_PARAM
;
162 timeline
->track_ID
= track_ID
;
166 int isom_timeline_set_movie_timescale
168 isom_timeline_t
*timeline
,
169 uint32_t movie_timescale
172 if( !timeline
|| movie_timescale
== 0 )
173 return LSMASH_ERR_FUNCTION_PARAM
;
174 timeline
->movie_timescale
= movie_timescale
;
178 int isom_timeline_set_media_timescale
180 isom_timeline_t
*timeline
,
181 uint32_t media_timescale
184 if( !timeline
|| media_timescale
== 0 )
185 return LSMASH_ERR_FUNCTION_PARAM
;
186 timeline
->media_timescale
= media_timescale
;
190 int isom_timeline_set_sample_count
192 isom_timeline_t
*timeline
,
193 uint32_t sample_count
196 if( !timeline
|| sample_count
== 0 )
197 return LSMASH_ERR_FUNCTION_PARAM
;
198 timeline
->sample_count
= sample_count
;
202 int isom_timeline_set_max_sample_size
204 isom_timeline_t
*timeline
,
205 uint32_t max_sample_size
208 if( !timeline
|| max_sample_size
== 0 )
209 return LSMASH_ERR_FUNCTION_PARAM
;
210 timeline
->max_sample_size
= max_sample_size
;
214 int isom_timeline_set_media_duration
216 isom_timeline_t
*timeline
,
217 uint32_t media_duration
220 if( !timeline
|| media_duration
== 0 )
221 return LSMASH_ERR_FUNCTION_PARAM
;
222 timeline
->media_duration
= media_duration
;
226 int isom_timeline_set_track_duration
228 isom_timeline_t
*timeline
,
229 uint32_t track_duration
232 if( !timeline
|| track_duration
== 0 )
233 return LSMASH_ERR_FUNCTION_PARAM
;
234 timeline
->track_duration
= track_duration
;
238 static void isom_get_qt_fixed_comp_audio_sample_quants
240 isom_timeline_t
*timeline
,
241 isom_sample_entry_t
*description
,
242 uint32_t *samples_per_packet
,
243 uint32_t *constant_sample_size
246 isom_audio_entry_t
*audio
= (isom_audio_entry_t
*)description
;
247 if( audio
->version
== 0 )
250 if( !isom_get_implicit_qt_fixed_comp_audio_sample_quants( audio
, samples_per_packet
, constant_sample_size
, &dummy
) )
253 if( !isom_is_lpcm_audio( audio
) )
254 lsmash_log( timeline
, LSMASH_LOG_WARNING
, "unsupported implicit sample table!\n" );
255 *samples_per_packet
= 1;
256 *constant_sample_size
= (audio
->samplesize
* audio
->channelcount
) / 8;
259 else if( audio
->version
== 1 )
261 *samples_per_packet
= audio
->samplesPerPacket
;
262 *constant_sample_size
= audio
->bytesPerFrame
;
264 else /* if( audio->version == 2 ) */
266 *samples_per_packet
= audio
->constLPCMFramesPerAudioPacket
;
267 *constant_sample_size
= audio
->constBytesPerAudioPacket
;
271 static int isom_is_qt_fixed_compressed_audio
273 isom_sample_entry_t
*description
276 if( (description
->manager
& LSMASH_VIDEO_DESCRIPTION
) || !isom_is_qt_audio( description
->type
) )
278 /* LPCM is a special case of fixed compression. */
279 return (((isom_audio_entry_t
*)description
)->compression_ID
!= QT_AUDIO_COMPRESSION_ID_VARIABLE_COMPRESSION
);
282 static int isom_add_sample_info_entry( isom_timeline_t
*timeline
, isom_sample_info_t
*src_info
)
284 isom_sample_info_t
*dst_info
= lsmash_malloc( sizeof(isom_sample_info_t
) );
286 return LSMASH_ERR_MEMORY_ALLOC
;
287 if( lsmash_list_add_entry( timeline
->info_list
, dst_info
) < 0 )
289 lsmash_free( dst_info
);
290 return LSMASH_ERR_MEMORY_ALLOC
;
292 *dst_info
= *src_info
;
296 int isom_add_lpcm_bunch_entry( isom_timeline_t
*timeline
, isom_lpcm_bunch_t
*src_bunch
)
298 isom_lpcm_bunch_t
*dst_bunch
= lsmash_malloc( sizeof(isom_lpcm_bunch_t
) );
300 return LSMASH_ERR_MEMORY_ALLOC
;
301 if( lsmash_list_add_entry( timeline
->bunch_list
, dst_bunch
) < 0 )
303 lsmash_free( dst_bunch
);
304 return LSMASH_ERR_MEMORY_ALLOC
;
306 *dst_bunch
= *src_bunch
;
310 static int isom_add_portable_chunk_entry( isom_timeline_t
*timeline
, isom_portable_chunk_t
*src_chunk
)
312 isom_portable_chunk_t
*dst_chunk
= lsmash_malloc( sizeof(isom_portable_chunk_t
) );
314 return LSMASH_ERR_MEMORY_ALLOC
;
315 if( lsmash_list_add_entry( timeline
->chunk_list
, dst_chunk
) < 0 )
317 lsmash_free( dst_chunk
);
318 return LSMASH_ERR_MEMORY_ALLOC
;
320 *dst_chunk
= *src_chunk
;
324 static int isom_compare_lpcm_sample_info( isom_lpcm_bunch_t
*bunch
, isom_sample_info_t
*info
)
326 return info
->duration
!= bunch
->duration
327 || info
->offset
!= bunch
->offset
328 || info
->length
!= bunch
->length
329 || info
->index
!= bunch
->index
330 || info
->chunk
!= bunch
->chunk
;
333 static void isom_update_bunch( isom_lpcm_bunch_t
*bunch
, isom_sample_info_t
*info
)
335 bunch
->pos
= info
->pos
;
336 bunch
->duration
= info
->duration
;
337 bunch
->offset
= info
->offset
;
338 bunch
->length
= info
->length
;
339 bunch
->index
= info
->index
;
340 bunch
->chunk
= info
->chunk
;
341 bunch
->prop
= info
->prop
;
342 bunch
->sample_count
= 1;
345 static isom_lpcm_bunch_t
*isom_get_bunch( isom_timeline_t
*timeline
, uint32_t sample_number
)
347 if( sample_number
>= timeline
->last_accessed_lpcm_bunch_first_sample_number
348 && sample_number
< timeline
->last_accessed_lpcm_bunch_first_sample_number
+ timeline
->last_accessed_lpcm_bunch_sample_count
)
349 /* Get from the last accessed LPCM bunch. */
350 return (isom_lpcm_bunch_t
*)lsmash_list_get_entry_data( timeline
->bunch_list
, timeline
->last_accessed_lpcm_bunch_number
);
351 uint32_t first_sample_number_in_next_bunch
;
352 uint32_t bunch_number
= 1;
354 if( timeline
->last_accessed_lpcm_bunch_first_sample_number
355 && timeline
->last_accessed_lpcm_bunch_first_sample_number
<= sample_number
)
357 first_sample_number_in_next_bunch
= timeline
->last_accessed_lpcm_bunch_first_sample_number
+ timeline
->last_accessed_lpcm_bunch_sample_count
;
358 bunch_number
+= timeline
->last_accessed_lpcm_bunch_number
;
359 bunch_dts
= timeline
->last_accessed_lpcm_bunch_dts
360 + timeline
->last_accessed_lpcm_bunch_duration
* timeline
->last_accessed_lpcm_bunch_sample_count
;
364 /* Seek from the first LPCM bunch. */
365 first_sample_number_in_next_bunch
= 1;
368 isom_lpcm_bunch_t
*bunch
= (isom_lpcm_bunch_t
*)lsmash_list_get_entry_data( timeline
->bunch_list
, bunch_number
++ );
371 first_sample_number_in_next_bunch
+= bunch
->sample_count
;
372 while( sample_number
>= first_sample_number_in_next_bunch
)
374 bunch_dts
+= bunch
->duration
* bunch
->sample_count
;
375 bunch
= (isom_lpcm_bunch_t
*)lsmash_list_get_entry_data( timeline
->bunch_list
, bunch_number
++ );
378 first_sample_number_in_next_bunch
+= bunch
->sample_count
;
380 timeline
->last_accessed_lpcm_bunch_dts
= bunch_dts
;
381 timeline
->last_accessed_lpcm_bunch_number
= bunch_number
- 1;
382 timeline
->last_accessed_lpcm_bunch_duration
= bunch
->duration
;
383 timeline
->last_accessed_lpcm_bunch_sample_count
= bunch
->sample_count
;
384 timeline
->last_accessed_lpcm_bunch_first_sample_number
= first_sample_number_in_next_bunch
- bunch
->sample_count
;
388 static int isom_get_dts_from_info_list( isom_timeline_t
*timeline
, uint32_t sample_number
, uint64_t *dts
)
390 if( sample_number
== timeline
->last_accessed_sample_number
)
391 *dts
= timeline
->last_accessed_sample_dts
;
392 else if( sample_number
== 1 )
394 else if( sample_number
== timeline
->last_accessed_sample_number
+ 1 )
396 isom_sample_info_t
*info
= (isom_sample_info_t
*)lsmash_list_get_entry_data( timeline
->info_list
, timeline
->last_accessed_sample_number
);
398 return LSMASH_ERR_NAMELESS
;
399 *dts
= timeline
->last_accessed_sample_dts
+ info
->duration
;
401 else if( sample_number
== timeline
->last_accessed_sample_number
- 1 )
403 isom_sample_info_t
*info
= (isom_sample_info_t
*)lsmash_list_get_entry_data( timeline
->info_list
, timeline
->last_accessed_sample_number
- 1 );
405 return LSMASH_ERR_NAMELESS
;
406 *dts
= timeline
->last_accessed_sample_dts
- info
->duration
;
411 uint32_t distance
= sample_number
- 1;
412 lsmash_entry_t
*entry
;
413 for( entry
= timeline
->info_list
->head
; entry
; entry
= entry
->next
)
415 isom_sample_info_t
*info
= (isom_sample_info_t
*)entry
->data
;
417 return LSMASH_ERR_NAMELESS
;
418 if( distance
-- == 0 )
420 *dts
+= info
->duration
;
423 return LSMASH_ERR_NAMELESS
;
425 /* Note: last_accessed_sample_number is always updated together with last_accessed_sample_dts, and vice versa. */
426 timeline
->last_accessed_sample_dts
= *dts
;
427 timeline
->last_accessed_sample_number
= sample_number
;
431 static int isom_get_cts_from_info_list( isom_timeline_t
*timeline
, uint32_t sample_number
, uint64_t *cts
)
433 int ret
= isom_get_dts_from_info_list( timeline
, sample_number
, cts
);
436 isom_sample_info_t
*info
= (isom_sample_info_t
*)lsmash_list_get_entry_data( timeline
->info_list
, sample_number
);
438 return LSMASH_ERR_NAMELESS
;
439 *cts
= isom_make_cts( *cts
, info
->offset
, timeline
->ctd_shift
);
443 static int isom_get_dts_from_bunch_list( isom_timeline_t
*timeline
, uint32_t sample_number
, uint64_t *dts
)
445 isom_lpcm_bunch_t
*bunch
= isom_get_bunch( timeline
, sample_number
);
447 return LSMASH_ERR_NAMELESS
;
448 *dts
= timeline
->last_accessed_lpcm_bunch_dts
+ (sample_number
- timeline
->last_accessed_lpcm_bunch_first_sample_number
) * bunch
->duration
;
452 static int isom_get_cts_from_bunch_list( isom_timeline_t
*timeline
, uint32_t sample_number
, uint64_t *cts
)
454 isom_lpcm_bunch_t
*bunch
= isom_get_bunch( timeline
, sample_number
);
456 return LSMASH_ERR_NAMELESS
;
457 *cts
= timeline
->last_accessed_lpcm_bunch_dts
+ (sample_number
- timeline
->last_accessed_lpcm_bunch_first_sample_number
) * bunch
->duration
+ bunch
->offset
;
461 static int isom_get_sample_duration_from_info_list( isom_timeline_t
*timeline
, uint32_t sample_number
, uint32_t *sample_duration
)
463 isom_sample_info_t
*info
= (isom_sample_info_t
*)lsmash_list_get_entry_data( timeline
->info_list
, sample_number
);
465 return LSMASH_ERR_NAMELESS
;
466 *sample_duration
= info
->duration
;
470 static int isom_get_sample_duration_from_bunch_list( isom_timeline_t
*timeline
, uint32_t sample_number
, uint32_t *sample_duration
)
472 isom_lpcm_bunch_t
*bunch
= isom_get_bunch( timeline
, sample_number
);
474 return LSMASH_ERR_NAMELESS
;
475 *sample_duration
= bunch
->duration
;
479 static int isom_check_sample_existence_in_info_list( isom_timeline_t
*timeline
, uint32_t sample_number
)
481 isom_sample_info_t
*info
= (isom_sample_info_t
*)lsmash_list_get_entry_data( timeline
->info_list
, sample_number
);
482 if( !info
|| !info
->chunk
)
484 return !!info
->chunk
->file
;
487 static int isom_check_sample_existence_in_bunch_list( isom_timeline_t
*timeline
, uint32_t sample_number
)
489 isom_lpcm_bunch_t
*bunch
= isom_get_bunch( timeline
, sample_number
);
490 if( !bunch
|| !bunch
->chunk
)
492 return !!bunch
->chunk
->file
;
495 static lsmash_sample_t
*isom_read_sample_data_from_stream
498 isom_timeline_t
*timeline
,
499 uint32_t sample_length
,
505 lsmash_sample_t
*sample
= lsmash_create_sample( 0 );
508 lsmash_bs_t
*bs
= file
->bs
;
509 lsmash_bs_read_seek( bs
, sample_pos
, SEEK_SET
);
510 sample
->data
= lsmash_bs_get_bytes( bs
, sample_length
);
513 lsmash_delete_sample( sample
);
519 static lsmash_sample_t
*isom_get_lpcm_sample_from_media_timeline( isom_timeline_t
*timeline
, uint32_t sample_number
)
521 isom_lpcm_bunch_t
*bunch
= isom_get_bunch( timeline
, sample_number
);
525 /* Get data of a sample from the stream. */
526 uint64_t sample_number_offset
= sample_number
- timeline
->last_accessed_lpcm_bunch_first_sample_number
;
527 uint64_t sample_pos
= bunch
->pos
+ sample_number_offset
* bunch
->length
;
528 lsmash_sample_t
*sample
= isom_read_sample_data_from_stream( bunch
->chunk
->file
, timeline
, bunch
->length
, sample_pos
);
531 /* Get sample info. */
532 sample
->dts
= timeline
->last_accessed_lpcm_bunch_dts
+ sample_number_offset
* bunch
->duration
;
533 sample
->cts
= isom_make_cts( sample
->dts
, bunch
->offset
, timeline
->ctd_shift
);
534 sample
->pos
= sample_pos
;
535 sample
->length
= bunch
->length
;
536 sample
->index
= bunch
->index
;
537 sample
->prop
= bunch
->prop
;
541 static lsmash_sample_t
*isom_get_sample_from_media_timeline( isom_timeline_t
*timeline
, uint32_t sample_number
)
544 if( isom_get_dts_from_info_list( timeline
, sample_number
, &dts
) < 0 )
546 isom_sample_info_t
*info
= (isom_sample_info_t
*)lsmash_list_get_entry_data( timeline
->info_list
, sample_number
);
550 /* Get data of a sample from the stream. */
551 lsmash_sample_t
*sample
= isom_read_sample_data_from_stream( info
->chunk
->file
, timeline
, info
->length
, info
->pos
);
554 /* Get sample info. */
556 sample
->cts
= isom_make_cts( dts
, info
->offset
, timeline
->ctd_shift
);
557 sample
->pos
= info
->pos
;
558 sample
->length
= info
->length
;
559 sample
->index
= info
->index
;
560 sample
->prop
= info
->prop
;
564 static int isom_get_lpcm_sample_info_from_media_timeline( isom_timeline_t
*timeline
, uint32_t sample_number
, lsmash_sample_t
*sample
)
566 isom_lpcm_bunch_t
*bunch
= isom_get_bunch( timeline
, sample_number
);
568 return LSMASH_ERR_NAMELESS
;
569 uint64_t sample_number_offset
= sample_number
- timeline
->last_accessed_lpcm_bunch_first_sample_number
;
570 sample
->dts
= timeline
->last_accessed_lpcm_bunch_dts
+ sample_number_offset
* bunch
->duration
;
571 sample
->cts
= isom_make_cts( sample
->dts
, bunch
->offset
, timeline
->ctd_shift
);
572 sample
->pos
= bunch
->pos
+ sample_number_offset
* bunch
->length
;
573 sample
->length
= bunch
->length
;
574 sample
->index
= bunch
->index
;
575 sample
->prop
= bunch
->prop
;
579 static int isom_get_sample_info_from_media_timeline( isom_timeline_t
*timeline
, uint32_t sample_number
, lsmash_sample_t
*sample
)
582 int ret
= isom_get_dts_from_info_list( timeline
, sample_number
, &dts
);
585 isom_sample_info_t
*info
= (isom_sample_info_t
*)lsmash_list_get_entry_data( timeline
->info_list
, sample_number
);
587 return LSMASH_ERR_NAMELESS
;
589 sample
->cts
= isom_make_cts( dts
, info
->offset
, timeline
->ctd_shift
);
590 sample
->pos
= info
->pos
;
591 sample
->length
= info
->length
;
592 sample
->index
= info
->index
;
593 sample
->prop
= info
->prop
;
597 static int isom_get_lpcm_sample_property_from_media_timeline( isom_timeline_t
*timeline
, uint32_t sample_number
, lsmash_sample_property_t
*prop
)
599 memset( prop
, 0, sizeof(lsmash_sample_property_t
) );
600 prop
->ra_flags
= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC
;
604 static int isom_get_sample_property_from_media_timeline( isom_timeline_t
*timeline
, uint32_t sample_number
, lsmash_sample_property_t
*prop
)
606 isom_sample_info_t
*info
= (isom_sample_info_t
*)lsmash_list_get_entry_data( timeline
->info_list
, sample_number
);
608 return LSMASH_ERR_NAMELESS
;
613 static void isom_timeline_set_sample_getter_funcs
615 isom_timeline_t
*timeline
618 timeline
->get_dts
= isom_get_dts_from_info_list
;
619 timeline
->get_cts
= isom_get_cts_from_info_list
;
620 timeline
->get_sample_duration
= isom_get_sample_duration_from_info_list
;
621 timeline
->check_sample_existence
= isom_check_sample_existence_in_info_list
;
622 timeline
->get_sample
= isom_get_sample_from_media_timeline
;
623 timeline
->get_sample_info
= isom_get_sample_info_from_media_timeline
;
624 timeline
->get_sample_property
= isom_get_sample_property_from_media_timeline
;
627 void isom_timeline_set_lpcm_sample_getter_funcs
629 isom_timeline_t
*timeline
632 timeline
->get_dts
= isom_get_dts_from_bunch_list
;
633 timeline
->get_cts
= isom_get_cts_from_bunch_list
;
634 timeline
->get_sample_duration
= isom_get_sample_duration_from_bunch_list
;
635 timeline
->check_sample_existence
= isom_check_sample_existence_in_bunch_list
;
636 timeline
->get_sample
= isom_get_lpcm_sample_from_media_timeline
;
637 timeline
->get_sample_info
= isom_get_lpcm_sample_info_from_media_timeline
;
638 timeline
->get_sample_property
= isom_get_lpcm_sample_property_from_media_timeline
;
641 static inline void isom_increment_sample_number_in_entry
643 uint32_t *sample_number_in_entry
,
644 lsmash_entry_t
**entry
,
645 uint32_t sample_count
648 if( *sample_number_in_entry
== sample_count
)
650 *sample_number_in_entry
= 1;
651 *entry
= (*entry
)->next
;
654 *sample_number_in_entry
+= 1;
657 static inline isom_sgpd_t
*isom_select_appropriate_sgpd
660 isom_sgpd_t
*sgpd_frag
,
661 uint32_t *group_description_index
664 if( LSMASH_IS_EXISTING_BOX( sgpd_frag
) && *group_description_index
>= 0x10000 )
666 /* The specification doesn't define 0x10000 explicitly, however says that there must be fewer than
667 * 65536 group definitions for this track and grouping type in the sample table in the Movie Box.
668 * So, we assume 0x10000 is equivalent to 0. */
669 *group_description_index
-= 0x10000;
676 static int isom_get_roll_recovery_grouping_info
678 isom_timeline_t
*timeline
,
679 lsmash_entry_t
**sbgp_roll_entry
,
680 isom_sgpd_t
*sgpd_roll
,
681 isom_sgpd_t
*sgpd_frag_roll
,
682 uint32_t *sample_number_in_sbgp_roll_entry
,
683 isom_sample_info_t
*info
,
684 uint32_t sample_number
687 isom_group_assignment_entry_t
*assignment
= (isom_group_assignment_entry_t
*)(*sbgp_roll_entry
)->data
;
689 return LSMASH_ERR_NAMELESS
;
690 if( assignment
->group_description_index
)
692 uint32_t group_description_index
= assignment
->group_description_index
;
693 isom_sgpd_t
*sgpd
= isom_select_appropriate_sgpd( sgpd_roll
, sgpd_frag_roll
, &group_description_index
);
694 isom_roll_entry_t
*roll_data
= (isom_roll_entry_t
*)lsmash_list_get_entry_data( sgpd
->list
, group_description_index
);
697 if( roll_data
->roll_distance
> 0 )
700 info
->prop
.post_roll
.complete
= sample_number
+ roll_data
->roll_distance
;
701 if( info
->prop
.ra_flags
== ISOM_SAMPLE_RANDOM_ACCESS_FLAG_NONE
)
702 info
->prop
.ra_flags
|= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_POST_ROLL_START
;
704 else if( roll_data
->roll_distance
< 0 )
707 info
->prop
.pre_roll
.distance
= -roll_data
->roll_distance
;
708 if( info
->prop
.ra_flags
== ISOM_SAMPLE_RANDOM_ACCESS_FLAG_NONE
)
709 info
->prop
.ra_flags
|= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_PRE_ROLL_END
;
712 else if( *sample_number_in_sbgp_roll_entry
== 1 && group_description_index
)
713 lsmash_log( timeline
, LSMASH_LOG_WARNING
, "a description of roll recoveries is not found in the Sample Group Description Box.\n" );
715 isom_increment_sample_number_in_entry( sample_number_in_sbgp_roll_entry
, sbgp_roll_entry
, assignment
->sample_count
);
719 static int isom_get_random_access_point_grouping_info
721 isom_timeline_t
*timeline
,
722 lsmash_entry_t
**sbgp_rap_entry
,
723 isom_sgpd_t
*sgpd_rap
,
724 isom_sgpd_t
*sgpd_frag_rap
,
725 uint32_t *sample_number_in_sbgp_rap_entry
,
726 isom_sample_info_t
*info
,
730 isom_group_assignment_entry_t
*assignment
= (isom_group_assignment_entry_t
*)(*sbgp_rap_entry
)->data
;
732 return LSMASH_ERR_NAMELESS
;
733 if( assignment
->group_description_index
&& (info
->prop
.ra_flags
== ISOM_SAMPLE_RANDOM_ACCESS_FLAG_NONE
) )
735 uint32_t group_description_index
= assignment
->group_description_index
;
736 isom_sgpd_t
*sgpd
= isom_select_appropriate_sgpd( sgpd_rap
, sgpd_frag_rap
, &group_description_index
);
737 isom_rap_entry_t
*rap_data
= (isom_rap_entry_t
*)lsmash_list_get_entry_data( sgpd
->list
, group_description_index
);
740 /* If this is not an open RAP, we treat it as an unknown RAP since non-IDR sample could make a closed GOP. */
741 info
->prop
.ra_flags
|= (rap_data
->num_leading_samples_known
&& !!rap_data
->num_leading_samples
)
742 ? ISOM_SAMPLE_RANDOM_ACCESS_FLAG_OPEN_RAP
743 : ISOM_SAMPLE_RANDOM_ACCESS_FLAG_RAP
;
746 else if( *sample_number_in_sbgp_rap_entry
== 1 && group_description_index
)
747 lsmash_log( timeline
, LSMASH_LOG_WARNING
, "a description of random access points is not found in the Sample Group Description Box.\n" );
749 isom_increment_sample_number_in_entry( sample_number_in_sbgp_rap_entry
, sbgp_rap_entry
, assignment
->sample_count
);
753 int isom_timeline_construct( lsmash_root_t
*root
, uint32_t track_ID
)
755 if( isom_check_initializer_present( root
) < 0 )
756 return LSMASH_ERR_FUNCTION_PARAM
;
757 lsmash_file_t
*file
= root
->file
;
758 if( LSMASH_IS_NON_EXISTING_BOX( file
->moov
->mvhd
)
759 || file
->moov
->mvhd
->timescale
== 0 )
760 return LSMASH_ERR_INVALID_DATA
;
761 /* Get track by track_ID. */
762 isom_trak_t
*trak
= isom_get_trak( file
, track_ID
);
763 if( LSMASH_IS_NON_EXISTING_BOX( trak
->tkhd
)
764 || LSMASH_IS_NON_EXISTING_BOX( trak
->mdia
->mdhd
)
765 || LSMASH_IS_NON_EXISTING_BOX( trak
->mdia
->minf
->stbl
->stco
)
766 || LSMASH_IS_NON_EXISTING_BOX( trak
->mdia
->minf
->stbl
->stsd
)
767 || (LSMASH_IS_NON_EXISTING_BOX( trak
->mdia
->minf
->stbl
->stsz
) && LSMASH_IS_NON_EXISTING_BOX( trak
->mdia
->minf
->stbl
->stz2
))
768 || trak
->mdia
->mdhd
->timescale
== 0 )
769 return LSMASH_ERR_INVALID_DATA
;
770 /* Create a timeline list if it doesn't exist. */
771 if( !file
->timeline
)
773 file
->timeline
= lsmash_list_create( isom_timeline_destroy
);
774 if( !file
->timeline
)
775 return LSMASH_ERR_MEMORY_ALLOC
;
777 /* Create a timeline. */
778 isom_timeline_t
*timeline
= isom_timeline_create();
780 return LSMASH_ERR_MEMORY_ALLOC
;
781 timeline
->track_ID
= track_ID
;
782 timeline
->movie_timescale
= file
->moov
->mvhd
->timescale
;
783 timeline
->media_timescale
= trak
->mdia
->mdhd
->timescale
;
784 timeline
->track_duration
= trak
->tkhd
->duration
;
785 /* Preparation for construction. */
786 isom_elst_t
*elst
= trak
->edts
->elst
;
787 isom_minf_t
*minf
= trak
->mdia
->minf
;
788 isom_dref_t
*dref
= minf
->dinf
->dref
;
789 isom_stbl_t
*stbl
= minf
->stbl
;
790 isom_stsd_t
*stsd
= stbl
->stsd
;
791 isom_stts_t
*stts
= stbl
->stts
;
792 isom_ctts_t
*ctts
= stbl
->ctts
;
793 isom_stss_t
*stss
= stbl
->stss
;
794 isom_stps_t
*stps
= stbl
->stps
;
795 isom_sdtp_t
*sdtp
= stbl
->sdtp
;
796 isom_stsc_t
*stsc
= stbl
->stsc
;
797 isom_stsz_t
*stsz
= stbl
->stsz
;
798 isom_stz2_t
*stz2
= stbl
->stz2
;
799 isom_stco_t
*stco
= stbl
->stco
;
800 isom_sgpd_t
*sgpd_rap
= isom_get_sample_group_description( stbl
, ISOM_GROUP_TYPE_RAP
);
801 isom_sbgp_t
*sbgp_rap
= isom_get_sample_to_group ( stbl
, ISOM_GROUP_TYPE_RAP
);
802 isom_sgpd_t
*sgpd_roll
= isom_get_roll_recovery_sample_group_description( &stbl
->sgpd_list
);
803 isom_sbgp_t
*sbgp_roll
= isom_get_roll_recovery_sample_to_group ( &stbl
->sbgp_list
);
804 lsmash_entry_t
*elst_entry
= elst
->list
? elst
->list
->head
: NULL
;
805 lsmash_entry_t
*stts_entry
= stts
->list
? stts
->list
->head
: NULL
;
806 lsmash_entry_t
*ctts_entry
= ctts
->list
? ctts
->list
->head
: NULL
;
807 lsmash_entry_t
*stss_entry
= stss
->list
? stss
->list
->head
: NULL
;
808 lsmash_entry_t
*stps_entry
= stps
->list
? stps
->list
->head
: NULL
;
809 lsmash_entry_t
*sdtp_entry
= sdtp
->list
? sdtp
->list
->head
: NULL
;
810 lsmash_entry_t
*stsz_entry
= LSMASH_IS_EXISTING_BOX( stsz
) ? (stsz
->list
? stsz
->list
->head
: NULL
)
811 : (stz2
->list
? stz2
->list
->head
: NULL
);
812 lsmash_entry_t
*stsc_entry
= stsc
->list
? stsc
->list
->head
: NULL
;
813 lsmash_entry_t
*stco_entry
= stco
->list
? stco
->list
->head
: NULL
;
814 lsmash_entry_t
*sbgp_roll_entry
= sbgp_roll
->list
? sbgp_roll
->list
->head
: NULL
;
815 lsmash_entry_t
*sbgp_rap_entry
= sbgp_rap
->list
? sbgp_rap
->list
->head
: NULL
;
816 lsmash_entry_t
*next_stsc_entry
= stsc_entry
? stsc_entry
->next
: NULL
;
817 isom_stsc_entry_t
*stsc_data
= stsc_entry
? (isom_stsc_entry_t
*)stsc_entry
->data
: NULL
;
818 int err
= LSMASH_ERR_INVALID_DATA
;
819 int movie_fragments_present
= (LSMASH_IS_EXISTING_BOX( file
->moov
->mvex
) && file
->moof_list
.head
);
820 if( !movie_fragments_present
&& (!stts_entry
|| !stsc_entry
|| !stco_entry
|| !stco_entry
->data
|| (next_stsc_entry
&& !next_stsc_entry
->data
)) )
822 isom_sample_entry_t
*description
= (isom_sample_entry_t
*)lsmash_list_get_entry_data( &stsd
->list
, stsc_data
? stsc_data
->sample_description_index
: 1 );
823 if( LSMASH_IS_NON_EXISTING_BOX( description
) )
825 lsmash_entry_list_t
*dref_list
= LSMASH_IS_EXISTING_BOX( dref
) ? &dref
->list
: NULL
;
826 isom_dref_entry_t
*dref_entry
= (isom_dref_entry_t
*)lsmash_list_get_entry_data( dref_list
, description
->data_reference_index
);
827 int all_sync
= LSMASH_IS_NON_EXISTING_BOX( stss
);
828 int large_presentation
= stco
->large_presentation
|| lsmash_check_box_type_identical( stco
->type
, ISOM_BOX_TYPE_CO64
);
829 int is_lpcm_audio
= isom_is_lpcm_audio( description
);
830 int is_qt_fixed_comp_audio
= isom_is_qt_fixed_compressed_audio( description
);
831 int iso_sdtp
= file
->max_isom_version
>= 2 || file
->avc_extensions
;
832 int allow_negative_sample_offset
= ctts
&& ((file
->max_isom_version
>= 4 && ctts
->version
== 1) || file
->qt_compatible
);
833 uint32_t sample_number_in_stts_entry
= 1;
834 uint32_t sample_number_in_ctts_entry
= 1;
835 uint32_t sample_number_in_sbgp_roll_entry
= 1;
836 uint32_t sample_number_in_sbgp_rap_entry
= 1;
838 uint32_t chunk_number
= 1;
839 uint64_t offset_from_chunk
= 0;
840 uint64_t data_offset
= stco_entry
&& stco_entry
->data
842 ? ((isom_co64_entry_t
*)stco_entry
->data
)->chunk_offset
843 : ((isom_stco_entry_t
*)stco_entry
->data
)->chunk_offset
845 uint32_t initial_movie_sample_count
= LSMASH_IS_EXISTING_BOX( stsz
) ? stsz
->sample_count
: stz2
->sample_count
;
846 uint32_t samples_per_packet
;
847 uint32_t constant_sample_size
;
848 if( is_qt_fixed_comp_audio
)
849 isom_get_qt_fixed_comp_audio_sample_quants( timeline
, description
, &samples_per_packet
, &constant_sample_size
);
852 samples_per_packet
= 1;
853 constant_sample_size
= stsz
? stsz
->sample_size
: 0;
855 uint32_t sample_number
= samples_per_packet
;
856 uint32_t sample_number_in_chunk
= samples_per_packet
;
860 isom_elst_entry_t
*edit
= (isom_elst_entry_t
*)lsmash_memdup( elst_entry
->data
, sizeof(isom_elst_entry_t
) );
862 || lsmash_list_add_entry( timeline
->edit_list
, edit
) < 0 )
864 err
= LSMASH_ERR_MEMORY_ALLOC
;
867 elst_entry
= elst_entry
->next
;
869 /* Check what the first 2-bits of sample dependency means.
870 * This check is for chimera of ISO Base Media and QTFF. */
871 if( iso_sdtp
&& sdtp_entry
)
875 isom_sdtp_entry_t
*sdtp_data
= (isom_sdtp_entry_t
*)sdtp_entry
->data
;
878 if( sdtp_data
->is_leading
> 1 )
879 break; /* Apparently, it's defined under ISO Base Media. */
880 if( (sdtp_data
->is_leading
== 1) && (sdtp_data
->sample_depends_on
== ISOM_SAMPLE_IS_INDEPENDENT
) )
882 /* Obviously, it's not defined under ISO Base Media. */
886 sdtp_entry
= sdtp_entry
->next
;
888 sdtp_entry
= sdtp
->list
->head
;
890 /**--- Construct media timeline. ---**/
891 isom_portable_chunk_t chunk
;
892 chunk
.data_offset
= data_offset
;
894 chunk
.number
= chunk_number
;
895 chunk
.file
= (!dref_entry
|| LSMASH_IS_NON_EXISTING_BOX( dref_entry
->ref_file
)) ? NULL
: dref_entry
->ref_file
;
896 if( (err
= isom_add_portable_chunk_entry( timeline
, &chunk
)) < 0 )
898 uint32_t distance
= NO_RANDOM_ACCESS_POINT
;
899 uint32_t last_duration
= UINT32_MAX
;
900 uint32_t packet_number
= 1;
901 isom_lpcm_bunch_t bunch
= { 0 };
902 while( sample_number
<= initial_movie_sample_count
)
904 isom_sample_info_t info
= { 0 };
905 /* Get sample duration and sample offset. */
906 for( uint32_t i
= 0; i
< samples_per_packet
; i
++ )
908 /* sample duration */
911 isom_stts_entry_t
*stts_data
= (isom_stts_entry_t
*)stts_entry
->data
;
914 isom_increment_sample_number_in_entry( &sample_number_in_stts_entry
, &stts_entry
, stts_data
->sample_count
);
915 last_duration
= stts_data
->sample_delta
;
917 info
.duration
+= last_duration
;
918 dts
+= last_duration
;
920 uint32_t sample_offset
;
923 isom_ctts_entry_t
*ctts_data
= (isom_ctts_entry_t
*)ctts_entry
->data
;
926 isom_increment_sample_number_in_entry( &sample_number_in_ctts_entry
, &ctts_entry
, ctts_data
->sample_count
);
927 sample_offset
= ctts_data
->sample_offset
;
928 if( allow_negative_sample_offset
&& sample_offset
!= ISOM_NON_OUTPUT_SAMPLE_OFFSET
)
930 uint64_t cts
= dts
+ (int32_t)sample_offset
;
931 if( (cts
+ timeline
->ctd_shift
) < dts
)
932 timeline
->ctd_shift
= dts
- cts
;
938 info
.offset
= sample_offset
;
940 timeline
->media_duration
+= info
.duration
;
941 if( !is_qt_fixed_comp_audio
)
943 /* Check whether sync sample or not. */
946 isom_stss_entry_t
*stss_data
= (isom_stss_entry_t
*)stss_entry
->data
;
949 if( sample_number
== stss_data
->sample_number
)
951 info
.prop
.ra_flags
|= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC
;
952 stss_entry
= stss_entry
->next
;
957 /* Don't reset distance as 0 since MDCT-based audio frames need pre-roll for correct presentation
958 * though all of them could be marked as a sync sample. */
959 info
.prop
.ra_flags
|= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC
;
960 /* Check whether partial sync sample or not. */
963 isom_stps_entry_t
*stps_data
= (isom_stps_entry_t
*)stps_entry
->data
;
966 if( sample_number
== stps_data
->sample_number
)
968 info
.prop
.ra_flags
|= QT_SAMPLE_RANDOM_ACCESS_FLAG_PARTIAL_SYNC
| QT_SAMPLE_RANDOM_ACCESS_FLAG_RAP
;
969 stps_entry
= stps_entry
->next
;
973 /* Get sample dependency info. */
976 isom_sdtp_entry_t
*sdtp_data
= (isom_sdtp_entry_t
*)sdtp_entry
->data
;
980 info
.prop
.leading
= sdtp_data
->is_leading
;
982 info
.prop
.allow_earlier
= sdtp_data
->is_leading
;
983 info
.prop
.independent
= sdtp_data
->sample_depends_on
;
984 info
.prop
.disposable
= sdtp_data
->sample_is_depended_on
;
985 info
.prop
.redundant
= sdtp_data
->sample_has_redundancy
;
986 sdtp_entry
= sdtp_entry
->next
;
988 /* Get roll recovery grouping info. */
990 && isom_get_roll_recovery_grouping_info( timeline
,
991 &sbgp_roll_entry
, sgpd_roll
, NULL
,
992 &sample_number_in_sbgp_roll_entry
,
993 &info
, sample_number
) < 0 )
995 info
.prop
.post_roll
.identifier
= sample_number
;
996 /* Get random access point grouping info. */
998 && isom_get_random_access_point_grouping_info( timeline
,
999 &sbgp_rap_entry
, sgpd_rap
, NULL
,
1000 &sample_number_in_sbgp_rap_entry
,
1001 &info
, &distance
) < 0 )
1003 /* Set up distance from the previous random access point. */
1004 if( distance
!= NO_RANDOM_ACCESS_POINT
)
1006 if( info
.prop
.pre_roll
.distance
== 0 )
1007 info
.prop
.pre_roll
.distance
= distance
;
1012 /* All uncompressed and non-variable compressed audio frame is a sync sample. */
1013 info
.prop
.ra_flags
= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC
;
1014 /* Get size of sample in the stream. */
1015 if( is_qt_fixed_comp_audio
|| !stsz_entry
)
1016 info
.length
= constant_sample_size
;
1019 if( !stsz_entry
->data
)
1021 info
.length
= ((isom_stsz_entry_t
*)stsz_entry
->data
)->entry_size
;
1022 stsz_entry
= stsz_entry
->next
;
1024 timeline
->max_sample_size
= LSMASH_MAX( timeline
->max_sample_size
, info
.length
);
1025 /* Get chunk info. */
1026 info
.pos
= data_offset
;
1027 info
.index
= stsc_data
->sample_description_index
;
1028 info
.chunk
= (isom_portable_chunk_t
*)timeline
->chunk_list
->tail
->data
;
1029 offset_from_chunk
+= info
.length
;
1030 if( sample_number_in_chunk
== stsc_data
->samples_per_chunk
)
1032 /* Set the length of the last chunk. */
1034 info
.chunk
->length
= offset_from_chunk
;
1035 /* Move the next chunk. */
1037 stco_entry
= stco_entry
->next
;
1039 && stco_entry
->data
)
1040 data_offset
= large_presentation
1041 ? ((isom_co64_entry_t
*)stco_entry
->data
)->chunk_offset
1042 : ((isom_stco_entry_t
*)stco_entry
->data
)->chunk_offset
;
1043 chunk
.data_offset
= data_offset
;
1045 chunk
.number
= ++chunk_number
;
1046 offset_from_chunk
= 0;
1047 /* Check if the next entry is broken. */
1048 while( next_stsc_entry
&& chunk_number
> ((isom_stsc_entry_t
*)next_stsc_entry
->data
)->first_chunk
)
1050 /* Just skip broken next entry. */
1051 lsmash_log( timeline
, LSMASH_LOG_WARNING
, "ignore broken entry in Sample To Chunk Box.\n" );
1052 lsmash_log( timeline
, LSMASH_LOG_WARNING
, "timeline might be corrupted.\n" );
1053 next_stsc_entry
= next_stsc_entry
->next
;
1055 && !next_stsc_entry
->data
)
1058 /* Check if the next chunk belongs to the next sequence of chunks. */
1059 if( next_stsc_entry
&& chunk_number
== ((isom_stsc_entry_t
*)next_stsc_entry
->data
)->first_chunk
)
1061 stsc_entry
= next_stsc_entry
;
1062 next_stsc_entry
= next_stsc_entry
->next
;
1064 && !next_stsc_entry
->data
)
1066 stsc_data
= (isom_stsc_entry_t
*)stsc_entry
->data
;
1067 /* Update sample description. */
1068 description
= (isom_sample_entry_t
*)lsmash_list_get_entry_data( &stsd
->list
, stsc_data
->sample_description_index
);
1069 is_lpcm_audio
= LSMASH_IS_EXISTING_BOX( description
) ? isom_is_lpcm_audio( description
) : 0;
1070 is_qt_fixed_comp_audio
= LSMASH_IS_EXISTING_BOX( description
) ? isom_is_qt_fixed_compressed_audio( description
) : 0;
1071 if( is_qt_fixed_comp_audio
)
1072 isom_get_qt_fixed_comp_audio_sample_quants( timeline
, description
, &samples_per_packet
, &constant_sample_size
);
1075 samples_per_packet
= 1;
1076 constant_sample_size
= stsz
? stsz
->sample_size
: 0;
1078 /* Reference media data. */
1079 dref_entry
= (isom_dref_entry_t
*)lsmash_list_get_entry_data( dref_list
, LSMASH_IS_EXISTING_BOX( description
) ? description
->data_reference_index
: 0 );
1080 chunk
.file
= (!dref_entry
|| LSMASH_IS_NON_EXISTING_BOX( dref_entry
->ref_file
)) ? NULL
: dref_entry
->ref_file
;
1082 sample_number_in_chunk
= samples_per_packet
;
1083 if( (err
= isom_add_portable_chunk_entry( timeline
, &chunk
)) < 0 )
1088 data_offset
+= info
.length
;
1089 sample_number_in_chunk
+= samples_per_packet
;
1091 /* OK. Let's add its info. */
1094 if( sample_number
== samples_per_packet
)
1095 isom_update_bunch( &bunch
, &info
);
1096 else if( isom_compare_lpcm_sample_info( &bunch
, &info
) )
1098 if( (err
= isom_add_lpcm_bunch_entry( timeline
, &bunch
)) < 0 )
1100 isom_update_bunch( &bunch
, &info
);
1103 ++ bunch
.sample_count
;
1105 else if( (err
= isom_add_sample_info_entry( timeline
, &info
)) < 0 )
1107 if( timeline
->info_list
->entry_count
&& timeline
->bunch_list
->entry_count
)
1109 lsmash_log( timeline
, LSMASH_LOG_ERROR
, "LPCM + non-LPCM track is not supported.\n" );
1110 err
= LSMASH_ERR_PATCH_WELCOME
;
1113 sample_number
+= samples_per_packet
;
1116 isom_portable_chunk_t
*last_chunk
= lsmash_list_get_entry_data( timeline
->chunk_list
, timeline
->chunk_list
->entry_count
);
1119 if( offset_from_chunk
)
1120 last_chunk
->length
= offset_from_chunk
;
1123 /* Remove the last invalid chunk. */
1124 lsmash_list_remove_entry( timeline
->chunk_list
, timeline
->chunk_list
->entry_count
);
1128 uint32_t sample_count
= packet_number
- 1;
1129 if( movie_fragments_present
)
1131 isom_tfra_t
*tfra
= isom_get_tfra( file
->mfra
, track_ID
);
1132 lsmash_entry_t
*tfra_entry
= tfra
->list
? tfra
->list
->head
: NULL
;
1133 isom_tfra_location_time_entry_t
*rap
= tfra_entry
? (isom_tfra_location_time_entry_t
*)tfra_entry
->data
: NULL
;
1134 chunk
.data_offset
= 0;
1136 /* Movie fragments */
1137 for( lsmash_entry_t
*moof_entry
= file
->moof_list
.head
; moof_entry
; moof_entry
= moof_entry
->next
)
1139 isom_moof_t
*moof
= (isom_moof_t
*)moof_entry
->data
;
1140 if( LSMASH_IS_NON_EXISTING_BOX( moof
) )
1142 uint64_t last_sample_end_pos
= 0;
1143 /* Track fragments */
1144 uint32_t traf_number
= 1;
1145 for( lsmash_entry_t
*traf_entry
= moof
->traf_list
.head
; traf_entry
; traf_entry
= traf_entry
->next
)
1147 isom_traf_t
*traf
= (isom_traf_t
*)traf_entry
->data
;
1148 isom_tfhd_t
*tfhd
= traf
->tfhd
;
1149 isom_trex_t
*trex
= isom_get_trex( file
->moov
->mvex
, tfhd
->track_ID
);
1150 if( LSMASH_IS_NON_EXISTING_BOX( trex
) )
1152 /* Ignore ISOM_TF_FLAGS_DURATION_IS_EMPTY flag even if set. */
1153 if( !traf
->trun_list
.head
)
1158 /* Get base_data_offset. */
1159 uint64_t base_data_offset
;
1160 if( tfhd
->flags
& ISOM_TF_FLAGS_BASE_DATA_OFFSET_PRESENT
)
1161 base_data_offset
= tfhd
->base_data_offset
;
1162 else if( (tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_BASE_IS_MOOF
) || traf_entry
== moof
->traf_list
.head
)
1163 base_data_offset
= moof
->pos
;
1165 base_data_offset
= last_sample_end_pos
;
1166 /* sample grouping */
1167 isom_sgpd_t
*sgpd_frag_rap
;
1168 isom_sgpd_t
*sgpd_frag_roll
;
1169 sgpd_frag_rap
= isom_get_fragment_sample_group_description( traf
, ISOM_GROUP_TYPE_RAP
);
1170 sbgp_rap
= isom_get_fragment_sample_to_group ( traf
, ISOM_GROUP_TYPE_RAP
);
1171 sbgp_rap_entry
= sbgp_rap
->list
? sbgp_rap
->list
->head
: NULL
;
1172 sgpd_frag_roll
= isom_get_roll_recovery_sample_group_description( &traf
->sgpd_list
);
1173 sbgp_roll
= isom_get_roll_recovery_sample_to_group ( &traf
->sbgp_list
);
1174 sbgp_roll_entry
= sbgp_roll
->list
? sbgp_roll
->list
->head
: NULL
;
1175 int need_data_offset_only
= (tfhd
->track_ID
!= track_ID
);
1177 uint32_t trun_number
= 1;
1178 for( lsmash_entry_t
*trun_entry
= traf
->trun_list
.head
; trun_entry
; trun_entry
= trun_entry
->next
)
1180 isom_trun_t
*trun
= (isom_trun_t
*)trun_entry
->data
;
1181 if( LSMASH_IS_NON_EXISTING_BOX( trun
) )
1183 if( trun
->sample_count
== 0 )
1188 /* Get data_offset. */
1189 if( trun
->flags
& ISOM_TR_FLAGS_DATA_OFFSET_PRESENT
)
1190 data_offset
= trun
->data_offset
+ base_data_offset
;
1191 else if( trun_entry
== traf
->trun_list
.head
)
1192 data_offset
= base_data_offset
;
1194 data_offset
= last_sample_end_pos
;
1196 uint32_t sample_description_index
= 0;
1197 isom_sdtp_entry_t
*sdtp_data
= NULL
;
1198 if( !need_data_offset_only
)
1200 /* Get sample_description_index of this track fragment. */
1201 if( tfhd
->flags
& ISOM_TF_FLAGS_SAMPLE_DESCRIPTION_INDEX_PRESENT
)
1202 sample_description_index
= tfhd
->sample_description_index
;
1204 sample_description_index
= trex
->default_sample_description_index
;
1205 description
= (isom_sample_entry_t
*)lsmash_list_get_entry_data( &stsd
->list
, sample_description_index
);
1206 is_lpcm_audio
= LSMASH_IS_EXISTING_BOX( description
) ? isom_is_lpcm_audio( description
) : 0;
1207 /* Reference media data. */
1208 dref_entry
= (isom_dref_entry_t
*)lsmash_list_get_entry_data( dref_list
, LSMASH_IS_EXISTING_BOX( description
) ? description
->data_reference_index
: 0 );
1209 lsmash_file_t
*ref_file
= (!dref_entry
|| LSMASH_IS_NON_EXISTING_BOX( dref_entry
->ref_file
)) ? NULL
: dref_entry
->ref_file
;
1210 /* Each track run can be considered as a chunk.
1211 * Here, we consider physically consecutive track runs as one chunk. */
1212 if( chunk
.data_offset
+ chunk
.length
!= data_offset
|| chunk
.file
!= ref_file
)
1214 chunk
.data_offset
= data_offset
;
1216 chunk
.number
= ++chunk_number
;
1217 chunk
.file
= ref_file
;
1218 if( (err
= isom_add_portable_chunk_entry( timeline
, &chunk
)) < 0 )
1221 /* Get dependency info for this track fragment. */
1222 sdtp_entry
= traf
->sdtp
->list
? traf
->sdtp
->list
->head
: NULL
;
1223 sdtp_data
= sdtp_entry
&& sdtp_entry
->data
? (isom_sdtp_entry_t
*)sdtp_entry
->data
: NULL
;
1225 /* Get info of each sample. */
1226 lsmash_entry_t
*row_entry
= trun
->optional
&& trun
->optional
->head
? trun
->optional
->head
: NULL
;
1228 while( sample_number
<= trun
->sample_count
)
1230 isom_sample_info_t info
= { 0 };
1231 isom_trun_optional_row_t
*row
= row_entry
&& row_entry
->data
? (isom_trun_optional_row_t
*)row_entry
->data
: NULL
;
1232 /* Get sample_size */
1233 if( row
&& (trun
->flags
& ISOM_TR_FLAGS_SAMPLE_SIZE_PRESENT
) )
1234 info
.length
= row
->sample_size
;
1235 else if( tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_SAMPLE_SIZE_PRESENT
)
1236 info
.length
= tfhd
->default_sample_size
;
1238 info
.length
= trex
->default_sample_size
;
1239 if( !need_data_offset_only
)
1241 info
.pos
= data_offset
;
1242 info
.index
= sample_description_index
;
1243 info
.chunk
= (isom_portable_chunk_t
*)timeline
->chunk_list
->tail
->data
;
1244 info
.chunk
->length
+= info
.length
;
1245 /* Get sample_duration. */
1246 if( row
&& (trun
->flags
& ISOM_TR_FLAGS_SAMPLE_DURATION_PRESENT
) )
1247 info
.duration
= row
->sample_duration
;
1248 else if( tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT
)
1249 info
.duration
= tfhd
->default_sample_duration
;
1251 info
.duration
= trex
->default_sample_duration
;
1252 /* Get composition time offset. */
1253 if( row
&& (trun
->flags
& ISOM_TR_FLAGS_SAMPLE_COMPOSITION_TIME_OFFSET_PRESENT
) )
1255 info
.offset
= row
->sample_composition_time_offset
;
1256 /* Check composition to decode timeline shift. */
1257 if( file
->max_isom_version
>= 6 && trun
->version
!= 0 && info
.offset
!= ISOM_NON_OUTPUT_SAMPLE_OFFSET
)
1259 uint64_t cts
= dts
+ (int32_t)info
.offset
;
1260 if( (cts
+ timeline
->ctd_shift
) < dts
)
1261 timeline
->ctd_shift
= dts
- cts
;
1266 dts
+= info
.duration
;
1267 /* Update media duration and maximun sample size. */
1268 timeline
->media_duration
+= info
.duration
;
1269 timeline
->max_sample_size
= LSMASH_MAX( timeline
->max_sample_size
, info
.length
);
1270 if( !is_lpcm_audio
)
1272 /* Get sample_flags. */
1273 isom_sample_flags_t sample_flags
;
1274 if( sample_number
== 1 && (trun
->flags
& ISOM_TR_FLAGS_FIRST_SAMPLE_FLAGS_PRESENT
) )
1275 sample_flags
= trun
->first_sample_flags
;
1276 else if( row
&& (trun
->flags
& ISOM_TR_FLAGS_SAMPLE_FLAGS_PRESENT
) )
1277 sample_flags
= row
->sample_flags
;
1278 else if( tfhd
->flags
& ISOM_TF_FLAGS_DEFAULT_SAMPLE_FLAGS_PRESENT
)
1279 sample_flags
= tfhd
->default_sample_flags
;
1281 sample_flags
= trex
->default_sample_flags
;
1284 /* Independent and Disposable Samples Box overrides the information from sample_flags.
1285 * There is no description in the specification about this, but the intention should be such a thing.
1286 * The ground is that sample_flags is placed in media layer
1287 * while Independent and Disposable Samples Box is placed in track or presentation layer. */
1288 info
.prop
.leading
= sdtp_data
->is_leading
;
1289 info
.prop
.independent
= sdtp_data
->sample_depends_on
;
1290 info
.prop
.disposable
= sdtp_data
->sample_is_depended_on
;
1291 info
.prop
.redundant
= sdtp_data
->sample_has_redundancy
;
1293 sdtp_entry
= sdtp_entry
->next
;
1294 sdtp_data
= sdtp_entry
? (isom_sdtp_entry_t
*)sdtp_entry
->data
: NULL
;
1298 info
.prop
.leading
= sample_flags
.is_leading
;
1299 info
.prop
.independent
= sample_flags
.sample_depends_on
;
1300 info
.prop
.disposable
= sample_flags
.sample_is_depended_on
;
1301 info
.prop
.redundant
= sample_flags
.sample_has_redundancy
;
1303 /* Check this sample is a sync sample or not.
1304 * Note: all sync sample shall be independent. */
1305 if( !sample_flags
.sample_is_non_sync_sample
1306 && info
.prop
.independent
!= ISOM_SAMPLE_IS_NOT_INDEPENDENT
)
1308 info
.prop
.ra_flags
|= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC
;
1311 /* Get roll recovery grouping info. */
1312 uint32_t roll_id
= sample_count
+ sample_number
;
1314 && isom_get_roll_recovery_grouping_info( timeline
,
1315 &sbgp_roll_entry
, sgpd_roll
, sgpd_frag_roll
,
1316 &sample_number_in_sbgp_roll_entry
,
1317 &info
, roll_id
) < 0 )
1319 info
.prop
.post_roll
.identifier
= roll_id
;
1320 /* Get random access point grouping info. */
1322 && isom_get_random_access_point_grouping_info( timeline
,
1323 &sbgp_rap_entry
, sgpd_rap
, sgpd_frag_rap
,
1324 &sample_number_in_sbgp_rap_entry
,
1325 &info
, &distance
) < 0 )
1327 /* Get the location of the sync sample from 'tfra' if it is not set up yet.
1328 * Note: there is no guarantee that its entries are placed in a specific order. */
1329 if( LSMASH_IS_EXISTING_BOX( tfra
) )
1331 if( tfra
->number_of_entry
== 0
1332 && info
.prop
.ra_flags
== ISOM_SAMPLE_RANDOM_ACCESS_FLAG_NONE
)
1333 info
.prop
.ra_flags
|= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC
;
1335 && rap
->moof_offset
== moof
->pos
1336 && rap
->traf_number
== traf_number
1337 && rap
->trun_number
== trun_number
1338 && rap
->sample_number
== sample_number
)
1340 if( info
.prop
.ra_flags
== ISOM_SAMPLE_RANDOM_ACCESS_FLAG_NONE
)
1341 info
.prop
.ra_flags
|= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC
;
1343 tfra_entry
= tfra_entry
->next
;
1344 rap
= tfra_entry
? (isom_tfra_location_time_entry_t
*)tfra_entry
->data
: NULL
;
1347 /* Set up distance from the previous random access point. */
1348 if( distance
!= NO_RANDOM_ACCESS_POINT
)
1350 if( info
.prop
.pre_roll
.distance
== 0 )
1351 info
.prop
.pre_roll
.distance
= distance
;
1354 /* OK. Let's add its info. */
1355 if( (err
= isom_add_sample_info_entry( timeline
, &info
)) < 0 )
1360 /* All LPCMFrame is a sync sample. */
1361 info
.prop
.ra_flags
= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC
;
1362 /* OK. Let's add its info. */
1363 if( sample_count
== 0 && sample_number
== 1 )
1364 isom_update_bunch( &bunch
, &info
);
1365 else if( isom_compare_lpcm_sample_info( &bunch
, &info
) )
1367 if( (err
= isom_add_lpcm_bunch_entry( timeline
, &bunch
)) < 0 )
1369 isom_update_bunch( &bunch
, &info
);
1372 ++ bunch
.sample_count
;
1374 if( timeline
-> info_list
->entry_count
1375 && timeline
->bunch_list
->entry_count
)
1377 lsmash_log( timeline
, LSMASH_LOG_ERROR
, "LPCM + non-LPCM track is not supported.\n" );
1378 err
= LSMASH_ERR_PATCH_WELCOME
;
1382 data_offset
+= info
.length
;
1383 last_sample_end_pos
= data_offset
;
1385 row_entry
= row_entry
->next
;
1388 if( !need_data_offset_only
)
1389 sample_count
+= sample_number
- 1;
1393 } /* Track fragments */
1394 } /* Movie fragments */
1396 else if( timeline
->chunk_list
->entry_count
== 0 )
1397 goto fail
; /* No samples in this track. */
1398 if( bunch
.sample_count
&& (err
= isom_add_lpcm_bunch_entry( timeline
, &bunch
)) < 0 )
1400 if( (err
= lsmash_list_add_entry( file
->timeline
, timeline
)) < 0 )
1402 /* Finish timeline construction. */
1403 timeline
->sample_count
= sample_count
;
1404 if( timeline
->info_list
->entry_count
)
1405 isom_timeline_set_sample_getter_funcs( timeline
);
1407 isom_timeline_set_lpcm_sample_getter_funcs( timeline
);
1410 isom_timeline_destroy( timeline
);
1414 int lsmash_construct_timeline( lsmash_root_t
*root
, uint32_t track_ID
)
1416 if( LSMASH_IS_NON_EXISTING_BOX( root
)
1417 || LSMASH_IS_NON_EXISTING_BOX( root
->file
)
1419 return LSMASH_ERR_FUNCTION_PARAM
;
1420 uint32_t track_number
;
1421 if( LSMASH_IS_EXISTING_BOX( root
->file
->initializer
) )
1423 if( LSMASH_IS_NON_EXISTING_BOX( root
->file
->initializer
->moov
) )
1424 return LSMASH_ERR_INVALID_DATA
;
1426 int track_found
= 0;
1427 for( lsmash_entry_t
*entry
= root
->file
->initializer
->moov
->trak_list
.head
; entry
; entry
= entry
->next
)
1429 isom_trak_t
*trak
= (isom_trak_t
*)entry
->data
;
1430 if( LSMASH_IS_NON_EXISTING_BOX( trak
)
1431 || LSMASH_IS_NON_EXISTING_BOX( trak
->tkhd
) )
1433 if( trak
->tkhd
->track_ID
== track_ID
)
1441 return LSMASH_ERR_NAMELESS
;
1444 track_number
= track_ID
;
1445 return lsmash_importer_construct_timeline( root
->file
->importer
, track_number
);
1448 int lsmash_get_dts_from_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t sample_number
, uint64_t *dts
)
1450 if( !sample_number
|| !dts
)
1451 return LSMASH_ERR_FUNCTION_PARAM
;
1452 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1453 if( !timeline
|| sample_number
> timeline
->sample_count
)
1454 return LSMASH_ERR_NAMELESS
;
1455 return timeline
->get_dts( timeline
, sample_number
, dts
);
1458 int lsmash_get_cts_from_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t sample_number
, uint64_t *cts
)
1460 if( !sample_number
|| !cts
)
1461 return LSMASH_ERR_FUNCTION_PARAM
;
1462 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1463 if( !timeline
|| sample_number
> timeline
->sample_count
)
1464 return LSMASH_ERR_NAMELESS
;
1465 return timeline
->get_cts( timeline
, sample_number
, cts
);
1468 lsmash_sample_t
*lsmash_get_sample_from_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t sample_number
)
1470 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1471 return timeline
? timeline
->get_sample( timeline
, sample_number
) : NULL
;
1474 int lsmash_get_sample_info_from_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t sample_number
, lsmash_sample_t
*sample
)
1477 return LSMASH_ERR_FUNCTION_PARAM
;
1478 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1479 return timeline
? timeline
->get_sample_info( timeline
, sample_number
, sample
) : -1;
1482 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
)
1485 return LSMASH_ERR_FUNCTION_PARAM
;
1486 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1487 return timeline
? timeline
->get_sample_property( timeline
, sample_number
, prop
) : -1;
1490 int lsmash_get_composition_to_decode_shift_from_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t *ctd_shift
)
1493 return LSMASH_ERR_FUNCTION_PARAM
;
1494 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1496 return LSMASH_ERR_NAMELESS
;
1497 *ctd_shift
= timeline
->ctd_shift
;
1501 static int isom_get_closest_past_random_accessible_point_from_media_timeline( isom_timeline_t
*timeline
, uint32_t sample_number
, uint32_t *rap_number
)
1503 lsmash_entry_t
*entry
= lsmash_list_get_entry( timeline
->info_list
, sample_number
-- );
1506 return LSMASH_ERR_NAMELESS
;
1507 isom_sample_info_t
*info
= (isom_sample_info_t
*)entry
->data
;
1508 while( info
->prop
.ra_flags
== ISOM_SAMPLE_RANDOM_ACCESS_FLAG_NONE
)
1510 entry
= entry
->prev
;
1513 return LSMASH_ERR_NAMELESS
;
1514 info
= (isom_sample_info_t
*)entry
->data
;
1517 *rap_number
= sample_number
+ 1;
1521 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
)
1523 lsmash_entry_t
*entry
= lsmash_list_get_entry( timeline
->info_list
, sample_number
++ );
1526 return LSMASH_ERR_NAMELESS
;
1527 isom_sample_info_t
*info
= (isom_sample_info_t
*)entry
->data
;
1528 while( info
->prop
.ra_flags
== ISOM_SAMPLE_RANDOM_ACCESS_FLAG_NONE
)
1530 entry
= entry
->next
;
1533 return LSMASH_ERR_NAMELESS
;
1534 info
= (isom_sample_info_t
*)entry
->data
;
1537 *rap_number
= sample_number
- 1;
1541 static int isom_get_closest_random_accessible_point_from_media_timeline_internal( isom_timeline_t
*timeline
, uint32_t sample_number
, uint32_t *rap_number
)
1544 return LSMASH_ERR_NAMELESS
;
1546 if( (ret
= isom_get_closest_past_random_accessible_point_from_media_timeline( timeline
, sample_number
, rap_number
)) < 0
1547 && (ret
= isom_get_closest_future_random_accessible_point_from_media_timeline( timeline
, sample_number
+ 1, rap_number
)) < 0 )
1552 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
)
1554 if( sample_number
== 0 || !rap_number
)
1555 return LSMASH_ERR_FUNCTION_PARAM
;
1556 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1558 return LSMASH_ERR_NAMELESS
;
1559 if( timeline
->info_list
->entry_count
== 0 )
1561 *rap_number
= sample_number
; /* All LPCM is sync sample. */
1564 return isom_get_closest_random_accessible_point_from_media_timeline_internal( timeline
, sample_number
, rap_number
);
1567 int lsmash_get_closest_random_accessible_point_detail_from_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t sample_number
,
1568 uint32_t *rap_number
, lsmash_random_access_flag
*ra_flags
, uint32_t *leading
, uint32_t *distance
)
1570 if( sample_number
== 0 )
1571 return LSMASH_ERR_FUNCTION_PARAM
;
1572 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1574 return LSMASH_ERR_NAMELESS
;
1575 if( timeline
->info_list
->entry_count
== 0 )
1577 /* All LPCM is sync sample. */
1578 *rap_number
= sample_number
;
1580 *ra_flags
= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC
;
1587 int ret
= isom_get_closest_random_accessible_point_from_media_timeline_internal( timeline
, sample_number
, rap_number
);
1590 isom_sample_info_t
*info
= (isom_sample_info_t
*)lsmash_list_get_entry_data( timeline
->info_list
, *rap_number
);
1592 return LSMASH_ERR_NAMELESS
;
1594 *ra_flags
= info
->prop
.ra_flags
;
1599 if( sample_number
< *rap_number
)
1600 /* Impossible to desire to decode the sample of given number correctly. */
1602 else if( !(info
->prop
.ra_flags
& ISOM_SAMPLE_RANDOM_ACCESS_FLAG_GDR
) )
1606 /* Count leading samples. */
1607 uint32_t current_sample_number
= *rap_number
+ 1;
1609 if( (ret
= isom_get_dts_from_info_list( timeline
, *rap_number
, &dts
)) < 0 )
1611 uint64_t rap_cts
= isom_make_cts_adjust( dts
, info
->offset
, timeline
->ctd_shift
);
1614 dts
+= info
->duration
;
1615 if( rap_cts
<= dts
)
1616 break; /* leading samples of this random accessible point must not be present more. */
1617 info
= (isom_sample_info_t
*)lsmash_list_get_entry_data( timeline
->info_list
, current_sample_number
++ );
1620 uint64_t cts
= isom_make_cts_adjust( dts
, info
->offset
, timeline
->ctd_shift
);
1621 if( rap_cts
!= LSMASH_TIMESTAMP_UNDEFINED
&& rap_cts
> cts
)
1625 if( !distance
|| sample_number
== *rap_number
)
1627 /* Measure distance from the first closest non-recovery random accessible point to the second. */
1628 uint32_t prev_rap_number
= *rap_number
;
1631 if( isom_get_closest_past_random_accessible_point_from_media_timeline( timeline
, prev_rap_number
- 1, &prev_rap_number
) < 0 )
1632 /* The previous random accessible point is not present. */
1634 info
= (isom_sample_info_t
*)lsmash_list_get_entry_data( timeline
->info_list
, prev_rap_number
);
1636 return LSMASH_ERR_NAMELESS
;
1637 if( !(info
->prop
.ra_flags
& ISOM_SAMPLE_RANDOM_ACCESS_FLAG_GDR
) )
1639 /* Decode shall already complete at the first closest non-recovery random accessible point if starting to decode from the second. */
1640 *distance
= *rap_number
- prev_rap_number
;
1647 /* Calculate roll-distance. */
1648 if( info
->prop
.pre_roll
.distance
)
1650 /* Pre-roll recovery */
1651 uint32_t prev_rap_number
= *rap_number
;
1654 if( isom_get_closest_past_random_accessible_point_from_media_timeline( timeline
, prev_rap_number
- 1, &prev_rap_number
) < 0
1655 && *rap_number
< info
->prop
.pre_roll
.distance
)
1657 /* The previous random accessible point is not present.
1658 * And sample of given number might be not able to decoded correctly. */
1662 if( prev_rap_number
+ info
->prop
.pre_roll
.distance
<= *rap_number
)
1665 * |<---- pre-roll distance ---->|
1666 * |<--------- distance -------->|
1667 * media +++++++++++++++++++++++++ *** +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1669 * random accessible point starting point random accessible point given sample
1672 *distance
= info
->prop
.pre_roll
.distance
;
1675 else if( !(info
->prop
.ra_flags
& ISOM_SAMPLE_RANDOM_ACCESS_FLAG_GDR
) )
1678 * |<------------ pre-roll distance ------------------>|
1679 * |<------ distance ------->|
1680 * media ++++++++++++++++ *** ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1682 * random accessible point random accessible point given sample
1683 * (starting point) (complete)
1685 *distance
= *rap_number
- prev_rap_number
;
1690 /* Post-roll recovery */
1691 if( sample_number
>= info
->prop
.post_roll
.complete
)
1693 * |<----- post-roll distance ----->|
1695 * media +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1697 * random accessible point complete given sample
1701 uint32_t prev_rap_number
= *rap_number
;
1704 if( isom_get_closest_past_random_accessible_point_from_media_timeline( timeline
, prev_rap_number
- 1, &prev_rap_number
) < 0 )
1705 /* The previous random accessible point is not present. */
1707 info
= (isom_sample_info_t
*)lsmash_list_get_entry_data( timeline
->info_list
, prev_rap_number
);
1709 return LSMASH_ERR_NAMELESS
;
1710 if( !(info
->prop
.ra_flags
& ISOM_SAMPLE_RANDOM_ACCESS_FLAG_GDR
) || sample_number
>= info
->prop
.post_roll
.complete
)
1712 *distance
= *rap_number
- prev_rap_number
;
1718 int lsmash_check_sample_existence_in_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t sample_number
)
1720 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1721 return timeline
? timeline
->check_sample_existence( timeline
, sample_number
) : 0;
1724 int lsmash_get_last_sample_delta_from_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t *last_sample_delta
)
1726 if( !last_sample_delta
)
1727 return LSMASH_ERR_FUNCTION_PARAM
;
1728 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1729 return timeline
? timeline
->get_sample_duration( timeline
, timeline
->sample_count
, last_sample_delta
) : -1;
1732 int lsmash_get_sample_delta_from_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
, uint32_t sample_number
, uint32_t *sample_delta
)
1735 return LSMASH_ERR_FUNCTION_PARAM
;
1736 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1737 return timeline
? timeline
->get_sample_duration( timeline
, sample_number
, sample_delta
) : -1;
1740 uint32_t lsmash_get_sample_count_in_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
)
1742 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1745 return timeline
->sample_count
;
1748 uint32_t lsmash_get_max_sample_size_in_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
)
1750 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1753 return timeline
->max_sample_size
;
1756 uint64_t lsmash_get_media_duration_from_media_timeline( lsmash_root_t
*root
, uint32_t track_ID
)
1758 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1761 return timeline
->media_duration
;
1764 isom_elst_entry_t
*isom_timelime_get_explicit_timeline_map
1766 lsmash_root_t
*root
,
1768 uint32_t edit_number
1771 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1774 return lsmash_list_get_entry_data( timeline
->edit_list
, edit_number
);
1777 uint32_t isom_timelime_count_explicit_timeline_map
1779 lsmash_root_t
*root
,
1783 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1786 return timeline
->edit_list
->entry_count
;
1789 int lsmash_copy_timeline_map( lsmash_root_t
*dst
, uint32_t dst_track_ID
, lsmash_root_t
*src
, uint32_t src_track_ID
)
1791 if( isom_check_initializer_present( dst
) < 0
1792 || isom_check_initializer_present( src
) < 0 )
1793 return LSMASH_ERR_FUNCTION_PARAM
;
1794 lsmash_file_t
*dst_file
= dst
->file
->initializer
;
1795 isom_trak_t
*dst_trak
= isom_get_trak( dst_file
, dst_track_ID
);
1796 if( LSMASH_IS_NON_EXISTING_BOX( dst_file
->moov
->mvhd
)
1797 || LSMASH_IS_NON_EXISTING_BOX( dst_trak
->mdia
->mdhd
)
1798 || LSMASH_IS_NON_EXISTING_BOX( dst_trak
->mdia
->minf
->stbl
)
1799 || dst_file
->moov
->mvhd
->timescale
== 0
1800 || dst_trak
->mdia
->mdhd
->timescale
== 0 )
1801 return LSMASH_ERR_NAMELESS
;
1802 if( LSMASH_IS_EXISTING_BOX( dst_trak
->edts
->elst
) )
1803 lsmash_list_remove_entries( dst_trak
->edts
->elst
->list
);
1804 uint32_t src_movie_timescale
;
1805 uint32_t src_media_timescale
;
1806 uint64_t src_track_duration
;
1807 uint64_t src_media_duration
;
1808 int32_t src_ctd_shift
; /* Add timeline shift difference between src and dst to each media_time.
1809 * Therefore, call this function as later as possible. */
1810 lsmash_entry_t
*src_entry
= NULL
;
1811 lsmash_file_t
*src_file
= src
->file
->initializer
;
1812 isom_trak_t
*src_trak
= isom_get_trak( src_file
, src_track_ID
);
1813 int src_fragmented
= !!(src_file
->flags
& LSMASH_FILE_MODE_FRAGMENTED
);
1814 if( !src_trak
->edts
->elst
->list
1817 /* Get from constructed timeline instead of boxes. */
1818 isom_timeline_t
*src_timeline
= isom_get_timeline( src
, src_track_ID
);
1820 && src_timeline
->movie_timescale
1821 && src_timeline
->media_timescale
)
1823 src_entry
= src_timeline
->edit_list
->head
;
1826 src_movie_timescale
= src_timeline
->movie_timescale
;
1827 src_media_timescale
= src_timeline
->media_timescale
;
1828 src_track_duration
= src_timeline
->track_duration
;
1829 src_media_duration
= src_timeline
->media_duration
;
1830 src_ctd_shift
= src_timeline
->ctd_shift
;
1832 else if( !src_fragmented
)
1833 return LSMASH_ERR_NAMELESS
;
1837 if( LSMASH_IS_NON_EXISTING_BOX( src_file
->moov
->mvhd
)
1838 || LSMASH_IS_NON_EXISTING_BOX( src_trak
->tkhd
)
1839 || LSMASH_IS_NON_EXISTING_BOX( src_trak
->mdia
->mdhd
)
1840 || LSMASH_IS_NON_EXISTING_BOX( src_trak
->mdia
->minf
->stbl
)
1841 || src_file
->moov
->mvhd
->timescale
== 0
1842 || src_trak
->mdia
->mdhd
->timescale
== 0 )
1843 return LSMASH_ERR_NAMELESS
;
1844 if( !src_trak
->edts
->elst
->list
1845 || !src_trak
->edts
->elst
->list
->head
)
1847 src_entry
= src_trak
->edts
->elst
->list
->head
;
1848 src_movie_timescale
= src_file
->moov
->mvhd
->timescale
;
1849 src_media_timescale
= src_trak
->mdia
->mdhd
->timescale
;
1850 src_track_duration
= src_trak
->tkhd
->duration
;
1851 src_media_duration
= src_trak
->mdia
->mdhd
->duration
;
1852 src_ctd_shift
= src_trak
->mdia
->minf
->stbl
->cslg
->compositionToDTSShift
;
1854 /* Generate the edit list if absent in the destination. */
1855 if( (LSMASH_IS_NON_EXISTING_BOX( dst_trak
->edts
) && LSMASH_IS_BOX_ADDITION_FAILURE( isom_add_edts( dst_trak
) ))
1856 || (LSMASH_IS_NON_EXISTING_BOX( dst_trak
->edts
->elst
) && LSMASH_IS_BOX_ADDITION_FAILURE( isom_add_elst( dst_trak
->edts
) )) )
1857 return LSMASH_ERR_NAMELESS
;
1858 uint32_t dst_movie_timescale
= dst_file
->moov
->mvhd
->timescale
;
1859 uint32_t dst_media_timescale
= dst_trak
->mdia
->mdhd
->timescale
;
1860 int32_t dst_ctd_shift
= dst_trak
->mdia
->minf
->stbl
->cslg
->compositionToDTSShift
;
1861 int32_t media_time_shift
= src_ctd_shift
- dst_ctd_shift
;
1862 lsmash_entry_list_t
*dst_list
= dst_trak
->edts
->elst
->list
;
1865 isom_elst_entry_t
*src_data
= (isom_elst_entry_t
*)src_entry
->data
;
1867 return LSMASH_ERR_NAMELESS
;
1868 isom_elst_entry_t
*dst_data
= (isom_elst_entry_t
*)lsmash_malloc( sizeof(isom_elst_entry_t
) );
1870 return LSMASH_ERR_MEMORY_ALLOC
;
1871 uint64_t segment_duration
;
1872 if( src_data
->segment_duration
== 0 && !dst_file
->fragment
)
1873 /* The implicit duration edit is not suitable for non-fragmented movie file.
1874 * Set an appropriate duration from the source track. */
1875 segment_duration
= src_fragmented
1876 ? (uint64_t)(src_media_duration
* ((double)src_movie_timescale
/ src_media_timescale
))
1877 : src_track_duration
;
1879 segment_duration
= src_data
->segment_duration
;
1880 dst_data
->segment_duration
= segment_duration
* ((double)dst_movie_timescale
/ src_movie_timescale
) + 0.5;
1881 dst_data
->media_rate
= src_data
->media_rate
;
1882 if( src_data
->media_time
!= ISOM_EDIT_MODE_EMPTY
)
1883 dst_data
->media_time
= (src_data
->media_time
+ media_time_shift
) * ((double)dst_media_timescale
/ src_media_timescale
) + 0.5;
1885 dst_data
->media_time
= ISOM_EDIT_MODE_EMPTY
;
1886 if( lsmash_list_add_entry( dst_list
, dst_data
) < 0 )
1888 lsmash_free( dst_data
);
1889 return LSMASH_ERR_MEMORY_ALLOC
;
1891 src_entry
= src_entry
->next
;
1896 int lsmash_set_media_timestamps( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_media_ts_list_t
*ts_list
)
1898 if( LSMASH_IS_NON_EXISTING_BOX( root
)
1899 || LSMASH_IS_NON_EXISTING_BOX( root
->file
)
1902 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1904 return LSMASH_ERR_NAMELESS
;
1905 if( timeline
->info_list
->entry_count
== 0 )
1907 lsmash_log( timeline
, LSMASH_LOG_ERROR
, "Changing timestamps of LPCM track is not supported.\n" );
1908 return LSMASH_ERR_PATCH_WELCOME
;
1910 if( ts_list
->sample_count
!= timeline
->info_list
->entry_count
)
1911 return LSMASH_ERR_INVALID_DATA
; /* Number of samples must be same. */
1912 lsmash_media_ts_t
*ts
= ts_list
->timestamp
;
1914 return LSMASH_ERR_INVALID_DATA
; /* DTS must start from value zero. */
1916 uint32_t sample_count
= ts_list
->sample_count
;
1918 if( timeline
->info_list
->entry_count
> 1 )
1921 lsmash_entry_t
*entry
= timeline
->info_list
->head
;
1922 isom_sample_info_t
*info
= NULL
;
1923 while( i
< sample_count
)
1925 info
= (isom_sample_info_t
*)entry
->data
;
1926 if( !info
|| (ts
[i
].dts
< ts
[i
- 1].dts
) )
1927 return LSMASH_ERR_INVALID_DATA
;
1928 info
->duration
= ts
[i
].dts
- ts
[i
- 1].dts
;
1929 entry
= entry
->next
;
1936 return LSMASH_ERR_INVALID_DATA
;
1937 /* Copy the previous duration. */
1938 ((isom_sample_info_t
*)entry
->data
)->duration
= info
->duration
;
1941 return LSMASH_ERR_INVALID_DATA
; /* Irregular case: sample_count this timeline has is incorrect. */
1943 else /* still image */
1944 ((isom_sample_info_t
*)timeline
->info_list
->head
->data
)->duration
= UINT32_MAX
;
1946 * ToDo: hint track must not have any sample_offset. */
1948 timeline
->ctd_shift
= 0;
1949 for( lsmash_entry_t
*entry
= timeline
->info_list
->head
; entry
; entry
= entry
->next
)
1951 isom_sample_info_t
*info
= (isom_sample_info_t
*)entry
->data
;
1952 if( ts
[i
].cts
!= LSMASH_TIMESTAMP_UNDEFINED
)
1954 if( (ts
[i
].cts
+ timeline
->ctd_shift
) < ts
[i
].dts
)
1955 timeline
->ctd_shift
= ts
[i
].dts
- ts
[i
].cts
;
1956 info
->offset
= ts
[i
].cts
- ts
[i
].dts
;
1959 info
->offset
= ISOM_NON_OUTPUT_SAMPLE_OFFSET
;
1962 if( timeline
->ctd_shift
&& (!root
->file
->qt_compatible
|| root
->file
->max_isom_version
< 4) )
1963 return LSMASH_ERR_INVALID_DATA
; /* Don't allow composition to decode timeline shift. */
1967 int lsmash_get_media_timestamps( lsmash_root_t
*root
, uint32_t track_ID
, lsmash_media_ts_list_t
*ts_list
)
1970 return LSMASH_ERR_FUNCTION_PARAM
;
1971 isom_timeline_t
*timeline
= isom_get_timeline( root
, track_ID
);
1973 return LSMASH_ERR_NAMELESS
;
1974 uint32_t sample_count
= timeline
->info_list
->entry_count
;
1975 if( sample_count
== 0 )
1977 ts_list
->sample_count
= 0;
1978 ts_list
->timestamp
= NULL
;
1981 lsmash_media_ts_t
*ts
= lsmash_malloc( sample_count
* sizeof(lsmash_media_ts_t
) );
1983 return LSMASH_ERR_MEMORY_ALLOC
;
1986 if( timeline
->info_list
->entry_count
)
1987 for( lsmash_entry_t
*entry
= timeline
->info_list
->head
; entry
; entry
= entry
->next
)
1989 isom_sample_info_t
*info
= (isom_sample_info_t
*)entry
->data
;
1993 return LSMASH_ERR_NAMELESS
;
1996 ts
[i
].cts
= isom_make_cts( dts
, info
->offset
, timeline
->ctd_shift
);
1997 dts
+= info
->duration
;
2001 for( lsmash_entry_t
*entry
= timeline
->bunch_list
->head
; entry
; entry
= entry
->next
)
2003 isom_lpcm_bunch_t
*bunch
= (isom_lpcm_bunch_t
*)entry
->data
;
2007 return LSMASH_ERR_NAMELESS
;
2009 for( uint32_t j
= 0; j
< bunch
->sample_count
; j
++ )
2012 ts
[i
].cts
= isom_make_cts( dts
, bunch
->offset
, timeline
->ctd_shift
);
2013 dts
+= bunch
->duration
;
2017 ts_list
->sample_count
= sample_count
;
2018 ts_list
->timestamp
= ts
;
2022 void lsmash_delete_media_timestamps( lsmash_media_ts_list_t
*ts_list
)
2026 lsmash_freep( &ts_list
->timestamp
);
2027 ts_list
->sample_count
= 0;
2030 static int isom_compare_dts( const lsmash_media_ts_t
*a
, const lsmash_media_ts_t
*b
)
2032 int64_t diff
= (int64_t)(a
->dts
- b
->dts
);
2033 return diff
> 0 ? 1 : (diff
== 0 ? 0 : -1);
2036 void lsmash_sort_timestamps_decoding_order( lsmash_media_ts_list_t
*ts_list
)
2040 qsort( ts_list
->timestamp
, ts_list
->sample_count
, sizeof(lsmash_media_ts_t
), (int(*)( const void *, const void * ))isom_compare_dts
);
2043 static int isom_compare_cts( const lsmash_media_ts_t
*a
, const lsmash_media_ts_t
*b
)
2045 int64_t diff
= (int64_t)(a
->cts
- b
->cts
);
2046 return diff
> 0 ? 1 : (diff
== 0 ? 0 : -1);
2049 void lsmash_sort_timestamps_composition_order( lsmash_media_ts_list_t
*ts_list
)
2053 qsort( ts_list
->timestamp
, ts_list
->sample_count
, sizeof(lsmash_media_ts_t
), (int(*)( const void *, const void * ))isom_compare_cts
);
2056 int lsmash_get_max_sample_delay( lsmash_media_ts_list_t
*ts_list
, uint32_t *max_sample_delay
)
2058 if( !ts_list
|| !max_sample_delay
)
2059 return LSMASH_ERR_FUNCTION_PARAM
;
2060 lsmash_media_ts_t
*orig_ts
= ts_list
->timestamp
;
2061 lsmash_media_ts_t
*ts
= lsmash_malloc( ts_list
->sample_count
* sizeof(lsmash_media_ts_t
) );
2063 return LSMASH_ERR_MEMORY_ALLOC
;
2064 ts_list
->timestamp
= ts
;
2065 *max_sample_delay
= 0;
2066 for( uint32_t i
= 0; i
< ts_list
->sample_count
; i
++ )
2068 ts
[i
].cts
= orig_ts
[i
].cts
; /* for sorting */
2071 lsmash_sort_timestamps_composition_order( ts_list
);
2072 for( uint32_t i
= 0; i
< ts_list
->sample_count
; i
++ )
2075 uint32_t sample_delay
= ts
[i
].dts
- i
;
2076 *max_sample_delay
= LSMASH_MAX( *max_sample_delay
, sample_delay
);
2079 ts_list
->timestamp
= orig_ts
;