print: Avoid Variable Length Arrays.
[L-SMASH.git] / importer / isobm_imp.c
blob36faa3609693bb839d2f5ba1094f7c4c4694482d
1 /*****************************************************************************
2 * isobm_imp.c
3 *****************************************************************************
4 * Copyright (C) 2014 L-SMASH project
6 * Authors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 *****************************************************************************/
21 /* This file is available under an ISC license. */
23 #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
32 **********************************************************************************/
33 #include "core/read.h"
34 #include "core/timeline.h"
36 typedef struct
38 uint64_t timebase;
39 uint32_t track_ID;
40 uint32_t current_sample_description_index;
41 uint32_t au_number;
42 } isobm_importer_t;
44 static void remove_isobm_importer( isobm_importer_t *isobm_imp )
46 if( !isobm_imp )
47 return;
48 lsmash_free( isobm_imp );
51 static isobm_importer_t *create_isobm_importer( importer_t *importer )
53 isobm_importer_t *isobm_imp = (isobm_importer_t *)lsmash_malloc_zero( sizeof(isobm_importer_t) );
54 if( isobm_imp )
56 isobm_imp->timebase = 1;
57 return isobm_imp;
59 else
60 return NULL;
63 static void isobm_importer_cleanup( importer_t *importer )
65 debug_if( importer && importer->info )
66 remove_isobm_importer( importer->info );
69 static int isobm_importer_get_accessunit( importer_t *importer, uint32_t track_number, lsmash_sample_t **p_sample )
71 if( !importer->info )
72 return LSMASH_ERR_NAMELESS;
73 if( track_number != 1 )
74 return LSMASH_ERR_FUNCTION_PARAM;
75 importer_status current_status = importer->status;
76 if( current_status == IMPORTER_ERROR )
77 return LSMASH_ERR_NAMELESS;
78 if( current_status == IMPORTER_EOF )
79 return IMPORTER_EOF;
80 isobm_importer_t *isobm_imp = (isobm_importer_t *)importer->info;
81 lsmash_root_t *root = importer->root;
82 uint32_t track_ID = lsmash_get_track_ID( root, track_number );
83 if( track_ID != isobm_imp->track_ID )
84 return LSMASH_ERR_PATCH_WELCOME;
85 lsmash_sample_t *sample = lsmash_get_sample_from_media_timeline( root, track_ID, isobm_imp->au_number + 1 );
86 if( !sample )
88 if( lsmash_check_sample_existence_in_media_timeline( root, track_ID, isobm_imp->au_number + 1 ) )
89 return LSMASH_ERR_NAMELESS;
90 else
92 /* No more samples. */
93 importer->status = IMPORTER_EOF;
94 return IMPORTER_EOF;
97 sample->dts /= isobm_imp->timebase;
98 sample->cts /= isobm_imp->timebase;
99 if( sample->index != isobm_imp->current_sample_description_index )
101 /* Update the active summary. */
102 lsmash_summary_t *summary = lsmash_get_summary( root, track_ID, sample->index );
103 if( !summary )
105 lsmash_delete_sample( sample );
106 return LSMASH_ERR_NAMELESS;
108 lsmash_remove_entry( importer->summaries, track_number, lsmash_cleanup_summary );
109 if( lsmash_add_entry( importer->summaries, summary ) < 0 )
111 lsmash_delete_sample( sample );
112 lsmash_cleanup_summary( (lsmash_summary_t *)summary );
113 return LSMASH_ERR_MEMORY_ALLOC;
115 isobm_imp->current_sample_description_index = sample->index;
116 importer->status = IMPORTER_OK;
117 current_status = IMPORTER_CHANGE;
119 *p_sample = sample;
120 ++ isobm_imp->au_number;
121 return current_status;
124 static int isobm_importer_probe( importer_t *importer )
126 isobm_importer_t *isobm_imp = create_isobm_importer( importer );
127 if( !isobm_imp )
128 return LSMASH_ERR_MEMORY_ALLOC;
129 int err = 0;
130 /* Get the file size if seekable when reading. */
131 lsmash_bs_t *bs = importer->bs;
132 if( !bs->unseekable )
134 int64_t ret = lsmash_bs_read_seek( bs, 0, SEEK_END );
135 if( ret < 0 )
137 err = ret;
138 goto fail;
140 bs->written = ret;
141 lsmash_bs_read_seek( bs, 0, SEEK_SET );
143 if( (err = isom_read_file( importer->file )) < 0 )
144 goto fail;
145 if( !(importer->file->flags & (LSMASH_FILE_MODE_BOX
146 | LSMASH_FILE_MODE_FRAGMENTED
147 | LSMASH_FILE_MODE_INITIALIZATION
148 | LSMASH_FILE_MODE_MEDIA
149 | LSMASH_FILE_MODE_INDEX
150 | LSMASH_FILE_MODE_SEGMENT)) )
152 err = LSMASH_ERR_INVALID_DATA;
153 goto fail;
155 importer->file->flags |= LSMASH_FILE_MODE_BOX;
156 lsmash_root_t *root = importer->root;
157 if( root && root == importer->file->root )
159 if( (isobm_imp->track_ID = lsmash_get_track_ID( root, 1 )) == 0 )
161 err = LSMASH_ERR_PATCH_WELCOME;
162 goto fail;
164 lsmash_summary_t *summary = lsmash_get_summary( root, isobm_imp->track_ID, 1 );
165 if( (err = lsmash_add_entry( importer->summaries, summary )) < 0 )
167 lsmash_cleanup_summary( (lsmash_summary_t *)summary );
168 goto fail;
170 isobm_imp->current_sample_description_index = 1;
172 importer->info = isobm_imp;
173 importer->status = IMPORTER_OK;
174 return 0;
175 fail:
176 remove_isobm_importer( isobm_imp );
177 return err;
180 static uint32_t isobm_importer_get_last_delta( importer_t *importer, uint32_t track_number )
182 debug_if( !importer || !importer->info )
183 return 0;
184 isobm_importer_t *isobm_imp = (isobm_importer_t *)importer->info;
185 if( !isobm_imp || track_number != 1 )
186 return 0;
187 uint32_t last_sample_delta;
188 if( lsmash_get_last_sample_delta_from_media_timeline( importer->root, isobm_imp->track_ID, &last_sample_delta ) < 0 )
189 return 0;
190 return last_sample_delta / isobm_imp->timebase;
193 static int isobm_importer_construct_timeline( importer_t *importer, uint32_t track_number )
195 lsmash_root_t *root = importer->root;
196 uint32_t track_ID = lsmash_get_track_ID( root, track_number );
197 int err = isom_timeline_construct( root, track_ID );
198 if( err < 0 )
199 return err;
200 if( root && root == importer->file->root )
202 lsmash_summary_t *summary = lsmash_get_entry_data( importer->summaries, track_number );
203 if( !summary )
204 return LSMASH_ERR_NAMELESS;
205 summary->max_au_length = lsmash_get_max_sample_size_in_media_timeline( root, track_ID );
206 if( summary->summary_type == LSMASH_SUMMARY_TYPE_VIDEO )
208 lsmash_media_ts_list_t ts_list;
209 if( (err = lsmash_get_media_timestamps( root, track_ID, &ts_list )) < 0 )
210 return err;
211 uint32_t last_sample_delta;
212 if( (err = lsmash_get_last_sample_delta_from_media_timeline( root, track_ID, &last_sample_delta )) < 0 )
213 return err;
214 isobm_importer_t *isobm_imp = (isobm_importer_t *)importer->info;
215 isobm_imp->timebase = last_sample_delta;
216 for( uint32_t i = 1; i < ts_list.sample_count; i++ )
217 isobm_imp->timebase = lsmash_get_gcd( isobm_imp->timebase, ts_list.timestamp[i].dts - ts_list.timestamp[i - 1].dts );
218 lsmash_sort_timestamps_composition_order( &ts_list );
219 for( uint32_t i = 1; i < ts_list.sample_count; i++ )
220 isobm_imp->timebase = lsmash_get_gcd( isobm_imp->timebase, ts_list.timestamp[i].cts - ts_list.timestamp[i - 1].cts );
221 lsmash_delete_media_timestamps( &ts_list );
222 if( isobm_imp->timebase == 0 )
223 isobm_imp->timebase = 1;
224 ((lsmash_video_summary_t *)summary)->timebase = isobm_imp->timebase;
225 ((lsmash_video_summary_t *)summary)->timescale = lsmash_get_media_timescale( root, track_ID );
228 return 0;
231 const importer_functions isobm_importer =
233 { "ISOBMFF/QTFF", offsetof( importer_t, log_level ) },
235 isobm_importer_probe,
236 isobm_importer_get_accessunit,
237 isobm_importer_get_last_delta,
238 isobm_importer_cleanup,
239 isobm_importer_construct_timeline