1 /*****************************************************************************
2  * importer.c
3  *****************************************************************************
4  * Copyright (C) 2010-2017 L-SMASH project
5  *
6  * Authors: Takashi Hirata <silverfilain@gmail.com>
7  * Contributors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
8  *
9  * Permission to use, copy, modify, and/or distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  *****************************************************************************/
21 
22 /* This file is available under an ISC license. */
23 
24 #include "common/internal.h" /* must be placed first */
25 
26 #include <string.h>
27 
28 #define LSMASH_IMPORTER_INTERNAL
29 #include "importer.h"
30 
31 /***************************************************************************
32     importer classes
33 ***************************************************************************/
34 static const lsmash_class_t lsmash_importer_class =
35 {
36     "importer",
37     offsetof( importer_t, log_level )
38 };
39 
40 extern const importer_functions mp4sys_adts_importer;
41 extern const importer_functions mp4sys_mp3_importer;
42 extern const importer_functions amr_importer;
43 extern const importer_functions ac3_importer;
44 extern const importer_functions eac3_importer;
45 extern const importer_functions mp4a_als_importer;
46 extern const importer_functions dts_importer;
47 extern const importer_functions wave_importer;
48 extern const importer_functions h264_importer;
49 extern const importer_functions hevc_importer;
50 extern const importer_functions vc1_importer;
51 extern const importer_functions isobm_importer;
52 
53 /******** importer listing table ********/
54 static const importer_functions *importer_func_table[] =
55 {
56     &mp4sys_adts_importer,
57     &mp4sys_mp3_importer,
58     &amr_importer,
59     &ac3_importer,
60     &eac3_importer,
61     &mp4a_als_importer,
62     &dts_importer,
63     &wave_importer,
64     &h264_importer,
65     &hevc_importer,
66     &vc1_importer,
67     &isobm_importer,
68     NULL,
69 };
70 
71 /***************************************************************************
72     importer public interfaces
73 ***************************************************************************/
74 
75 /******** importer public functions ********/
lsmash_importer_alloc(lsmash_root_t * root)76 importer_t *lsmash_importer_alloc( lsmash_root_t *root )
77 {
78     if( LSMASH_IS_NON_EXISTING_BOX( root ) )
79         return NULL;
80     importer_t *importer = (importer_t *)lsmash_malloc_zero( sizeof(importer_t) );
81     if( !importer )
82         return NULL;
83     importer->root = root;
84     importer->summaries = lsmash_list_create( lsmash_cleanup_summary );
85     if( !importer->summaries )
86     {
87         lsmash_destroy_root( importer->root );
88         lsmash_free( importer );
89         return NULL;
90     }
91     return importer;
92 }
93 
lsmash_importer_destroy(importer_t * importer)94 void lsmash_importer_destroy( importer_t *importer )
95 {
96     if( !importer )
97         return;
98     lsmash_file_t *file = importer->file;
99     if( importer->funcs.cleanup )
100         importer->funcs.cleanup( importer );
101     lsmash_list_destroy( importer->summaries );
102     lsmash_free( importer );
103     /* Prevent freeing this already freed importer in file's destructor again. */
104     if( file && file->importer )
105         file->importer = NULL;
106 }
107 
lsmash_importer_set_file(importer_t * importer,lsmash_file_t * file)108 int lsmash_importer_set_file( importer_t *importer, lsmash_file_t *file )
109 {
110     if( !importer
111      || lsmash_activate_file( importer->root, file ) < 0
112      || !file->bs )
113         return LSMASH_ERR_NAMELESS;
114     importer->file = file;
115     importer->bs   = file->bs;
116     file->importer = importer;
117     return 0;
118 }
119 
lsmash_importer_close(importer_t * importer)120 void lsmash_importer_close( importer_t *importer )
121 {
122     if( !importer )
123         return;
124     lsmash_close_file( &importer->file_param );
125     lsmash_importer_destroy( importer );
126 }
127 
lsmash_importer_find(importer_t * importer,const char * format,int auto_detect)128 int lsmash_importer_find( importer_t *importer, const char *format, int auto_detect )
129 {
130     importer->log_level = LSMASH_LOG_QUIET; /* Any error log is confusing for the probe step. */
131     const importer_functions *funcs;
132     int err = LSMASH_ERR_NAMELESS;
133     if( auto_detect )
134     {
135         /* just rely on detector. */
136         for( int i = 0; (funcs = importer_func_table[i]) != NULL; i++ )
137         {
138             importer->class = &funcs->class;
139             if( !funcs->detectable )
140                 continue;
141             if( (err = funcs->probe( importer )) == 0
142              || lsmash_bs_read_seek( importer->bs, 0, SEEK_SET ) != 0 )
143                 break;
144         }
145     }
146     else
147     {
148         /* needs name matching. */
149         for( int i = 0; (funcs = importer_func_table[i]) != NULL; i++ )
150         {
151             importer->class = &funcs->class;
152             if( strcmp( importer->class->name, format ) )
153                 continue;
154             if( (err = funcs->probe( importer )) < 0 )
155                 funcs = NULL;
156             break;
157         }
158     }
159     importer->log_level = LSMASH_LOG_INFO;
160     if( !funcs )
161     {
162         importer->class = &lsmash_importer_class;
163         lsmash_log( importer, LSMASH_LOG_ERROR, "failed to find the matched importer.\n" );
164     }
165     else
166         importer->funcs = *funcs;
167     return err;
168 }
169 
lsmash_importer_open(lsmash_root_t * root,const char * identifier,const char * format)170 importer_t *lsmash_importer_open( lsmash_root_t *root, const char *identifier, const char *format )
171 {
172     if( identifier == NULL )
173         return NULL;
174     int auto_detect = (format == NULL || !strcmp( format, "auto" ));
175     importer_t *importer = lsmash_importer_alloc( root );
176     if( !importer )
177         return NULL;
178     importer->is_adhoc_open = 1;
179     /* Open an input 'stream'. */
180     if( !strcmp( identifier, "-" ) )
181     {
182         /* special treatment for stdin */
183         if( auto_detect )
184         {
185             lsmash_log( importer, LSMASH_LOG_ERROR, "auto importer detection on stdin is not supported.\n" );
186             goto fail;
187         }
188     }
189     if( lsmash_open_file( identifier, 1, &importer->file_param ) < 0 )
190     {
191         lsmash_log( importer, LSMASH_LOG_ERROR, "failed to open %s.\n", identifier );
192         goto fail;
193     }
194     lsmash_file_t *file = lsmash_set_file( root, &importer->file_param );
195     if( LSMASH_IS_NON_EXISTING_BOX( file ) )
196     {
197         lsmash_log( importer, LSMASH_LOG_ERROR, "failed to set opened file.\n" );
198         goto fail;
199     }
200     lsmash_importer_set_file( importer, file );
201     if( lsmash_importer_find( importer, format, auto_detect ) < 0 )
202         goto fail;
203     return importer;
204 fail:
205     lsmash_importer_close( importer );
206     return NULL;
207 }
208 
209 /* 0 if success, positive if changed, negative if failed */
lsmash_importer_get_access_unit(importer_t * importer,uint32_t track_number,lsmash_sample_t ** p_sample)210 int lsmash_importer_get_access_unit( importer_t *importer, uint32_t track_number, lsmash_sample_t **p_sample )
211 {
212     if( !importer || !p_sample )
213         return LSMASH_ERR_FUNCTION_PARAM;
214     if( !importer->funcs.get_accessunit )
215         return LSMASH_ERR_NAMELESS;
216     *p_sample = NULL;
217     return importer->funcs.get_accessunit( importer, track_number, p_sample );
218 }
219 
220 /* Return 0 if failed, otherwise succeeded. */
lsmash_importer_get_last_delta(importer_t * importer,uint32_t track_number)221 uint32_t lsmash_importer_get_last_delta( importer_t *importer, uint32_t track_number )
222 {
223     if( !importer || !importer->funcs.get_last_delta )
224         return 0;
225     return importer->funcs.get_last_delta( importer, track_number );
226 }
227 
lsmash_importer_construct_timeline(importer_t * importer,uint32_t track_number)228 int lsmash_importer_construct_timeline( importer_t *importer, uint32_t track_number )
229 {
230     if( !importer )
231         return LSMASH_ERR_FUNCTION_PARAM;
232     if( !importer->funcs.construct_timeline )
233         return LSMASH_ERR_PATCH_WELCOME;
234     return importer->funcs.construct_timeline( importer, track_number );
235 }
236 
lsmash_importer_get_track_count(importer_t * importer)237 uint32_t lsmash_importer_get_track_count( importer_t *importer )
238 {
239     if( !importer || !importer->summaries )
240         return 0;
241     return importer->summaries->entry_count;
242 }
243 
lsmash_duplicate_summary(importer_t * importer,uint32_t track_number)244 lsmash_summary_t *lsmash_duplicate_summary( importer_t *importer, uint32_t track_number )
245 {
246     if( !importer )
247         return NULL;
248     lsmash_summary_t *src_summary = lsmash_list_get_entry_data( importer->summaries, track_number );
249     if( !src_summary )
250         return NULL;
251     lsmash_summary_t *summary = lsmash_create_summary( src_summary->summary_type );
252     if( !summary )
253         return NULL;
254     lsmash_codec_specific_list_t *opaque = summary->opaque;
255     switch( src_summary->summary_type )
256     {
257         case LSMASH_SUMMARY_TYPE_VIDEO :
258             *(lsmash_video_summary_t *)summary = *(lsmash_video_summary_t *)src_summary;
259             break;
260         case LSMASH_SUMMARY_TYPE_AUDIO :
261             *(lsmash_audio_summary_t *)summary = *(lsmash_audio_summary_t *)src_summary;
262             break;
263         default :
264             lsmash_cleanup_summary( summary );
265             return NULL;
266     }
267     summary->opaque = opaque;
268     for( lsmash_entry_t *entry = src_summary->opaque->list.head; entry; entry = entry->next )
269     {
270         lsmash_codec_specific_t *src_specific = (lsmash_codec_specific_t *)entry->data;
271         if( !src_specific )
272             continue;
273         lsmash_codec_specific_t *dup = isom_duplicate_codec_specific_data( src_specific );
274         if( lsmash_list_add_entry( &summary->opaque->list, dup ) < 0 )
275         {
276             lsmash_cleanup_summary( (lsmash_summary_t *)summary );
277             lsmash_destroy_codec_specific_data( dup );
278             return NULL;
279         }
280     }
281     return summary;
282 }
283 
lsmash_importer_make_fake_movie(importer_t * importer)284 int lsmash_importer_make_fake_movie( importer_t *importer )
285 {
286     if( !importer || (importer->file->flags & LSMASH_FILE_MODE_BOX) )
287         return LSMASH_ERR_FUNCTION_PARAM;
288     if( LSMASH_IS_BOX_ADDITION_FAILURE( isom_movie_create( importer->file ) ) )
289         return LSMASH_ERR_NAMELESS;
290     return 0;
291 }
292 
lsmash_importer_make_fake_track(importer_t * importer,lsmash_media_type media_type,uint32_t * track_ID)293 int lsmash_importer_make_fake_track( importer_t *importer, lsmash_media_type media_type, uint32_t *track_ID )
294 {
295     if( !importer || (importer->file->flags & LSMASH_FILE_MODE_BOX) || track_ID == 0 )
296         return LSMASH_ERR_FUNCTION_PARAM;
297     isom_trak_t *trak = isom_track_create( importer->file, media_type );
298     int err;
299     if( LSMASH_IS_NON_EXISTING_BOX( trak->tkhd )
300      || LSMASH_IS_NON_EXISTING_BOX( trak->mdia->minf )
301      || trak->tkhd->track_ID == 0 )
302     {
303         err = LSMASH_ERR_NAMELESS;
304         goto fail;
305     }
306     if( (err = isom_complement_data_reference( trak->mdia->minf )) < 0 )
307         goto fail;
308     *track_ID = trak->tkhd->track_ID;
309     return 0;
310 fail:
311     isom_remove_box_by_itself( trak );
312     return err;
313 }
314 
lsmash_importer_break_fake_movie(importer_t * importer)315 void lsmash_importer_break_fake_movie( importer_t *importer )
316 {
317     if( !importer )
318         return;
319     isom_remove_box_by_itself( importer->file->moov );
320 }
321