list: Decide the entry eliminator of list at its initialization.
[L-SMASH.git] / importer / isobm_imp.c
blob7e856bcf4ea80f14ac0b5a9cd35e2ef00cce4bd0
1 /*****************************************************************************
2 * isobm_imp.c
3 *****************************************************************************
4 * Copyright (C) 2014-2017 L-SMASH project
6 * Authors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 *****************************************************************************/
21 /* This file is available under an ISC license. */
23 #include "common/internal.h" /* must be placed first */
25 #include <string.h>
27 #define LSMASH_IMPORTER_INTERNAL
28 #include "importer.h"
30 /*********************************************************************************
31 ISO Base Media File Format (ISOBMFF) / QuickTime File Format (QTFF) importer
33 TODO: Make this importer work for multiple tracks.
34 **********************************************************************************/
35 #include "core/read.h"
36 #include "core/timeline.h"
38 typedef struct
40 uint64_t timebase;
41 uint32_t track_ID;
42 uint32_t current_sample_description_index;
43 uint32_t au_number;
44 } isobm_importer_t;
46 static void remove_isobm_importer( isobm_importer_t *isobm_imp )
48 if( !isobm_imp )
49 return;
50 lsmash_free( isobm_imp );
53 static isobm_importer_t *create_isobm_importer( importer_t *importer )
55 isobm_importer_t *isobm_imp = (isobm_importer_t *)lsmash_malloc_zero( sizeof(isobm_importer_t) );
56 if( isobm_imp )
58 isobm_imp->timebase = 1;
59 return isobm_imp;
61 else
62 return NULL;
65 static void isobm_importer_cleanup( importer_t *importer )
67 debug_if( importer && importer->info )
68 remove_isobm_importer( importer->info );
71 static int isobm_importer_get_accessunit( importer_t *importer, uint32_t track_number, lsmash_sample_t **p_sample )
73 if( !importer->info )
74 return LSMASH_ERR_NAMELESS;
75 if( track_number != 1 )
76 return LSMASH_ERR_FUNCTION_PARAM;
77 importer_status current_status = importer->status;
78 if( current_status == IMPORTER_ERROR )
79 return LSMASH_ERR_NAMELESS;
80 if( current_status == IMPORTER_EOF )
81 return IMPORTER_EOF;
82 isobm_importer_t *isobm_imp = (isobm_importer_t *)importer->info;
83 lsmash_root_t *root = importer->root;
84 uint32_t track_ID = lsmash_get_track_ID( root, track_number );
85 if( track_ID != isobm_imp->track_ID )
86 return LSMASH_ERR_PATCH_WELCOME;
87 lsmash_sample_t *sample = lsmash_get_sample_from_media_timeline( root, track_ID, isobm_imp->au_number + 1 );
88 if( !sample )
90 if( lsmash_check_sample_existence_in_media_timeline( root, track_ID, isobm_imp->au_number + 1 ) )
91 return LSMASH_ERR_NAMELESS;
92 else
94 /* No more samples. */
95 importer->status = IMPORTER_EOF;
96 return IMPORTER_EOF;
99 sample->dts /= isobm_imp->timebase;
100 sample->cts /= isobm_imp->timebase;
101 if( sample->index != isobm_imp->current_sample_description_index )
103 /* Update the active summary. */
104 lsmash_summary_t *summary = lsmash_get_summary( root, track_ID, sample->index );
105 if( !summary )
107 lsmash_delete_sample( sample );
108 return LSMASH_ERR_NAMELESS;
110 lsmash_list_remove_entry( importer->summaries, track_number );
111 if( lsmash_list_add_entry( importer->summaries, summary ) < 0 )
113 lsmash_delete_sample( sample );
114 lsmash_cleanup_summary( (lsmash_summary_t *)summary );
115 return LSMASH_ERR_MEMORY_ALLOC;
117 isobm_imp->current_sample_description_index = sample->index;
118 importer->status = IMPORTER_OK;
119 current_status = IMPORTER_CHANGE;
121 *p_sample = sample;
122 ++ isobm_imp->au_number;
123 return current_status;
126 static int isobm_importer_probe( importer_t *importer )
128 isobm_importer_t *isobm_imp = create_isobm_importer( importer );
129 if( !isobm_imp )
130 return LSMASH_ERR_MEMORY_ALLOC;
131 int err = 0;
132 /* Get the file size if seekable when reading. */
133 lsmash_bs_t *bs = importer->bs;
134 if( !bs->unseekable )
136 int64_t ret = lsmash_bs_read_seek( bs, 0, SEEK_END );
137 if( ret < 0 )
139 err = ret;
140 goto fail;
142 bs->written = ret;
143 lsmash_bs_read_seek( bs, 0, SEEK_SET );
145 if( (err = isom_read_file( importer->file )) < 0 )
146 goto fail;
147 if( !(importer->file->flags & (LSMASH_FILE_MODE_BOX
148 | LSMASH_FILE_MODE_FRAGMENTED
149 | LSMASH_FILE_MODE_INITIALIZATION
150 | LSMASH_FILE_MODE_MEDIA
151 | LSMASH_FILE_MODE_INDEX
152 | LSMASH_FILE_MODE_SEGMENT)) )
154 err = LSMASH_ERR_INVALID_DATA;
155 goto fail;
157 importer->file->flags |= LSMASH_FILE_MODE_BOX;
158 if( importer->is_adhoc_open )
160 lsmash_root_t *root = importer->root;
161 if( (isobm_imp->track_ID = lsmash_get_track_ID( root, 1 )) == 0 )
163 err = LSMASH_ERR_PATCH_WELCOME;
164 goto fail;
166 lsmash_summary_t *summary = lsmash_get_summary( root, isobm_imp->track_ID, 1 );
167 if( (err = lsmash_list_add_entry( importer->summaries, summary )) < 0 )
169 lsmash_cleanup_summary( (lsmash_summary_t *)summary );
170 goto fail;
172 isobm_imp->current_sample_description_index = 1;
174 importer->info = isobm_imp;
175 importer->status = IMPORTER_OK;
176 return 0;
177 fail:
178 remove_isobm_importer( isobm_imp );
179 return err;
182 static uint32_t isobm_importer_get_last_delta( importer_t *importer, uint32_t track_number )
184 debug_if( !importer || !importer->info )
185 return 0;
186 isobm_importer_t *isobm_imp = (isobm_importer_t *)importer->info;
187 if( !isobm_imp || track_number != 1 )
188 return 0;
189 uint32_t last_sample_delta;
190 if( lsmash_get_last_sample_delta_from_media_timeline( importer->root, isobm_imp->track_ID, &last_sample_delta ) < 0 )
191 return 0;
192 return last_sample_delta / isobm_imp->timebase;
195 static int isobm_importer_construct_timeline( importer_t *importer, uint32_t track_number )
197 lsmash_root_t *root = importer->root;
198 uint32_t track_ID = lsmash_get_track_ID( root, track_number );
199 int err = isom_timeline_construct( root, track_ID );
200 if( err < 0 )
201 return err;
202 if( importer->is_adhoc_open )
204 lsmash_summary_t *summary = lsmash_list_get_entry_data( importer->summaries, track_number );
205 if( !summary )
206 return LSMASH_ERR_NAMELESS;
207 summary->max_au_length = lsmash_get_max_sample_size_in_media_timeline( root, track_ID );
208 if( summary->summary_type == LSMASH_SUMMARY_TYPE_VIDEO )
210 lsmash_media_ts_list_t ts_list;
211 if( (err = lsmash_get_media_timestamps( root, track_ID, &ts_list )) < 0 )
212 return err;
213 uint32_t last_sample_delta;
214 if( (err = lsmash_get_last_sample_delta_from_media_timeline( root, track_ID, &last_sample_delta )) < 0 )
215 return err;
216 isobm_importer_t *isobm_imp = (isobm_importer_t *)importer->info;
217 isobm_imp->timebase = last_sample_delta;
218 for( uint32_t i = 1; i < ts_list.sample_count; i++ )
219 isobm_imp->timebase = lsmash_get_gcd( isobm_imp->timebase, ts_list.timestamp[i].dts - ts_list.timestamp[i - 1].dts );
220 lsmash_sort_timestamps_composition_order( &ts_list );
221 for( uint32_t i = 1; i < ts_list.sample_count; i++ )
222 isobm_imp->timebase = lsmash_get_gcd( isobm_imp->timebase, ts_list.timestamp[i].cts - ts_list.timestamp[i - 1].cts );
223 lsmash_delete_media_timestamps( &ts_list );
224 if( isobm_imp->timebase == 0 )
225 isobm_imp->timebase = 1;
226 ((lsmash_video_summary_t *)summary)->timebase = isobm_imp->timebase;
227 ((lsmash_video_summary_t *)summary)->timescale = lsmash_get_media_timescale( root, track_ID );
230 return 0;
233 const importer_functions isobm_importer =
235 { "ISOBMFF/QTFF", offsetof( importer_t, log_level ) },
237 isobm_importer_probe,
238 isobm_importer_get_accessunit,
239 isobm_importer_get_last_delta,
240 isobm_importer_cleanup,
241 isobm_importer_construct_timeline