1 /*****************************************************************************
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 */
27 #define LSMASH_IMPORTER_INTERNAL
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"
42 uint32_t current_sample_description_index
;
46 static void remove_isobm_importer( isobm_importer_t
*isobm_imp
)
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
) );
58 isobm_imp
->timebase
= 1;
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
)
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
)
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 );
90 if( lsmash_check_sample_existence_in_media_timeline( root
, track_ID
, isobm_imp
->au_number
+ 1 ) )
91 return LSMASH_ERR_NAMELESS
;
94 /* No more samples. */
95 importer
->status
= 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
);
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
;
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
);
130 return LSMASH_ERR_MEMORY_ALLOC
;
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
);
143 lsmash_bs_read_seek( bs
, 0, SEEK_SET
);
145 if( (err
= isom_read_file( importer
->file
)) < 0 )
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
;
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
;
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
);
172 isobm_imp
->current_sample_description_index
= 1;
174 importer
->info
= isobm_imp
;
175 importer
->status
= IMPORTER_OK
;
178 remove_isobm_importer( isobm_imp
);
182 static uint32_t isobm_importer_get_last_delta( importer_t
*importer
, uint32_t track_number
)
184 debug_if( !importer
|| !importer
->info
)
186 isobm_importer_t
*isobm_imp
= (isobm_importer_t
*)importer
->info
;
187 if( !isobm_imp
|| track_number
!= 1 )
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 )
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
);
202 if( importer
->is_adhoc_open
)
204 lsmash_summary_t
*summary
= lsmash_list_get_entry_data( importer
->summaries
, track_number
);
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 )
213 uint32_t last_sample_delta
;
214 if( (err
= lsmash_get_last_sample_delta_from_media_timeline( root
, track_ID
, &last_sample_delta
)) < 0 )
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
);
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