1 /*****************************************************************************
2  * timeline.c
3  *****************************************************************************
4  * Copyright (C) 2011-2017 L-SMASH project
5  *
6  * Authors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
7  *
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.
11  *
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  *****************************************************************************/
20 
21 /* This file is available under an ISC license. */
22 
23 #include "common/internal.h" /* must be placed first */
24 
25 #include <stdlib.h>
26 #include <string.h>
27 #include <inttypes.h>
28 
29 #include "box.h"
30 #include "timeline.h"
31 
32 #include "codecs/mp4a.h"
33 #include "codecs/mp4sys.h"
34 #include "codecs/description.h"
35 
36 #include "importer/importer.h"
37 
38 #define NO_RANDOM_ACCESS_POINT 0xffffffff
39 
40 typedef struct
41 {
42     uint64_t pos;
43     uint32_t duration;
44     uint32_t offset;
45     uint32_t length;
46     uint32_t index;
47     isom_portable_chunk_t *chunk;
48     lsmash_sample_property_t prop;
49 } isom_sample_info_t;
50 
51 static const lsmash_class_t lsmash_timeline_class =
52 {
53     "timeline"
54 };
55 
56 struct isom_timeline_tag
57 {
58     const lsmash_class_t *class;
59     uint32_t track_ID;
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 );
85 };
86 
isom_get_timeline(lsmash_root_t * root,uint32_t track_ID)87 isom_timeline_t *isom_get_timeline( lsmash_root_t *root, uint32_t track_ID )
88 {
89     if( isom_check_initializer_present( root ) < 0
90      || track_ID == 0
91      || !root->file->timeline )
92         return NULL;
93     for( lsmash_entry_t *entry = root->file->timeline->head; entry; entry = entry->next )
94     {
95         isom_timeline_t *timeline = (isom_timeline_t *)entry->data;
96         if( !timeline )
97             return NULL;
98         if( timeline->track_ID == track_ID )
99             return timeline;
100     }
101     return NULL;
102 }
103 
isom_timeline_create(void)104 isom_timeline_t *isom_timeline_create( void )
105 {
106     isom_timeline_t *timeline = lsmash_malloc_zero( sizeof(isom_timeline_t) );
107     if( !timeline )
108         return NULL;
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 );
114     return timeline;
115 }
116 
isom_timeline_destroy(isom_timeline_t * timeline)117 void isom_timeline_destroy( isom_timeline_t *timeline )
118 {
119     if( !timeline )
120         return;
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 );
126 }
127 
isom_remove_timelines(lsmash_file_t * file)128 void isom_remove_timelines( lsmash_file_t *file )
129 {
130     if( LSMASH_IS_NON_EXISTING_BOX( file ) || !file->timeline )
131         return;
132     lsmash_list_destroy( file->timeline );
133 }
134 
lsmash_destruct_timeline(lsmash_root_t * root,uint32_t track_ID)135 void lsmash_destruct_timeline( lsmash_root_t *root, uint32_t track_ID )
136 {
137     if( LSMASH_IS_NON_EXISTING_BOX( root )
138      || track_ID == 0
139      || !root->file->timeline )
140         return;
141     for( lsmash_entry_t *entry = root->file->timeline->head; entry; entry = entry->next )
142     {
143         isom_timeline_t *timeline = (isom_timeline_t *)entry->data;
144         if( !timeline )
145             continue;
146         if( timeline->track_ID == track_ID )
147         {
148             lsmash_list_remove_entry_direct( root->file->timeline, entry );
149             break;
150         }
151     }
152 }
153 
isom_timeline_set_track_ID(isom_timeline_t * timeline,uint32_t track_ID)154 int isom_timeline_set_track_ID
155 (
156     isom_timeline_t *timeline,
157     uint32_t         track_ID
158 )
159 {
160     if( !timeline || track_ID == 0 )
161         return LSMASH_ERR_FUNCTION_PARAM;
162     timeline->track_ID = track_ID;
163     return 0;
164 }
165 
isom_timeline_set_movie_timescale(isom_timeline_t * timeline,uint32_t movie_timescale)166 int isom_timeline_set_movie_timescale
167 (
168     isom_timeline_t *timeline,
169     uint32_t         movie_timescale
170 )
171 {
172     if( !timeline || movie_timescale == 0 )
173         return LSMASH_ERR_FUNCTION_PARAM;
174     timeline->movie_timescale = movie_timescale;
175     return 0;
176 }
177 
isom_timeline_set_media_timescale(isom_timeline_t * timeline,uint32_t media_timescale)178 int isom_timeline_set_media_timescale
179 (
180     isom_timeline_t *timeline,
181     uint32_t         media_timescale
182 )
183 {
184     if( !timeline || media_timescale == 0 )
185         return LSMASH_ERR_FUNCTION_PARAM;
186     timeline->media_timescale = media_timescale;
187     return 0;
188 }
189 
isom_timeline_set_sample_count(isom_timeline_t * timeline,uint32_t sample_count)190 int isom_timeline_set_sample_count
191 (
192     isom_timeline_t *timeline,
193     uint32_t         sample_count
194 )
195 {
196     if( !timeline || sample_count == 0 )
197         return LSMASH_ERR_FUNCTION_PARAM;
198     timeline->sample_count = sample_count;
199     return 0;
200 }
201 
isom_timeline_set_max_sample_size(isom_timeline_t * timeline,uint32_t max_sample_size)202 int isom_timeline_set_max_sample_size
203 (
204     isom_timeline_t *timeline,
205     uint32_t         max_sample_size
206 )
207 {
208     if( !timeline || max_sample_size == 0 )
209         return LSMASH_ERR_FUNCTION_PARAM;
210     timeline->max_sample_size = max_sample_size;
211     return 0;
212 }
213 
isom_timeline_set_media_duration(isom_timeline_t * timeline,uint32_t media_duration)214 int isom_timeline_set_media_duration
215 (
216     isom_timeline_t *timeline,
217     uint32_t         media_duration
218 )
219 {
220     if( !timeline || media_duration == 0 )
221         return LSMASH_ERR_FUNCTION_PARAM;
222     timeline->media_duration = media_duration;
223     return 0;
224 }
225 
isom_timeline_set_track_duration(isom_timeline_t * timeline,uint32_t track_duration)226 int isom_timeline_set_track_duration
227 (
228     isom_timeline_t *timeline,
229     uint32_t         track_duration
230 )
231 {
232     if( !timeline || track_duration == 0 )
233         return LSMASH_ERR_FUNCTION_PARAM;
234     timeline->track_duration = track_duration;
235     return 0;
236 }
237 
isom_get_qt_fixed_comp_audio_sample_quants(isom_timeline_t * timeline,isom_sample_entry_t * description,uint32_t * samples_per_packet,uint32_t * constant_sample_size)238 static void isom_get_qt_fixed_comp_audio_sample_quants
239 (
240     isom_timeline_t     *timeline,
241     isom_sample_entry_t *description,
242     uint32_t            *samples_per_packet,
243     uint32_t            *constant_sample_size
244 )
245 {
246     isom_audio_entry_t *audio = (isom_audio_entry_t *)description;
247     if( audio->version == 0 )
248     {
249         uint32_t dummy;
250         if( !isom_get_implicit_qt_fixed_comp_audio_sample_quants( audio, samples_per_packet, constant_sample_size, &dummy ) )
251         {
252             /* LPCM */
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;
257         }
258     }
259     else if( audio->version == 1 )
260     {
261         *samples_per_packet   = audio->samplesPerPacket;
262         *constant_sample_size = audio->bytesPerFrame;
263     }
264     else /* if( audio->version == 2 ) */
265     {
266         *samples_per_packet   = audio->constLPCMFramesPerAudioPacket;
267         *constant_sample_size = audio->constBytesPerAudioPacket;
268     }
269 }
270 
isom_is_qt_fixed_compressed_audio(isom_sample_entry_t * description)271 static int isom_is_qt_fixed_compressed_audio
272 (
273     isom_sample_entry_t *description
274 )
275 {
276     if( (description->manager & LSMASH_VIDEO_DESCRIPTION) || !isom_is_qt_audio( description->type ) )
277         return 0;
278     /* LPCM is a special case of fixed compression. */
279     return (((isom_audio_entry_t *)description)->compression_ID != QT_AUDIO_COMPRESSION_ID_VARIABLE_COMPRESSION);
280 }
281 
isom_add_sample_info_entry(isom_timeline_t * timeline,isom_sample_info_t * src_info)282 static int isom_add_sample_info_entry( isom_timeline_t *timeline, isom_sample_info_t *src_info )
283 {
284     isom_sample_info_t *dst_info = lsmash_malloc( sizeof(isom_sample_info_t) );
285     if( !dst_info )
286         return LSMASH_ERR_MEMORY_ALLOC;
287     if( lsmash_list_add_entry( timeline->info_list, dst_info ) < 0 )
288     {
289         lsmash_free( dst_info );
290         return LSMASH_ERR_MEMORY_ALLOC;
291     }
292     *dst_info = *src_info;
293     return 0;
294 }
295 
isom_add_lpcm_bunch_entry(isom_timeline_t * timeline,isom_lpcm_bunch_t * src_bunch)296 int isom_add_lpcm_bunch_entry( isom_timeline_t *timeline, isom_lpcm_bunch_t *src_bunch )
297 {
298     isom_lpcm_bunch_t *dst_bunch = lsmash_malloc( sizeof(isom_lpcm_bunch_t) );
299     if( !dst_bunch )
300         return LSMASH_ERR_MEMORY_ALLOC;
301     if( lsmash_list_add_entry( timeline->bunch_list, dst_bunch ) < 0 )
302     {
303         lsmash_free( dst_bunch );
304         return LSMASH_ERR_MEMORY_ALLOC;
305     }
306     *dst_bunch = *src_bunch;
307     return 0;
308 }
309 
isom_add_portable_chunk_entry(isom_timeline_t * timeline,isom_portable_chunk_t * src_chunk)310 static int isom_add_portable_chunk_entry( isom_timeline_t *timeline, isom_portable_chunk_t *src_chunk )
311 {
312     isom_portable_chunk_t *dst_chunk = lsmash_malloc( sizeof(isom_portable_chunk_t) );
313     if( !dst_chunk )
314         return LSMASH_ERR_MEMORY_ALLOC;
315     if( lsmash_list_add_entry( timeline->chunk_list, dst_chunk ) < 0 )
316     {
317         lsmash_free( dst_chunk );
318         return LSMASH_ERR_MEMORY_ALLOC;
319     }
320     *dst_chunk = *src_chunk;
321     return 0;
322 }
323 
isom_compare_lpcm_sample_info(isom_lpcm_bunch_t * bunch,isom_sample_info_t * info)324 static int isom_compare_lpcm_sample_info( isom_lpcm_bunch_t *bunch, isom_sample_info_t *info )
325 {
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;
331 }
332 
isom_update_bunch(isom_lpcm_bunch_t * bunch,isom_sample_info_t * info)333 static void isom_update_bunch( isom_lpcm_bunch_t *bunch, isom_sample_info_t *info )
334 {
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;
343 }
344 
isom_get_bunch(isom_timeline_t * timeline,uint32_t sample_number)345 static isom_lpcm_bunch_t *isom_get_bunch( isom_timeline_t *timeline, uint32_t sample_number )
346 {
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;
353     uint64_t bunch_dts;
354     if( timeline->last_accessed_lpcm_bunch_first_sample_number
355      && timeline->last_accessed_lpcm_bunch_first_sample_number <= sample_number )
356     {
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;
361     }
362     else
363     {
364         /* Seek from the first LPCM bunch. */
365         first_sample_number_in_next_bunch = 1;
366         bunch_dts = 0;
367     }
368     isom_lpcm_bunch_t *bunch = (isom_lpcm_bunch_t *)lsmash_list_get_entry_data( timeline->bunch_list, bunch_number++ );
369     if( !bunch )
370         return NULL;
371     first_sample_number_in_next_bunch += bunch->sample_count;
372     while( sample_number >= first_sample_number_in_next_bunch )
373     {
374         bunch_dts += bunch->duration * bunch->sample_count;
375         bunch = (isom_lpcm_bunch_t *)lsmash_list_get_entry_data( timeline->bunch_list, bunch_number++ );
376         if( !bunch )
377             return NULL;
378         first_sample_number_in_next_bunch += bunch->sample_count;
379     }
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;
385     return bunch;
386 }
387 
isom_get_dts_from_info_list(isom_timeline_t * timeline,uint32_t sample_number,uint64_t * dts)388 static int isom_get_dts_from_info_list( isom_timeline_t *timeline, uint32_t sample_number, uint64_t *dts )
389 {
390     if( sample_number == timeline->last_accessed_sample_number )
391         *dts = timeline->last_accessed_sample_dts;
392     else if( sample_number == 1 )
393         *dts = 0;
394     else if( sample_number == timeline->last_accessed_sample_number + 1 )
395     {
396         isom_sample_info_t *info = (isom_sample_info_t *)lsmash_list_get_entry_data( timeline->info_list, timeline->last_accessed_sample_number );
397         if( !info )
398             return LSMASH_ERR_NAMELESS;
399         *dts = timeline->last_accessed_sample_dts + info->duration;
400     }
401     else if( sample_number == timeline->last_accessed_sample_number - 1 )
402     {
403         isom_sample_info_t *info = (isom_sample_info_t *)lsmash_list_get_entry_data( timeline->info_list, timeline->last_accessed_sample_number - 1 );
404         if( !info )
405             return LSMASH_ERR_NAMELESS;
406         *dts = timeline->last_accessed_sample_dts - info->duration;
407     }
408     else
409     {
410         *dts = 0;
411         uint32_t distance = sample_number - 1;
412         lsmash_entry_t *entry;
413         for( entry = timeline->info_list->head; entry; entry = entry->next )
414         {
415             isom_sample_info_t *info = (isom_sample_info_t *)entry->data;
416             if( !info )
417                 return LSMASH_ERR_NAMELESS;
418             if( distance-- == 0 )
419                 break;
420             *dts += info->duration;
421         }
422         if( !entry )
423             return LSMASH_ERR_NAMELESS;
424     }
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;
428     return 0;
429 }
430 
isom_get_cts_from_info_list(isom_timeline_t * timeline,uint32_t sample_number,uint64_t * cts)431 static int isom_get_cts_from_info_list( isom_timeline_t *timeline, uint32_t sample_number, uint64_t *cts )
432 {
433     int ret = isom_get_dts_from_info_list( timeline, sample_number, cts );
434     if( ret < 0 )
435         return ret;
436     isom_sample_info_t *info = (isom_sample_info_t *)lsmash_list_get_entry_data( timeline->info_list, sample_number );
437     if( !info )
438         return LSMASH_ERR_NAMELESS;
439     *cts = isom_make_cts( *cts, info->offset, timeline->ctd_shift );
440     return 0;
441 }
442 
isom_get_dts_from_bunch_list(isom_timeline_t * timeline,uint32_t sample_number,uint64_t * dts)443 static int isom_get_dts_from_bunch_list( isom_timeline_t *timeline, uint32_t sample_number, uint64_t *dts )
444 {
445     isom_lpcm_bunch_t *bunch = isom_get_bunch( timeline, sample_number );
446     if( !bunch )
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;
449     return 0;
450 }
451 
isom_get_cts_from_bunch_list(isom_timeline_t * timeline,uint32_t sample_number,uint64_t * cts)452 static int isom_get_cts_from_bunch_list( isom_timeline_t *timeline, uint32_t sample_number, uint64_t *cts )
453 {
454     isom_lpcm_bunch_t *bunch = isom_get_bunch( timeline, sample_number );
455     if( !bunch )
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;
458     return 0;
459 }
460 
isom_get_sample_duration_from_info_list(isom_timeline_t * timeline,uint32_t sample_number,uint32_t * sample_duration)461 static int isom_get_sample_duration_from_info_list( isom_timeline_t *timeline, uint32_t sample_number, uint32_t *sample_duration )
462 {
463     isom_sample_info_t *info = (isom_sample_info_t *)lsmash_list_get_entry_data( timeline->info_list, sample_number );
464     if( !info )
465         return LSMASH_ERR_NAMELESS;
466     *sample_duration = info->duration;
467     return 0;
468 }
469 
isom_get_sample_duration_from_bunch_list(isom_timeline_t * timeline,uint32_t sample_number,uint32_t * sample_duration)470 static int isom_get_sample_duration_from_bunch_list( isom_timeline_t *timeline, uint32_t sample_number, uint32_t *sample_duration )
471 {
472     isom_lpcm_bunch_t *bunch = isom_get_bunch( timeline, sample_number );
473     if( !bunch )
474         return LSMASH_ERR_NAMELESS;
475     *sample_duration = bunch->duration;
476     return 0;
477 }
478 
isom_check_sample_existence_in_info_list(isom_timeline_t * timeline,uint32_t sample_number)479 static int isom_check_sample_existence_in_info_list( isom_timeline_t *timeline, uint32_t sample_number )
480 {
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 )
483         return 0;
484     return !!info->chunk->file;
485 }
486 
isom_check_sample_existence_in_bunch_list(isom_timeline_t * timeline,uint32_t sample_number)487 static int isom_check_sample_existence_in_bunch_list( isom_timeline_t *timeline, uint32_t sample_number )
488 {
489     isom_lpcm_bunch_t *bunch = isom_get_bunch( timeline, sample_number );
490     if( !bunch || !bunch->chunk )
491         return 0;
492     return !!bunch->chunk->file;
493 }
494 
isom_read_sample_data_from_stream(lsmash_file_t * file,isom_timeline_t * timeline,uint32_t sample_length,uint64_t sample_pos)495 static lsmash_sample_t *isom_read_sample_data_from_stream
496 (
497     lsmash_file_t   *file,
498     isom_timeline_t *timeline,
499     uint32_t         sample_length,
500     uint64_t         sample_pos
501 )
502 {
503     if( !file )
504         return NULL;
505     lsmash_sample_t *sample = lsmash_create_sample( 0 );
506     if( !sample )
507         return NULL;
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 );
511     if( !sample->data )
512     {
513         lsmash_delete_sample( sample );
514         return NULL;
515     }
516     return sample;
517 }
518 
isom_get_lpcm_sample_from_media_timeline(isom_timeline_t * timeline,uint32_t sample_number)519 static lsmash_sample_t *isom_get_lpcm_sample_from_media_timeline( isom_timeline_t *timeline, uint32_t sample_number )
520 {
521     isom_lpcm_bunch_t *bunch = isom_get_bunch( timeline, sample_number );
522     if( !bunch
523      || !bunch->chunk )
524         return NULL;
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 );
529     if( !sample )
530         return NULL;
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;
538     return sample;
539 }
540 
isom_get_sample_from_media_timeline(isom_timeline_t * timeline,uint32_t sample_number)541 static lsmash_sample_t *isom_get_sample_from_media_timeline( isom_timeline_t *timeline, uint32_t sample_number )
542 {
543     uint64_t dts;
544     if( isom_get_dts_from_info_list( timeline, sample_number, &dts ) < 0 )
545         return NULL;
546     isom_sample_info_t *info = (isom_sample_info_t *)lsmash_list_get_entry_data( timeline->info_list, sample_number );
547     if( !info
548      || !info->chunk )
549         return NULL;
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 );
552     if( !sample )
553         return NULL;
554     /* Get sample info. */
555     sample->dts    = dts;
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;
561     return sample;
562 }
563 
isom_get_lpcm_sample_info_from_media_timeline(isom_timeline_t * timeline,uint32_t sample_number,lsmash_sample_t * sample)564 static int isom_get_lpcm_sample_info_from_media_timeline( isom_timeline_t *timeline, uint32_t sample_number, lsmash_sample_t *sample )
565 {
566     isom_lpcm_bunch_t *bunch = isom_get_bunch( timeline, sample_number );
567     if( !bunch )
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;
576     return 0;
577 }
578 
isom_get_sample_info_from_media_timeline(isom_timeline_t * timeline,uint32_t sample_number,lsmash_sample_t * sample)579 static int isom_get_sample_info_from_media_timeline( isom_timeline_t *timeline, uint32_t sample_number, lsmash_sample_t *sample )
580 {
581     uint64_t dts;
582     int ret = isom_get_dts_from_info_list( timeline, sample_number, &dts );
583     if( ret < 0 )
584         return ret;
585     isom_sample_info_t *info = (isom_sample_info_t *)lsmash_list_get_entry_data( timeline->info_list, sample_number );
586     if( !info )
587         return LSMASH_ERR_NAMELESS;
588     sample->dts    = dts;
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;
594     return 0;
595 }
596 
isom_get_lpcm_sample_property_from_media_timeline(isom_timeline_t * timeline,uint32_t sample_number,lsmash_sample_property_t * 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 )
598 {
599     memset( prop, 0, sizeof(lsmash_sample_property_t) );
600     prop->ra_flags = ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC;
601     return 0;
602 }
603 
isom_get_sample_property_from_media_timeline(isom_timeline_t * timeline,uint32_t sample_number,lsmash_sample_property_t * prop)604 static int isom_get_sample_property_from_media_timeline( isom_timeline_t *timeline, uint32_t sample_number, lsmash_sample_property_t *prop )
605 {
606     isom_sample_info_t *info = (isom_sample_info_t *)lsmash_list_get_entry_data( timeline->info_list, sample_number );
607     if( !info )
608         return LSMASH_ERR_NAMELESS;
609     *prop = info->prop;
610     return 0;
611 }
612 
isom_timeline_set_sample_getter_funcs(isom_timeline_t * timeline)613 static void isom_timeline_set_sample_getter_funcs
614 (
615     isom_timeline_t *timeline
616 )
617 {
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;
625 }
626 
isom_timeline_set_lpcm_sample_getter_funcs(isom_timeline_t * timeline)627 void isom_timeline_set_lpcm_sample_getter_funcs
628 (
629     isom_timeline_t *timeline
630 )
631 {
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;
639 }
640 
isom_increment_sample_number_in_entry(uint32_t * sample_number_in_entry,lsmash_entry_t ** entry,uint32_t sample_count)641 static inline void isom_increment_sample_number_in_entry
642 (
643     uint32_t        *sample_number_in_entry,
644     lsmash_entry_t **entry,
645     uint32_t         sample_count
646 )
647 {
648     if( *sample_number_in_entry == sample_count )
649     {
650         *sample_number_in_entry = 1;
651         *entry = (*entry)->next;
652     }
653     else
654         *sample_number_in_entry += 1;
655 }
656 
isom_select_appropriate_sgpd(isom_sgpd_t * sgpd,isom_sgpd_t * sgpd_frag,uint32_t * group_description_index)657 static inline isom_sgpd_t *isom_select_appropriate_sgpd
658 (
659     isom_sgpd_t *sgpd,
660     isom_sgpd_t *sgpd_frag,
661     uint32_t    *group_description_index
662 )
663 {
664     if( LSMASH_IS_EXISTING_BOX( sgpd_frag ) && *group_description_index >= 0x10000 )
665     {
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;
670         return sgpd_frag;
671     }
672     else
673         return sgpd;
674 }
675 
isom_get_roll_recovery_grouping_info(isom_timeline_t * timeline,lsmash_entry_t ** sbgp_roll_entry,isom_sgpd_t * sgpd_roll,isom_sgpd_t * sgpd_frag_roll,uint32_t * sample_number_in_sbgp_roll_entry,isom_sample_info_t * info,uint32_t sample_number)676 static int isom_get_roll_recovery_grouping_info
677 (
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
685 )
686 {
687     isom_group_assignment_entry_t *assignment = (isom_group_assignment_entry_t *)(*sbgp_roll_entry)->data;
688     if( !assignment )
689         return LSMASH_ERR_NAMELESS;
690     if( assignment->group_description_index )
691     {
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 );
695         if( roll_data )
696         {
697             if( roll_data->roll_distance > 0 )
698             {
699                 /* post-roll */
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;
703             }
704             else if( roll_data->roll_distance < 0 )
705             {
706                 /* pre-roll */
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;
710             }
711         }
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" );
714     }
715     isom_increment_sample_number_in_entry( sample_number_in_sbgp_roll_entry, sbgp_roll_entry, assignment->sample_count );
716     return 0;
717 }
718 
isom_get_random_access_point_grouping_info(isom_timeline_t * timeline,lsmash_entry_t ** sbgp_rap_entry,isom_sgpd_t * sgpd_rap,isom_sgpd_t * sgpd_frag_rap,uint32_t * sample_number_in_sbgp_rap_entry,isom_sample_info_t * info,uint32_t * distance)719 static int isom_get_random_access_point_grouping_info
720 (
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,
727     uint32_t           *distance
728 )
729 {
730     isom_group_assignment_entry_t *assignment = (isom_group_assignment_entry_t *)(*sbgp_rap_entry)->data;
731     if( !assignment )
732         return LSMASH_ERR_NAMELESS;
733     if( assignment->group_description_index && (info->prop.ra_flags == ISOM_SAMPLE_RANDOM_ACCESS_FLAG_NONE) )
734     {
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 );
738         if( rap_data )
739         {
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;
744             *distance = 0;
745         }
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" );
748     }
749     isom_increment_sample_number_in_entry( sample_number_in_sbgp_rap_entry, sbgp_rap_entry, assignment->sample_count );
750     return 0;
751 }
752 
isom_timeline_construct(lsmash_root_t * root,uint32_t track_ID)753 int isom_timeline_construct( lsmash_root_t *root, uint32_t track_ID )
754 {
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 )
772     {
773         file->timeline = lsmash_list_create( isom_timeline_destroy );
774         if( !file->timeline )
775             return LSMASH_ERR_MEMORY_ALLOC;
776     }
777     /* Create a timeline. */
778     isom_timeline_t *timeline = isom_timeline_create();
779     if( !timeline )
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)) )
821         goto fail;
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 ) )
824         goto fail;
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;
837     uint64_t dts               = 0;
838     uint32_t chunk_number      = 1;
839     uint64_t offset_from_chunk = 0;
840     uint64_t data_offset = stco_entry && stco_entry->data
841                          ? large_presentation
842                              ? ((isom_co64_entry_t *)stco_entry->data)->chunk_offset
843                              : ((isom_stco_entry_t *)stco_entry->data)->chunk_offset
844                          : 0;
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 );
850     else
851     {
852         samples_per_packet   = 1;
853         constant_sample_size = stsz ? stsz->sample_size : 0;
854     }
855     uint32_t sample_number          = samples_per_packet;
856     uint32_t sample_number_in_chunk = samples_per_packet;
857     /* Copy edits. */
858     while( elst_entry )
859     {
860         isom_elst_entry_t *edit = (isom_elst_entry_t *)lsmash_memdup( elst_entry->data, sizeof(isom_elst_entry_t) );
861         if( !edit
862          || lsmash_list_add_entry( timeline->edit_list, edit ) < 0 )
863         {
864             err = LSMASH_ERR_MEMORY_ALLOC;
865             goto fail;
866         }
867         elst_entry = elst_entry->next;
868     }
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 )
872     {
873         while( sdtp_entry )
874         {
875             isom_sdtp_entry_t *sdtp_data = (isom_sdtp_entry_t *)sdtp_entry->data;
876             if( !sdtp_data )
877                 goto fail;
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) )
881             {
882                 /* Obviously, it's not defined under ISO Base Media. */
883                 iso_sdtp = 0;
884                 break;
885             }
886             sdtp_entry = sdtp_entry->next;
887         }
888         sdtp_entry = sdtp->list->head;
889     }
890     /**--- Construct media timeline. ---**/
891     isom_portable_chunk_t chunk;
892     chunk.data_offset = data_offset;
893     chunk.length      = 0;
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 )
897         goto fail;
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 )
903     {
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++ )
907         {
908             /* sample duration */
909             if( stts_entry )
910             {
911                 isom_stts_entry_t *stts_data = (isom_stts_entry_t *)stts_entry->data;
912                 if( !stts_data )
913                     goto fail;
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;
916             }
917             info.duration += last_duration;
918             dts           += last_duration;
919             /* sample offset */
920             uint32_t sample_offset;
921             if( ctts_entry )
922             {
923                 isom_ctts_entry_t *ctts_data = (isom_ctts_entry_t *)ctts_entry->data;
924                 if( !ctts_data )
925                     goto fail;
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 )
929                 {
930                     uint64_t cts = dts + (int32_t)sample_offset;
931                     if( (cts + timeline->ctd_shift) < dts )
932                         timeline->ctd_shift = dts - cts;
933                 }
934             }
935             else
936                 sample_offset = 0;
937             if( i == 0 )
938                 info.offset = sample_offset;
939         }
940         timeline->media_duration += info.duration;
941         if( !is_qt_fixed_comp_audio )
942         {
943             /* Check whether sync sample or not. */
944             if( stss_entry )
945             {
946                 isom_stss_entry_t *stss_data = (isom_stss_entry_t *)stss_entry->data;
947                 if( !stss_data )
948                     goto fail;
949                 if( sample_number == stss_data->sample_number )
950                 {
951                     info.prop.ra_flags |= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC;
952                     stss_entry = stss_entry->next;
953                     distance = 0;
954                 }
955             }
956             else if( all_sync )
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. */
961             if( stps_entry )
962             {
963                 isom_stps_entry_t *stps_data = (isom_stps_entry_t *)stps_entry->data;
964                 if( !stps_data )
965                     goto fail;
966                 if( sample_number == stps_data->sample_number )
967                 {
968                     info.prop.ra_flags |= QT_SAMPLE_RANDOM_ACCESS_FLAG_PARTIAL_SYNC | QT_SAMPLE_RANDOM_ACCESS_FLAG_RAP;
969                     stps_entry = stps_entry->next;
970                     distance = 0;
971                 }
972             }
973             /* Get sample dependency info. */
974             if( sdtp_entry )
975             {
976                 isom_sdtp_entry_t *sdtp_data = (isom_sdtp_entry_t *)sdtp_entry->data;
977                 if( !sdtp_data )
978                     goto fail;
979                 if( iso_sdtp )
980                     info.prop.leading       = sdtp_data->is_leading;
981                 else
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;
987             }
988             /* Get roll recovery grouping info. */
989             if( sbgp_roll_entry
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 )
994                 goto fail;
995             info.prop.post_roll.identifier = sample_number;
996             /* Get random access point grouping info. */
997             if( sbgp_rap_entry
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 )
1002                 goto fail;
1003             /* Set up distance from the previous random access point. */
1004             if( distance != NO_RANDOM_ACCESS_POINT )
1005             {
1006                 if( info.prop.pre_roll.distance == 0 )
1007                     info.prop.pre_roll.distance = distance;
1008                 ++distance;
1009             }
1010         }
1011         else
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;
1017         else
1018         {
1019             if( !stsz_entry->data )
1020                 goto fail;
1021             info.length = ((isom_stsz_entry_t *)stsz_entry->data)->entry_size;
1022             stsz_entry = stsz_entry->next;
1023         }
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 )
1031         {
1032             /* Set the length of the last chunk. */
1033             if( info.chunk )
1034                 info.chunk->length = offset_from_chunk;
1035             /* Move the next chunk. */
1036             if( stco_entry )
1037                 stco_entry = stco_entry->next;
1038             if( stco_entry
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;
1044             chunk.length      = 0;
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 )
1049             {
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;
1054                 if(  next_stsc_entry
1055                  && !next_stsc_entry->data )
1056                     goto fail;
1057             }
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 )
1060             {
1061                 stsc_entry      = next_stsc_entry;
1062                 next_stsc_entry = next_stsc_entry->next;
1063                 if(  next_stsc_entry
1064                  && !next_stsc_entry->data )
1065                     goto fail;
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 );
1073                 else
1074                 {
1075                     samples_per_packet   = 1;
1076                     constant_sample_size = stsz ? stsz->sample_size : 0;
1077                 }
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;
1081             }
1082             sample_number_in_chunk = samples_per_packet;
1083             if( (err = isom_add_portable_chunk_entry( timeline, &chunk )) < 0 )
1084                 goto fail;
1085         }
1086         else
1087         {
1088             data_offset            += info.length;
1089             sample_number_in_chunk += samples_per_packet;
1090         }
1091         /* OK. Let's add its info. */
1092         if( is_lpcm_audio )
1093         {
1094             if( sample_number == samples_per_packet )
1095                 isom_update_bunch( &bunch, &info );
1096             else if( isom_compare_lpcm_sample_info( &bunch, &info ) )
1097             {
1098                 if( (err = isom_add_lpcm_bunch_entry( timeline, &bunch )) < 0 )
1099                     goto fail;
1100                 isom_update_bunch( &bunch, &info );
1101             }
1102             else
1103                 ++ bunch.sample_count;
1104         }
1105         else if( (err = isom_add_sample_info_entry( timeline, &info )) < 0 )
1106             goto fail;
1107         if( timeline->info_list->entry_count && timeline->bunch_list->entry_count )
1108         {
1109             lsmash_log( timeline, LSMASH_LOG_ERROR, "LPCM + non-LPCM track is not supported.\n" );
1110             err = LSMASH_ERR_PATCH_WELCOME;
1111             goto fail;
1112         }
1113         sample_number += samples_per_packet;
1114         packet_number += 1;
1115     }
1116     isom_portable_chunk_t *last_chunk = lsmash_list_get_entry_data( timeline->chunk_list, timeline->chunk_list->entry_count );
1117     if( last_chunk )
1118     {
1119         if( offset_from_chunk )
1120             last_chunk->length = offset_from_chunk;
1121         else
1122         {
1123             /* Remove the last invalid chunk. */
1124             lsmash_list_remove_entry( timeline->chunk_list, timeline->chunk_list->entry_count );
1125             --chunk_number;
1126         }
1127     }
1128     uint32_t sample_count = packet_number - 1;
1129     if( movie_fragments_present )
1130     {
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;
1135         chunk.length      = 0;
1136         /* Movie fragments */
1137         for( lsmash_entry_t *moof_entry = file->moof_list.head; moof_entry; moof_entry = moof_entry->next )
1138         {
1139             isom_moof_t *moof = (isom_moof_t *)moof_entry->data;
1140             if( LSMASH_IS_NON_EXISTING_BOX( moof ) )
1141                 goto fail;
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 )
1146             {
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 ) )
1151                     goto fail;
1152                 /* Ignore ISOM_TF_FLAGS_DURATION_IS_EMPTY flag even if set. */
1153                 if( !traf->trun_list.head )
1154                 {
1155                     ++traf_number;
1156                     continue;
1157                 }
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;
1164                 else
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);
1176                 /* Track runs */
1177                 uint32_t trun_number = 1;
1178                 for( lsmash_entry_t *trun_entry = traf->trun_list.head; trun_entry; trun_entry = trun_entry->next )
1179                 {
1180                     isom_trun_t *trun = (isom_trun_t *)trun_entry->data;
1181                     if( LSMASH_IS_NON_EXISTING_BOX( trun ) )
1182                         goto fail;
1183                     if( trun->sample_count == 0 )
1184                     {
1185                         ++trun_number;
1186                         continue;
1187                     }
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;
1193                     else
1194                         data_offset = last_sample_end_pos;
1195                     /* */
1196                     uint32_t sample_description_index = 0;
1197                     isom_sdtp_entry_t *sdtp_data = NULL;
1198                     if( !need_data_offset_only )
1199                     {
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;
1203                         else
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 )
1213                         {
1214                             chunk.data_offset = data_offset;
1215                             chunk.length      = 0;
1216                             chunk.number      = ++chunk_number;
1217                             chunk.file        = ref_file;
1218                             if( (err = isom_add_portable_chunk_entry( timeline, &chunk )) < 0 )
1219                                 goto fail;
1220                         }
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;
1224                     }
1225                     /* Get info of each sample. */
1226                     lsmash_entry_t *row_entry = trun->optional && trun->optional->head ? trun->optional->head : NULL;
1227                     sample_number = 1;
1228                     while( sample_number <= trun->sample_count )
1229                     {
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;
1237                         else
1238                             info.length = trex->default_sample_size;
1239                         if( !need_data_offset_only )
1240                         {
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;
1250                             else
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) )
1254                             {
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 )
1258                                 {
1259                                     uint64_t cts = dts + (int32_t)info.offset;
1260                                     if( (cts + timeline->ctd_shift) < dts )
1261                                         timeline->ctd_shift = dts - cts;
1262                                 }
1263                             }
1264                             else
1265                                 info.offset = 0;
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 )
1271                             {
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;
1280                                 else
1281                                     sample_flags = trex->default_sample_flags;
1282                                 if( sdtp_data )
1283                                 {
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;
1292                                     if( sdtp_entry )
1293                                         sdtp_entry = sdtp_entry->next;
1294                                     sdtp_data = sdtp_entry ? (isom_sdtp_entry_t *)sdtp_entry->data : NULL;
1295                                 }
1296                                 else
1297                                 {
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;
1302                                 }
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 )
1307                                 {
1308                                     info.prop.ra_flags |= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC;
1309                                     distance = 0;
1310                                 }
1311                                 /* Get roll recovery grouping info. */
1312                                 uint32_t roll_id = sample_count + sample_number;
1313                                 if( sbgp_roll_entry
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 )
1318                                     goto fail;
1319                                 info.prop.post_roll.identifier = roll_id;
1320                                 /* Get random access point grouping info. */
1321                                 if( sbgp_rap_entry
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 )
1326                                     goto fail;
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 ) )
1330                                 {
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;
1334                                     if( rap
1335                                      && rap->moof_offset   == moof->pos
1336                                      && rap->traf_number   == traf_number
1337                                      && rap->trun_number   == trun_number
1338                                      && rap->sample_number == sample_number )
1339                                     {
1340                                         if( info.prop.ra_flags == ISOM_SAMPLE_RANDOM_ACCESS_FLAG_NONE )
1341                                             info.prop.ra_flags |= ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC;
1342                                         if( tfra_entry )
1343                                             tfra_entry = tfra_entry->next;
1344                                         rap = tfra_entry ? (isom_tfra_location_time_entry_t *)tfra_entry->data : NULL;
1345                                     }
1346                                 }
1347                                 /* Set up distance from the previous random access point. */
1348                                 if( distance != NO_RANDOM_ACCESS_POINT )
1349                                 {
1350                                     if( info.prop.pre_roll.distance == 0 )
1351                                         info.prop.pre_roll.distance = distance;
1352                                     ++distance;
1353                                 }
1354                                 /* OK. Let's add its info. */
1355                                 if( (err = isom_add_sample_info_entry( timeline, &info )) < 0 )
1356                                     goto fail;
1357                             }
1358                             else
1359                             {
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 ) )
1366                                 {
1367                                     if( (err = isom_add_lpcm_bunch_entry( timeline, &bunch )) < 0 )
1368                                         goto fail;
1369                                     isom_update_bunch( &bunch, &info );
1370                                 }
1371                                 else
1372                                     ++ bunch.sample_count;
1373                             }
1374                             if( timeline-> info_list->entry_count
1375                              && timeline->bunch_list->entry_count )
1376                             {
1377                                 lsmash_log( timeline, LSMASH_LOG_ERROR, "LPCM + non-LPCM track is not supported.\n" );
1378                                 err = LSMASH_ERR_PATCH_WELCOME;
1379                                 goto fail;
1380                             }
1381                         }
1382                         data_offset += info.length;
1383                         last_sample_end_pos = data_offset;
1384                         if( row_entry )
1385                             row_entry = row_entry->next;
1386                         ++sample_number;
1387                     }
1388                     if( !need_data_offset_only )
1389                         sample_count += sample_number - 1;
1390                     ++trun_number;
1391                 }   /* Track runs */
1392                 ++traf_number;
1393             }   /* Track fragments */
1394         }   /* Movie fragments */
1395     }
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 )
1399         goto fail;
1400     if( (err = lsmash_list_add_entry( file->timeline, timeline )) < 0 )
1401         goto fail;
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 );
1406     else
1407         isom_timeline_set_lpcm_sample_getter_funcs( timeline );
1408     return 0;
1409 fail:
1410     isom_timeline_destroy( timeline );
1411     return err;
1412 }
1413 
lsmash_construct_timeline(lsmash_root_t * root,uint32_t track_ID)1414 int lsmash_construct_timeline( lsmash_root_t *root, uint32_t track_ID )
1415 {
1416     if( LSMASH_IS_NON_EXISTING_BOX( root )
1417      || LSMASH_IS_NON_EXISTING_BOX( root->file )
1418      || track_ID == 0 )
1419         return LSMASH_ERR_FUNCTION_PARAM;
1420     uint32_t track_number;
1421     if( LSMASH_IS_EXISTING_BOX( root->file->initializer ) )
1422     {
1423         if( LSMASH_IS_NON_EXISTING_BOX( root->file->initializer->moov ) )
1424             return LSMASH_ERR_INVALID_DATA;
1425         track_number = 1;
1426         int track_found = 0;
1427         for( lsmash_entry_t *entry = root->file->initializer->moov->trak_list.head; entry; entry = entry->next )
1428         {
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 ) )
1432                 continue;
1433             if( trak->tkhd->track_ID == track_ID )
1434             {
1435                 track_found = 1;
1436                 break;
1437             }
1438             ++track_number;
1439         }
1440         if( !track_found )
1441             return LSMASH_ERR_NAMELESS;
1442     }
1443     else
1444         track_number = track_ID;
1445     return lsmash_importer_construct_timeline( root->file->importer, track_number );
1446 }
1447 
lsmash_get_dts_from_media_timeline(lsmash_root_t * root,uint32_t track_ID,uint32_t sample_number,uint64_t * dts)1448 int lsmash_get_dts_from_media_timeline( lsmash_root_t *root, uint32_t track_ID, uint32_t sample_number, uint64_t *dts )
1449 {
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 );
1456 }
1457 
lsmash_get_cts_from_media_timeline(lsmash_root_t * root,uint32_t track_ID,uint32_t sample_number,uint64_t * cts)1458 int lsmash_get_cts_from_media_timeline( lsmash_root_t *root, uint32_t track_ID, uint32_t sample_number, uint64_t *cts )
1459 {
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 );
1466 }
1467 
lsmash_get_sample_from_media_timeline(lsmash_root_t * root,uint32_t track_ID,uint32_t sample_number)1468 lsmash_sample_t *lsmash_get_sample_from_media_timeline( lsmash_root_t *root, uint32_t track_ID, uint32_t sample_number )
1469 {
1470     isom_timeline_t *timeline = isom_get_timeline( root, track_ID );
1471     return timeline ? timeline->get_sample( timeline, sample_number ) : NULL;
1472 }
1473 
lsmash_get_sample_info_from_media_timeline(lsmash_root_t * root,uint32_t track_ID,uint32_t sample_number,lsmash_sample_t * sample)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 )
1475 {
1476     if( !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;
1480 }
1481 
lsmash_get_sample_property_from_media_timeline(lsmash_root_t * root,uint32_t track_ID,uint32_t sample_number,lsmash_sample_property_t * prop)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 )
1483 {
1484     if( !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;
1488 }
1489 
lsmash_get_composition_to_decode_shift_from_media_timeline(lsmash_root_t * root,uint32_t track_ID,uint32_t * ctd_shift)1490 int lsmash_get_composition_to_decode_shift_from_media_timeline( lsmash_root_t *root, uint32_t track_ID, uint32_t *ctd_shift )
1491 {
1492     if( !ctd_shift )
1493         return LSMASH_ERR_FUNCTION_PARAM;
1494     isom_timeline_t *timeline = isom_get_timeline( root, track_ID );
1495     if( !timeline )
1496         return LSMASH_ERR_NAMELESS;
1497     *ctd_shift = timeline->ctd_shift;
1498     return 0;
1499 }
1500 
isom_get_closest_past_random_accessible_point_from_media_timeline(isom_timeline_t * timeline,uint32_t sample_number,uint32_t * rap_number)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 )
1502 {
1503     lsmash_entry_t *entry = lsmash_list_get_entry( timeline->info_list, sample_number-- );
1504     if( !entry
1505      || !entry->data )
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 )
1509     {
1510         entry = entry->prev;
1511         if( !entry
1512          || !entry->data )
1513             return LSMASH_ERR_NAMELESS;
1514         info = (isom_sample_info_t *)entry->data;
1515         --sample_number;
1516     }
1517     *rap_number = sample_number + 1;
1518     return 0;
1519 }
1520 
isom_get_closest_future_random_accessible_point_from_media_timeline(isom_timeline_t * timeline,uint32_t sample_number,uint32_t * rap_number)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 )
1522 {
1523     lsmash_entry_t *entry = lsmash_list_get_entry( timeline->info_list, sample_number++ );
1524     if( !entry
1525      || !entry->data )
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 )
1529     {
1530         entry = entry->next;
1531         if( !entry
1532          || !entry->data )
1533             return LSMASH_ERR_NAMELESS;
1534         info = (isom_sample_info_t *)entry->data;
1535         ++sample_number;
1536     }
1537     *rap_number = sample_number - 1;
1538     return 0;
1539 }
1540 
isom_get_closest_random_accessible_point_from_media_timeline_internal(isom_timeline_t * timeline,uint32_t sample_number,uint32_t * rap_number)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 )
1542 {
1543     if( !timeline )
1544         return LSMASH_ERR_NAMELESS;
1545     int ret;
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 )
1548         return ret;
1549     return 0;
1550 }
1551 
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)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 )
1553 {
1554     if( sample_number == 0 || !rap_number )
1555         return LSMASH_ERR_FUNCTION_PARAM;
1556     isom_timeline_t *timeline = isom_get_timeline( root, track_ID );
1557     if( !timeline )
1558         return LSMASH_ERR_NAMELESS;
1559     if( timeline->info_list->entry_count == 0 )
1560     {
1561         *rap_number = sample_number;    /* All LPCM is sync sample. */
1562         return 0;
1563     }
1564     return isom_get_closest_random_accessible_point_from_media_timeline_internal( timeline, sample_number, rap_number );
1565 }
1566 
lsmash_get_closest_random_accessible_point_detail_from_media_timeline(lsmash_root_t * root,uint32_t track_ID,uint32_t sample_number,uint32_t * rap_number,lsmash_random_access_flag * ra_flags,uint32_t * leading,uint32_t * distance)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 )
1569 {
1570     if( sample_number == 0 )
1571         return LSMASH_ERR_FUNCTION_PARAM;
1572     isom_timeline_t *timeline = isom_get_timeline( root, track_ID );
1573     if( !timeline )
1574         return LSMASH_ERR_NAMELESS;
1575     if( timeline->info_list->entry_count == 0 )
1576     {
1577         /* All LPCM is sync sample. */
1578         *rap_number = sample_number;
1579         if( ra_flags )
1580             *ra_flags = ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC;
1581         if( leading )
1582             *leading  = 0;
1583         if( distance )
1584             *distance = 0;
1585         return 0;
1586     }
1587     int ret = isom_get_closest_random_accessible_point_from_media_timeline_internal( timeline, sample_number, rap_number );
1588     if( ret < 0 )
1589         return ret;
1590     isom_sample_info_t *info = (isom_sample_info_t *)lsmash_list_get_entry_data( timeline->info_list, *rap_number );
1591     if( !info )
1592         return LSMASH_ERR_NAMELESS;
1593     if( ra_flags )
1594         *ra_flags = info->prop.ra_flags;
1595     if( leading )
1596         *leading  = 0;
1597     if( distance )
1598         *distance = 0;
1599     if( sample_number < *rap_number )
1600         /* Impossible to desire to decode the sample of given number correctly. */
1601         return 0;
1602     else if( !(info->prop.ra_flags & ISOM_SAMPLE_RANDOM_ACCESS_FLAG_GDR) )
1603     {
1604         if( leading )
1605         {
1606             /* Count leading samples. */
1607             uint32_t current_sample_number = *rap_number + 1;
1608             uint64_t dts;
1609             if( (ret = isom_get_dts_from_info_list( timeline, *rap_number, &dts )) < 0 )
1610                 return ret;
1611             uint64_t rap_cts = isom_make_cts_adjust( dts, info->offset, timeline->ctd_shift );
1612             do
1613             {
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++ );
1618                 if( !info )
1619                     break;
1620                 uint64_t cts = isom_make_cts_adjust( dts, info->offset, timeline->ctd_shift );
1621                 if( rap_cts != LSMASH_TIMESTAMP_UNDEFINED && rap_cts > cts )
1622                     ++ *leading;
1623             } while( 1 );
1624         }
1625         if( !distance || sample_number == *rap_number )
1626             return 0;
1627         /* Measure distance from the first closest non-recovery random accessible point to the second. */
1628         uint32_t prev_rap_number = *rap_number;
1629         do
1630         {
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. */
1633                 return 0;
1634             info = (isom_sample_info_t *)lsmash_list_get_entry_data( timeline->info_list, prev_rap_number );
1635             if( !info )
1636                 return LSMASH_ERR_NAMELESS;
1637             if( !(info->prop.ra_flags & ISOM_SAMPLE_RANDOM_ACCESS_FLAG_GDR) )
1638             {
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;
1641                 return 0;
1642             }
1643         } while( 1 );
1644     }
1645     if( !distance )
1646         return 0;
1647     /* Calculate roll-distance. */
1648     if( info->prop.pre_roll.distance )
1649     {
1650         /* Pre-roll recovery */
1651         uint32_t prev_rap_number = *rap_number;
1652         do
1653         {
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 )
1656             {
1657                 /* The previous random accessible point is not present.
1658                  * And sample of given number might be not able to decoded correctly. */
1659                 *distance = 0;
1660                 return 0;
1661             }
1662             if( prev_rap_number + info->prop.pre_roll.distance <= *rap_number )
1663             {
1664                 /*
1665                  *                                          |<---- pre-roll distance ---->|
1666                  *                                          |<--------- distance -------->|
1667                  * media +++++++++++++++++++++++++ *** +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1668                  *                  ^                       ^                             ^                    ^
1669                  *       random accessible point         starting point        random accessible point   given sample
1670                  *                                                                   (complete)
1671                  */
1672                 *distance = info->prop.pre_roll.distance;
1673                 return 0;
1674             }
1675             else if( !(info->prop.ra_flags & ISOM_SAMPLE_RANDOM_ACCESS_FLAG_GDR) )
1676             {
1677                 /*
1678                  *            |<------------ pre-roll distance ------------------>|
1679                  *                                      |<------ distance ------->|
1680                  * media ++++++++++++++++ *** ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1681                  *            ^                         ^                         ^                     ^
1682                  *                            random accessible point   random accessible point   given sample
1683                  *                                (starting point)            (complete)
1684                  */
1685                 *distance = *rap_number - prev_rap_number;
1686                 return 0;
1687             }
1688         } while( 1 );
1689     }
1690     /* Post-roll recovery */
1691     if( sample_number >= info->prop.post_roll.complete )
1692         /*
1693          *                  |<----- post-roll distance ----->|
1694          *            (distance = 0)
1695          * media +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1696          *                  ^                                ^            ^
1697          *       random accessible point                 complete     given sample
1698          *          (starting point)
1699          */
1700         return 0;
1701     uint32_t prev_rap_number = *rap_number;
1702     do
1703     {
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. */
1706             return 0;
1707         info = (isom_sample_info_t *)lsmash_list_get_entry_data( timeline->info_list, prev_rap_number );
1708         if( !info )
1709             return LSMASH_ERR_NAMELESS;
1710         if( !(info->prop.ra_flags & ISOM_SAMPLE_RANDOM_ACCESS_FLAG_GDR) || sample_number >= info->prop.post_roll.complete )
1711         {
1712             *distance = *rap_number - prev_rap_number;
1713             return 0;
1714         }
1715     } while( 1 );
1716 }
1717 
lsmash_check_sample_existence_in_media_timeline(lsmash_root_t * root,uint32_t track_ID,uint32_t sample_number)1718 int lsmash_check_sample_existence_in_media_timeline( lsmash_root_t *root, uint32_t track_ID, uint32_t sample_number )
1719 {
1720     isom_timeline_t *timeline = isom_get_timeline( root, track_ID );
1721     return timeline ? timeline->check_sample_existence( timeline, sample_number ) : 0;
1722 }
1723 
lsmash_get_last_sample_delta_from_media_timeline(lsmash_root_t * root,uint32_t track_ID,uint32_t * last_sample_delta)1724 int lsmash_get_last_sample_delta_from_media_timeline( lsmash_root_t *root, uint32_t track_ID, uint32_t *last_sample_delta )
1725 {
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;
1730 }
1731 
lsmash_get_sample_delta_from_media_timeline(lsmash_root_t * root,uint32_t track_ID,uint32_t sample_number,uint32_t * sample_delta)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 )
1733 {
1734     if( !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;
1738 }
1739 
lsmash_get_sample_count_in_media_timeline(lsmash_root_t * root,uint32_t track_ID)1740 uint32_t lsmash_get_sample_count_in_media_timeline( lsmash_root_t *root, uint32_t track_ID )
1741 {
1742     isom_timeline_t *timeline = isom_get_timeline( root, track_ID );
1743     if( !timeline )
1744         return 0;
1745     return timeline->sample_count;
1746 }
1747 
lsmash_get_max_sample_size_in_media_timeline(lsmash_root_t * root,uint32_t track_ID)1748 uint32_t lsmash_get_max_sample_size_in_media_timeline( lsmash_root_t *root, uint32_t track_ID )
1749 {
1750     isom_timeline_t *timeline = isom_get_timeline( root, track_ID );
1751     if( !timeline )
1752         return 0;
1753     return timeline->max_sample_size;
1754 }
1755 
lsmash_get_media_duration_from_media_timeline(lsmash_root_t * root,uint32_t track_ID)1756 uint64_t lsmash_get_media_duration_from_media_timeline( lsmash_root_t *root, uint32_t track_ID )
1757 {
1758     isom_timeline_t *timeline = isom_get_timeline( root, track_ID );
1759     if( !timeline )
1760         return 0;
1761     return timeline->media_duration;
1762 }
1763 
isom_timelime_get_explicit_timeline_map(lsmash_root_t * root,uint32_t track_ID,uint32_t edit_number)1764 isom_elst_entry_t *isom_timelime_get_explicit_timeline_map
1765 (
1766     lsmash_root_t *root,
1767     uint32_t       track_ID,
1768     uint32_t       edit_number
1769 )
1770 {
1771     isom_timeline_t *timeline = isom_get_timeline( root, track_ID );
1772     if( !timeline )
1773         return NULL;
1774     return lsmash_list_get_entry_data( timeline->edit_list, edit_number );
1775 }
1776 
isom_timelime_count_explicit_timeline_map(lsmash_root_t * root,uint32_t track_ID)1777 uint32_t isom_timelime_count_explicit_timeline_map
1778 (
1779     lsmash_root_t *root,
1780     uint32_t       track_ID
1781 )
1782 {
1783     isom_timeline_t *timeline = isom_get_timeline( root, track_ID );
1784     if( !timeline )
1785         return 0;
1786     return timeline->edit_list->entry_count;
1787 }
1788 
lsmash_copy_timeline_map(lsmash_root_t * dst,uint32_t dst_track_ID,lsmash_root_t * src,uint32_t src_track_ID)1789 int lsmash_copy_timeline_map( lsmash_root_t *dst, uint32_t dst_track_ID, lsmash_root_t *src, uint32_t src_track_ID )
1790 {
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
1815      || src_fragmented )
1816     {
1817         /* Get from constructed timeline instead of boxes. */
1818         isom_timeline_t *src_timeline = isom_get_timeline( src, src_track_ID );
1819         if( src_timeline
1820          && src_timeline->movie_timescale
1821          && src_timeline->media_timescale )
1822         {
1823             src_entry = src_timeline->edit_list->head;
1824             if( !src_entry )
1825                 return 0;
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;
1831         }
1832         else if( !src_fragmented )
1833             return LSMASH_ERR_NAMELESS;
1834     }
1835     if( !src_entry )
1836     {
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 )
1846             return 0;
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;
1853     }
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;
1863     while( src_entry )
1864     {
1865         isom_elst_entry_t *src_data = (isom_elst_entry_t *)src_entry->data;
1866         if( !src_data )
1867             return LSMASH_ERR_NAMELESS;
1868         isom_elst_entry_t *dst_data = (isom_elst_entry_t *)lsmash_malloc( sizeof(isom_elst_entry_t) );
1869         if( !dst_data )
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;
1878         else
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;
1884         else
1885             dst_data->media_time = ISOM_EDIT_MODE_EMPTY;
1886         if( lsmash_list_add_entry( dst_list, dst_data ) < 0 )
1887         {
1888             lsmash_free( dst_data );
1889             return LSMASH_ERR_MEMORY_ALLOC;
1890         }
1891         src_entry = src_entry->next;
1892     }
1893     return 0;
1894 }
1895 
lsmash_set_media_timestamps(lsmash_root_t * root,uint32_t track_ID,lsmash_media_ts_list_t * ts_list)1896 int lsmash_set_media_timestamps( lsmash_root_t *root, uint32_t track_ID, lsmash_media_ts_list_t *ts_list )
1897 {
1898     if( LSMASH_IS_NON_EXISTING_BOX( root )
1899      || LSMASH_IS_NON_EXISTING_BOX( root->file )
1900      || !ts_list )
1901         return -1;
1902     isom_timeline_t *timeline = isom_get_timeline( root, track_ID );
1903     if( !timeline )
1904         return LSMASH_ERR_NAMELESS;
1905     if( timeline->info_list->entry_count == 0 )
1906     {
1907         lsmash_log( timeline, LSMASH_LOG_ERROR, "Changing timestamps of LPCM track is not supported.\n" );
1908         return LSMASH_ERR_PATCH_WELCOME;
1909     }
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;
1913     if( ts[0].dts )
1914         return LSMASH_ERR_INVALID_DATA; /* DTS must start from value zero. */
1915     /* Update DTSs. */
1916     uint32_t sample_count  = ts_list->sample_count;
1917     uint32_t i;
1918     if( timeline->info_list->entry_count > 1 )
1919     {
1920         i = 1;
1921         lsmash_entry_t *entry = timeline->info_list->head;
1922         isom_sample_info_t *info = NULL;
1923         while( i < sample_count )
1924         {
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;
1930             ++i;
1931         }
1932         if( i > 1 )
1933         {
1934             if( !entry
1935              || !entry->data )
1936                 return LSMASH_ERR_INVALID_DATA;
1937             /* Copy the previous duration. */
1938             ((isom_sample_info_t *)entry->data)->duration = info->duration;
1939         }
1940         else
1941             return LSMASH_ERR_INVALID_DATA; /* Irregular case: sample_count this timeline has is incorrect. */
1942     }
1943     else    /* still image */
1944         ((isom_sample_info_t *)timeline->info_list->head->data)->duration = UINT32_MAX;
1945     /* Update CTSs.
1946      * ToDo: hint track must not have any sample_offset. */
1947     i = 0;
1948     timeline->ctd_shift = 0;
1949     for( lsmash_entry_t *entry = timeline->info_list->head; entry; entry = entry->next )
1950     {
1951         isom_sample_info_t *info = (isom_sample_info_t *)entry->data;
1952         if( ts[i].cts != LSMASH_TIMESTAMP_UNDEFINED )
1953         {
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;
1957         }
1958         else
1959             info->offset = ISOM_NON_OUTPUT_SAMPLE_OFFSET;
1960         ++i;
1961     }
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. */
1964     return 0;
1965 }
1966 
lsmash_get_media_timestamps(lsmash_root_t * root,uint32_t track_ID,lsmash_media_ts_list_t * ts_list)1967 int lsmash_get_media_timestamps( lsmash_root_t *root, uint32_t track_ID, lsmash_media_ts_list_t *ts_list )
1968 {
1969     if( !ts_list )
1970         return LSMASH_ERR_FUNCTION_PARAM;
1971     isom_timeline_t *timeline = isom_get_timeline( root, track_ID );
1972     if( !timeline )
1973         return LSMASH_ERR_NAMELESS;
1974     uint32_t sample_count = timeline->info_list->entry_count;
1975     if( sample_count == 0 )
1976     {
1977         ts_list->sample_count = 0;
1978         ts_list->timestamp    = NULL;
1979         return 0;
1980     }
1981     lsmash_media_ts_t *ts = lsmash_malloc( sample_count * sizeof(lsmash_media_ts_t) );
1982     if( !ts )
1983         return LSMASH_ERR_MEMORY_ALLOC;
1984     uint64_t dts = 0;
1985     uint32_t i = 0;
1986     if( timeline->info_list->entry_count )
1987         for( lsmash_entry_t *entry = timeline->info_list->head; entry; entry = entry->next )
1988         {
1989             isom_sample_info_t *info = (isom_sample_info_t *)entry->data;
1990             if( !info )
1991             {
1992                 lsmash_free( ts );
1993                 return LSMASH_ERR_NAMELESS;
1994             }
1995             ts[i].dts = dts;
1996             ts[i].cts = isom_make_cts( dts, info->offset, timeline->ctd_shift );
1997             dts += info->duration;
1998             ++i;
1999         }
2000     else
2001         for( lsmash_entry_t *entry = timeline->bunch_list->head; entry; entry = entry->next )
2002         {
2003             isom_lpcm_bunch_t *bunch = (isom_lpcm_bunch_t *)entry->data;
2004             if( !bunch )
2005             {
2006                 lsmash_free( ts );
2007                 return LSMASH_ERR_NAMELESS;
2008             }
2009             for( uint32_t j = 0; j < bunch->sample_count; j++ )
2010             {
2011                 ts[i].dts = dts;
2012                 ts[i].cts = isom_make_cts( dts, bunch->offset, timeline->ctd_shift );
2013                 dts += bunch->duration;
2014                 ++i;
2015             }
2016         }
2017     ts_list->sample_count = sample_count;
2018     ts_list->timestamp    = ts;
2019     return 0;
2020 }
2021 
lsmash_delete_media_timestamps(lsmash_media_ts_list_t * ts_list)2022 void lsmash_delete_media_timestamps( lsmash_media_ts_list_t *ts_list )
2023 {
2024     if( !ts_list )
2025         return;
2026     lsmash_freep( &ts_list->timestamp );
2027     ts_list->sample_count = 0;
2028 }
2029 
isom_compare_dts(const lsmash_media_ts_t * a,const lsmash_media_ts_t * b)2030 static int isom_compare_dts( const lsmash_media_ts_t *a, const lsmash_media_ts_t *b )
2031 {
2032     int64_t diff = (int64_t)(a->dts - b->dts);
2033     return diff > 0 ? 1 : (diff == 0 ? 0 : -1);
2034 }
2035 
lsmash_sort_timestamps_decoding_order(lsmash_media_ts_list_t * ts_list)2036 void lsmash_sort_timestamps_decoding_order( lsmash_media_ts_list_t *ts_list )
2037 {
2038     if( !ts_list )
2039         return;
2040     qsort( ts_list->timestamp, ts_list->sample_count, sizeof(lsmash_media_ts_t), (int(*)( const void *, const void * ))isom_compare_dts );
2041 }
2042 
isom_compare_cts(const lsmash_media_ts_t * a,const lsmash_media_ts_t * b)2043 static int isom_compare_cts( const lsmash_media_ts_t *a, const lsmash_media_ts_t *b )
2044 {
2045     int64_t diff = (int64_t)(a->cts - b->cts);
2046     return diff > 0 ? 1 : (diff == 0 ? 0 : -1);
2047 }
2048 
lsmash_sort_timestamps_composition_order(lsmash_media_ts_list_t * ts_list)2049 void lsmash_sort_timestamps_composition_order( lsmash_media_ts_list_t *ts_list )
2050 {
2051     if( !ts_list )
2052         return;
2053     qsort( ts_list->timestamp, ts_list->sample_count, sizeof(lsmash_media_ts_t), (int(*)( const void *, const void * ))isom_compare_cts );
2054 }
2055 
lsmash_get_max_sample_delay(lsmash_media_ts_list_t * ts_list,uint32_t * max_sample_delay)2056 int lsmash_get_max_sample_delay( lsmash_media_ts_list_t *ts_list, uint32_t *max_sample_delay )
2057 {
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) );
2062     if( !ts )
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++ )
2067     {
2068         ts[i].cts = orig_ts[i].cts;     /* for sorting */
2069         ts[i].dts = i;
2070     }
2071     lsmash_sort_timestamps_composition_order( ts_list );
2072     for( uint32_t i = 0; i < ts_list->sample_count; i++ )
2073         if( i < ts[i].dts )
2074         {
2075             uint32_t sample_delay = ts[i].dts - i;
2076             *max_sample_delay = LSMASH_MAX( *max_sample_delay, sample_delay );
2077         }
2078     lsmash_free( ts );
2079     ts_list->timestamp = orig_ts;
2080     return 0;
2081 }
2082