msvc: Add MSVC Project files for CLI programs.
[L-SMASH.git] / codecs / description.c
blobead430f86244d42a96e592c8fbd313176e728905
1 /*****************************************************************************
2 * description.c:
3 *****************************************************************************
4 * Copyright (C) 2012-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 <stdlib.h>
26 #include <string.h>
28 #include "core/box.h"
30 #include "a52.h"
31 #include "mp4a.h"
32 #include "mp4sys.h"
33 #include "description.h"
35 typedef isom_wave_t lsmash_qt_decoder_parameters_t;
37 static void global_destruct_specific_data( void *data )
39 if( !data )
40 return;
41 lsmash_codec_global_header_t *global = (lsmash_codec_global_header_t *)data;
42 lsmash_free( global->header_data );
43 lsmash_free( global );
46 static int isom_is_qt_video( lsmash_codec_type_t type )
48 return lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_2VUY_VIDEO )
49 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_APCH_VIDEO )
50 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_APCN_VIDEO )
51 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_APCS_VIDEO )
52 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_APCO_VIDEO )
53 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_AP4H_VIDEO )
54 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_CFHD_VIDEO )
55 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_CIVD_VIDEO )
56 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVC_VIDEO )
57 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVCP_VIDEO )
58 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVPP_VIDEO )
59 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DV5N_VIDEO )
60 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DV5P_VIDEO )
61 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVH2_VIDEO )
62 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVH3_VIDEO )
63 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVH5_VIDEO )
64 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVH6_VIDEO )
65 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVHP_VIDEO )
66 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVHQ_VIDEO )
67 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DV10_VIDEO )
68 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVOO_VIDEO )
69 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVOR_VIDEO )
70 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVTV_VIDEO )
71 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVVT_VIDEO )
72 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_FLIC_VIDEO )
73 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_GIF_VIDEO )
74 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_H261_VIDEO )
75 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_H263_VIDEO )
76 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_HD10_VIDEO )
77 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_JPEG_VIDEO )
78 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_M105_VIDEO )
79 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_MJPA_VIDEO )
80 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_MJPB_VIDEO )
81 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_PNG_VIDEO )
82 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_PNTG_VIDEO )
83 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_RAW_VIDEO )
84 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_RLE_VIDEO )
85 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_RPZA_VIDEO )
86 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_SHR0_VIDEO )
87 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_SHR1_VIDEO )
88 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_SHR2_VIDEO )
89 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_SHR3_VIDEO )
90 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_SHR4_VIDEO )
91 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_SVQ1_VIDEO )
92 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_SVQ3_VIDEO )
93 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_TGA_VIDEO )
94 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_TIFF_VIDEO )
95 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ULRA_VIDEO )
96 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ULRG_VIDEO )
97 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ULY2_VIDEO )
98 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ULY0_VIDEO )
99 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ULH2_VIDEO )
100 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ULH0_VIDEO )
101 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V210_VIDEO )
102 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V216_VIDEO )
103 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V308_VIDEO )
104 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V408_VIDEO )
105 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V410_VIDEO )
106 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_YUV2_VIDEO )
107 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_WRLE_VIDEO );
110 static int isom_is_nalff( lsmash_codec_type_t type )
112 return lsmash_check_codec_type_identical( type, ISOM_CODEC_TYPE_AVC1_VIDEO )
113 || lsmash_check_codec_type_identical( type, ISOM_CODEC_TYPE_AVC2_VIDEO )
114 || lsmash_check_codec_type_identical( type, ISOM_CODEC_TYPE_AVC3_VIDEO )
115 || lsmash_check_codec_type_identical( type, ISOM_CODEC_TYPE_AVC4_VIDEO )
116 || lsmash_check_codec_type_identical( type, ISOM_CODEC_TYPE_AVCP_VIDEO )
117 || lsmash_check_codec_type_identical( type, ISOM_CODEC_TYPE_HVC1_VIDEO )
118 || lsmash_check_codec_type_identical( type, ISOM_CODEC_TYPE_HEV1_VIDEO );
121 int lsmash_convert_crop_into_clap( lsmash_crop_t crop, uint32_t width, uint32_t height, lsmash_clap_t *clap )
123 if( !clap || crop.top.d == 0 || crop.bottom.d == 0 || crop.left.d == 0 || crop.right.d == 0 )
124 return LSMASH_ERR_FUNCTION_PARAM;
125 uint64_t vertical_crop_lcm = lsmash_get_lcm( crop.top.d, crop.bottom.d );
126 uint64_t horizontal_crop_lcm = lsmash_get_lcm( crop.left.d, crop.right.d );
127 lsmash_rational_u64_t clap_height;
128 lsmash_rational_u64_t clap_width;
129 lsmash_rational_s64_t clap_horizontal_offset;
130 lsmash_rational_s64_t clap_vertical_offset;
131 clap_height.d = vertical_crop_lcm;
132 clap_width.d = horizontal_crop_lcm;
133 clap_horizontal_offset.d = 2 * vertical_crop_lcm;
134 clap_vertical_offset.d = 2 * horizontal_crop_lcm;
135 clap_height.n = height * vertical_crop_lcm
136 - (crop.top.n * (vertical_crop_lcm / crop.top.d) + crop.bottom.n * (vertical_crop_lcm / crop.bottom.d));
137 clap_width.n = width * horizontal_crop_lcm
138 - (crop.left.n * (horizontal_crop_lcm / crop.left.d) + crop.right.n * (horizontal_crop_lcm / crop.right.d));
139 clap_horizontal_offset.n = (int64_t)(crop.left.n * (horizontal_crop_lcm / crop.left.d))
140 - crop.right.n * (horizontal_crop_lcm / crop.right.d);
141 clap_vertical_offset.n = (int64_t)(crop.top.n * (vertical_crop_lcm / crop.top.d))
142 - crop.bottom.n * (vertical_crop_lcm / crop.bottom.d);
143 lsmash_reduce_fraction( &clap_height.n, &clap_height.d );
144 lsmash_reduce_fraction( &clap_width.n, &clap_width.d );
145 lsmash_reduce_fraction_su( &clap_vertical_offset.n, &clap_vertical_offset.d );
146 lsmash_reduce_fraction_su( &clap_horizontal_offset.n, &clap_horizontal_offset.d );
147 clap->height = (lsmash_rational_u32_t){ clap_height.n, clap_height.d };
148 clap->width = (lsmash_rational_u32_t){ clap_width.n, clap_width.d };
149 clap->vertical_offset = (lsmash_rational_s32_t){ clap_vertical_offset.n, clap_vertical_offset.d };
150 clap->horizontal_offset = (lsmash_rational_s32_t){ clap_horizontal_offset.n, clap_horizontal_offset.d };
151 return 0;
154 int lsmash_convert_clap_into_crop( lsmash_clap_t clap, uint32_t width, uint32_t height, lsmash_crop_t *crop )
156 if( !crop || clap.height.d == 0 || clap.vertical_offset.d == 0 || clap.width.d == 0 || clap.horizontal_offset.d == 0 )
157 return LSMASH_ERR_FUNCTION_PARAM;
158 uint64_t clap_vertical_lcm = lsmash_get_lcm( clap.height.d, clap.vertical_offset.d );
159 uint64_t clap_horizontal_lcm = lsmash_get_lcm( clap.width.d, clap.horizontal_offset.d );
160 lsmash_rational_u64_t crop_top;
161 lsmash_rational_u64_t crop_bottom;
162 lsmash_rational_u64_t crop_left;
163 lsmash_rational_u64_t crop_right;
164 crop_top.d = 2 * clap_vertical_lcm;
165 crop_bottom.d = 2 * clap_vertical_lcm;
166 crop_left.d = 2 * clap_horizontal_lcm;
167 crop_right.d = 2 * clap_horizontal_lcm;
168 crop_top.n = (height * crop_top.d - clap.height.n * (crop_top.d / clap.height.d)) / 2
169 + clap.vertical_offset.n * (crop_top.d / clap.vertical_offset.d);
170 crop_bottom.n = (height * crop_bottom.d - clap.height.n * (crop_bottom.d / clap.height.d)) / 2
171 - clap.vertical_offset.n * (crop_bottom.d / clap.vertical_offset.d);
172 crop_left.n = (width * crop_left.d - clap.width.n * (crop_left.d / clap.width.d)) / 2
173 + clap.horizontal_offset.n * (crop_left.d / clap.horizontal_offset.d);
174 crop_right.n = (width * crop_right.d - clap.width.n * (crop_right.d / clap.width.d)) / 2
175 - clap.horizontal_offset.n * (crop_right.d / clap.horizontal_offset.d);
176 lsmash_reduce_fraction( &crop_top.n, &crop_top.d );
177 lsmash_reduce_fraction( &crop_bottom.n, &crop_bottom.d );
178 lsmash_reduce_fraction( &crop_left.n, &crop_left.d );
179 lsmash_reduce_fraction( &crop_right.n, &crop_right.d );
180 crop->top = (lsmash_rational_u32_t){ crop_top.n, crop_top.d };
181 crop->bottom = (lsmash_rational_u32_t){ crop_bottom.n, crop_bottom.d };
182 crop->left = (lsmash_rational_u32_t){ crop_left.n, crop_left.d };
183 crop->right = (lsmash_rational_u32_t){ crop_right.n, crop_right.d };
184 return 0;
187 static void isom_destruct_nothing( void *data )
189 /* Do nothing. */;
192 static int isom_initialize_structured_codec_specific_data( lsmash_codec_specific_t *specific )
194 extern void mp4sys_destruct_decoder_config( void * );
195 extern void h264_destruct_specific_data( void * );
196 extern void hevc_destruct_specific_data( void * );
197 extern void vc1_destruct_specific_data( void * );
198 extern void dts_destruct_specific_data( void * );
199 switch( specific->type )
201 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG :
202 specific->size = sizeof(lsmash_mp4sys_decoder_parameters_t);
203 specific->destruct = mp4sys_destruct_decoder_config;
204 break;
205 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264 :
206 specific->size = sizeof(lsmash_h264_specific_parameters_t);
207 specific->destruct = h264_destruct_specific_data;
208 break;
209 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_HEVC :
210 specific->size = sizeof(lsmash_hevc_specific_parameters_t);
211 specific->destruct = hevc_destruct_specific_data;
212 break;
213 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_VC_1 :
214 specific->size = sizeof(lsmash_vc1_specific_parameters_t);
215 specific->destruct = vc1_destruct_specific_data;
216 break;
217 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_AC_3 :
218 specific->size = sizeof(lsmash_ac3_specific_parameters_t);
219 specific->destruct = lsmash_free;
220 break;
221 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_EC_3 :
222 specific->size = sizeof(lsmash_eac3_specific_parameters_t);
223 specific->destruct = lsmash_free;
224 break;
225 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS :
226 specific->size = sizeof(lsmash_dts_specific_parameters_t);
227 specific->destruct = dts_destruct_specific_data;
228 break;
229 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_ALAC :
230 specific->size = sizeof(lsmash_alac_specific_parameters_t);
231 specific->destruct = lsmash_free;
232 break;
233 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_SAMPLE_SCALE :
234 specific->size = sizeof(lsmash_isom_sample_scale_t);
235 specific->destruct = lsmash_free;
236 break;
237 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264_BITRATE :
238 specific->size = sizeof(lsmash_h264_bitrate_t);
239 specific->destruct = lsmash_free;
240 break;
241 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_COMMON :
242 specific->size = sizeof(lsmash_qt_video_common_t);
243 specific->destruct = lsmash_free;
244 break;
245 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_COMMON :
246 specific->size = sizeof(lsmash_qt_audio_common_t);
247 specific->destruct = lsmash_free;
248 break;
249 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS :
250 specific->size = sizeof(lsmash_qt_audio_format_specific_flags_t);
251 specific->destruct = lsmash_free;
252 break;
253 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER :
254 specific->size = sizeof(lsmash_codec_global_header_t);
255 specific->destruct = global_destruct_specific_data;
256 break;
257 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_FIELD_INFO :
258 specific->size = sizeof(lsmash_qt_field_info_t);
259 specific->destruct = lsmash_free;
260 break;
261 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_PIXEL_FORMAT :
262 specific->size = sizeof(lsmash_qt_pixel_format_t);
263 specific->destruct = lsmash_free;
264 break;
265 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_SIGNIFICANT_BITS :
266 specific->size = sizeof(lsmash_qt_significant_bits_t);
267 specific->destruct = lsmash_free;
268 break;
269 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT :
270 specific->size = sizeof(lsmash_qt_audio_channel_layout_t);
271 specific->destruct = lsmash_free;
272 break;
273 default :
274 specific->size = 0;
275 specific->destruct = isom_destruct_nothing;
276 return 0;
278 specific->data.structured = lsmash_malloc_zero( specific->size );
279 if( !specific->data.structured )
281 specific->size = 0;
282 specific->destruct = NULL;
283 return LSMASH_ERR_MEMORY_ALLOC;
285 return 0;
288 static inline int isom_initialize_codec_specific_data( lsmash_codec_specific_t *specific,
289 lsmash_codec_specific_data_type type,
290 lsmash_codec_specific_format format )
292 specific->type = type;
293 specific->format = format;
294 if( format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
296 int err = isom_initialize_structured_codec_specific_data( specific );
297 if( err < 0 )
298 return err;
300 else
302 specific->data.unstructured = NULL;
303 specific->size = 0;
304 specific->destruct = (lsmash_codec_specific_destructor_t)lsmash_free;
306 return 0;
309 void lsmash_destroy_codec_specific_data( lsmash_codec_specific_t *specific )
311 if( !specific )
312 return;
313 if( specific->destruct )
315 if( specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
317 if( specific->data.structured )
318 specific->destruct( specific->data.structured );
320 else
322 if( specific->data.unstructured )
323 specific->destruct( specific->data.unstructured );
326 lsmash_free( specific );
329 lsmash_codec_specific_t *lsmash_create_codec_specific_data( lsmash_codec_specific_data_type type, lsmash_codec_specific_format format )
331 lsmash_codec_specific_t *specific = lsmash_malloc( sizeof(lsmash_codec_specific_t) );
332 if( !specific )
333 return NULL;
334 if( isom_initialize_codec_specific_data( specific, type, format ) < 0 )
336 lsmash_destroy_codec_specific_data( specific );
337 return NULL;
339 return specific;
342 static int isom_duplicate_structured_specific_data( lsmash_codec_specific_t *dst, lsmash_codec_specific_t *src )
344 extern int mp4sys_copy_decoder_config( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
345 extern int h264_copy_codec_specific( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
346 extern int hevc_copy_codec_specific( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
347 extern int vc1_copy_codec_specific( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
348 extern int dts_copy_codec_specific( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
349 void *src_data = src->data.structured;
350 void *dst_data = dst->data.structured;
351 switch( src->type )
353 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG :
354 return mp4sys_copy_decoder_config( dst, src );
355 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264 :
356 return h264_copy_codec_specific( dst, src );
357 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_HEVC :
358 return hevc_copy_codec_specific( dst, src );
359 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_VC_1 :
360 return vc1_copy_codec_specific( dst, src );
361 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_AC_3 :
362 *(lsmash_ac3_specific_parameters_t *)dst_data = *(lsmash_ac3_specific_parameters_t *)src_data;
363 return 0;
364 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_EC_3 :
365 *(lsmash_eac3_specific_parameters_t *)dst_data = *(lsmash_eac3_specific_parameters_t *)src_data;
366 return 0;
367 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS :
368 return dts_copy_codec_specific( dst, src );
369 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_ALAC :
370 *(lsmash_alac_specific_parameters_t *)dst_data = *(lsmash_alac_specific_parameters_t *)src_data;
371 return 0;
372 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_SAMPLE_SCALE :
373 *(lsmash_isom_sample_scale_t *)dst_data = *(lsmash_isom_sample_scale_t *)src_data;
374 return 0;
375 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264_BITRATE :
376 *(lsmash_h264_bitrate_t *)dst_data = *(lsmash_h264_bitrate_t *)src_data;
377 return 0;
378 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_COMMON :
379 *(lsmash_qt_video_common_t *)dst_data = *(lsmash_qt_video_common_t *)src_data;
380 return 0;
381 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_COMMON :
382 *(lsmash_qt_audio_common_t *)dst_data = *(lsmash_qt_audio_common_t *)src_data;
383 return 0;
384 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS :
385 *(lsmash_qt_audio_format_specific_flags_t *)dst_data = *(lsmash_qt_audio_format_specific_flags_t *)src_data;
386 return 0;
387 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER :
389 lsmash_codec_global_header_t *src_global = (lsmash_codec_global_header_t *)src_data;
390 if( src_global->header_data && src_global->header_size )
392 lsmash_codec_global_header_t *dst_global = (lsmash_codec_global_header_t *)dst_data;
393 dst_global->header_data = lsmash_memdup( src_global->header_data, src_global->header_size );
394 if( !dst_global->header_data )
395 return LSMASH_ERR_MEMORY_ALLOC;
396 dst_global->header_size = src_global->header_size;
398 return 0;
400 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_FIELD_INFO :
401 *(lsmash_qt_field_info_t *)dst_data = *(lsmash_qt_field_info_t *)src_data;
402 return 0;
403 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_PIXEL_FORMAT :
404 *(lsmash_qt_pixel_format_t *)dst_data = *(lsmash_qt_pixel_format_t *)src_data;
405 return 0;
406 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_SIGNIFICANT_BITS :
407 *(lsmash_qt_significant_bits_t *)dst_data = *(lsmash_qt_significant_bits_t *)src_data;
408 return 0;
409 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_GAMMA_LEVEL :
410 *(lsmash_qt_gamma_t *)dst_data = *(lsmash_qt_gamma_t *)src_data;
411 return 0;
412 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT :
413 *(lsmash_qt_audio_channel_layout_t *)dst_data = *(lsmash_qt_audio_channel_layout_t *)src_data;
414 return 0;
415 default :
416 return LSMASH_ERR_NAMELESS;
420 lsmash_codec_specific_t *isom_duplicate_codec_specific_data( lsmash_codec_specific_t *specific )
422 if( !specific )
423 return NULL;
424 lsmash_codec_specific_t *dup = lsmash_create_codec_specific_data( specific->type, specific->format );
425 if( !dup )
426 return NULL;
427 if( specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
429 if( isom_duplicate_structured_specific_data( dup, specific ) < 0 )
431 lsmash_destroy_codec_specific_data( dup );
432 return NULL;
435 else
437 dup->data.unstructured = lsmash_memdup( specific->data.unstructured, specific->size );
438 if( !dup->data.unstructured )
440 lsmash_destroy_codec_specific_data( dup );
441 return NULL;
444 dup->size = specific->size;
445 return dup;
448 static size_t isom_description_read_box_common( uint8_t **p_data, uint64_t *size, lsmash_box_type_t *type )
450 uint8_t *orig = *p_data;
451 uint8_t *data = *p_data;
452 *size = LSMASH_GET_BE32( &data[0] );
453 type->fourcc = LSMASH_GET_BE32( &data[4] );
454 data += ISOM_BASEBOX_COMMON_SIZE;
455 if( *size == 1 )
457 *size = LSMASH_GET_BE64( data );
458 data += 8;
460 *p_data = data;
461 if( type->fourcc == ISOM_BOX_TYPE_UUID.fourcc )
463 type->user.fourcc = LSMASH_GET_BE32( &data[0] );
464 memcpy( type->user.id, &data[4], 12 );
466 return data - orig;
469 uint8_t *isom_get_child_box_position( uint8_t *parent_data, uint32_t parent_size, lsmash_box_type_t child_type, uint32_t *child_size )
471 if( !parent_data || !child_size || parent_size < ISOM_BASEBOX_COMMON_SIZE )
472 return NULL;
473 uint8_t *data = parent_data;
474 uint64_t size;
475 lsmash_box_type_t type;
476 uint32_t offset = isom_description_read_box_common( &data, &size, &type );
477 if( size != parent_size )
478 return NULL;
479 uint8_t *end = parent_data + parent_size;
480 for( uint8_t *pos = data; pos + ISOM_BASEBOX_COMMON_SIZE <= end; )
482 offset = isom_description_read_box_common( &pos, &size, &type );
483 if( lsmash_check_box_type_identical( type, child_type ) )
485 *child_size = size;
486 return pos - offset;
488 pos += size - offset; /* Move to the next box. */
490 return NULL;
493 static int isom_construct_global_specific_header( lsmash_codec_specific_t *dst, lsmash_codec_specific_t *src )
495 if( src->size < ISOM_BASEBOX_COMMON_SIZE )
496 return LSMASH_ERR_INVALID_DATA;
497 lsmash_codec_global_header_t *global = (lsmash_codec_global_header_t *)dst->data.structured;
498 uint8_t *data = src->data.unstructured;
499 uint64_t size = LSMASH_GET_BE32( data );
500 data += ISOM_BASEBOX_COMMON_SIZE;
501 if( size == 1 )
503 size = LSMASH_GET_BE64( data );
504 data += 8;
506 if( size != src->size )
507 return LSMASH_ERR_INVALID_DATA;
508 global->header_size = size - ISOM_BASEBOX_COMMON_SIZE;
509 if( data != src->data.unstructured + ISOM_BASEBOX_COMMON_SIZE )
510 global->header_size -= 8; /* largesize */
511 if( global->header_size )
513 global->header_data = lsmash_memdup( data, global->header_size );
514 if( !global->header_data )
515 return LSMASH_ERR_MEMORY_ALLOC;
517 return 0;
520 static int isom_construct_audio_channel_layout( lsmash_codec_specific_t *dst, lsmash_codec_specific_t *src )
522 if( src->size < ISOM_FULLBOX_COMMON_SIZE + 12 )
523 return LSMASH_ERR_INVALID_DATA;
524 lsmash_qt_audio_channel_layout_t *layout = (lsmash_qt_audio_channel_layout_t *)dst->data.structured;
525 uint8_t *data = src->data.unstructured;
526 uint64_t size = LSMASH_GET_BE32( data );
527 data += ISOM_FULLBOX_COMMON_SIZE;
528 if( size == 1 )
530 size = LSMASH_GET_BE64( data );
531 data += 8;
533 if( size != src->size )
534 return LSMASH_ERR_INVALID_DATA;
535 layout->channelLayoutTag = LSMASH_GET_BE32( &data[0] );
536 layout->channelBitmap = LSMASH_GET_BE32( &data[4] );
537 return 0;
540 #if 0
541 static int codec_construct_qt_audio_decompression_info( lsmash_codec_specific_t *dst, lsmash_codec_specific_t *src )
543 if( src->size < ISOM_BASEBOX_COMMON_SIZE )
544 return LSMASH_ERR_INVALID_DATA;
545 uint8_t *data = src->data.unstructured;
546 uint64_t size;
547 uint32_t type;
548 uint32_t offset = isom_description_read_box_common( &data, &size, &type );
549 if( size != src->size )
550 return LSMASH_ERR_INVALID_DATA;
551 uint8_t *end = src->data.unstructured + src->size;
552 isom_wave_t *wave = lsmash_malloc_zero( sizeof(isom_wave_t) );
553 if( !wave )
554 return LSMASH_ERR_MEMORY_ALLOC;
555 wave->type = QT_BOX_TYPE_WAVE;
556 for( uint8_t *pos = data; pos + ISOM_BASEBOX_COMMON_SIZE <= end; )
558 offset = isom_description_read_box_common( &pos, &size, &type );
559 switch( type )
561 case QT_BOX_TYPE_FRMA :
563 if( pos + 4 > end )
564 return LSMASH_ERR_INVALID_DATA;
565 isom_frma_t *frma = isom_add_frma( wave );
566 if( !frma )
567 return LSMASH_ERR_NAMELESS;
568 frma->data_format = LSMASH_GET_BE32( pos );
569 pos += 4;
570 break;
572 case QT_BOX_TYPE_ENDA :
574 if( pos + 2 > end )
575 return LSMASH_ERR_INVALID_DATA;
576 isom_enda_t *enda = isom_add_enda( wave );
577 if( !enda )
578 return LSMASH_ERR_NAMELESS;
579 enda->littleEndian = LSMASH_GET_BE16( pos );
580 break;
582 case QT_BOX_TYPE_MP4A :
584 if( pos + 4 > end )
585 return LSMASH_ERR_INVALID_DATA;
586 isom_mp4a_t *mp4a = isom_add_mp4a( wave );
587 if( !mp4a )
588 return LSMASH_ERR_NAMELESS;
589 mp4a->unknown = LSMASH_GET_BE32( pos );
590 pos += 4;
591 break;
593 case QT_BOX_TYPE_TERMINATOR :
595 if( !isom_add_terminator( wave ) )
596 return LSMASH_ERR_NAMELESS;
597 break;
599 default :
601 isom_unknown_box_t *box = lsmash_malloc_zero( sizeof(isom_unknown_box_t) );
602 if( !box )
603 return LSMASH_ERR_MEMORY_ALLOC;
604 isom_init_box_common( box, wave, type, isom_remove_unknown_box );
605 box->unknown_size = size - offset;
606 box->unknown_field = lsmash_memdup( pos, box->unknown_size );
607 if( !box->unknown_field )
609 lsmash_free( box );
610 return LSMASH_ERR_MEMORY_ALLOC;
612 if( lsmash_add_entry( &wave->extensions, box ) < 0 )
614 isom_remove_unknown_box( box );
615 return LSMASH_ERR_MEMORY_ALLOC;
617 pos += box->unknown_size;
618 break;
622 return 0;
624 #endif
626 /* structured <-> unstructured conversion might be irreversible by CODEC
627 * since structured formats we defined don't always have all contents included in unstructured data. */
628 lsmash_codec_specific_t *lsmash_convert_codec_specific_format( lsmash_codec_specific_t *specific, lsmash_codec_specific_format format )
630 if( !specific || format == LSMASH_CODEC_SPECIFIC_FORMAT_UNSPECIFIED )
631 return NULL;
632 if( format == specific->format )
633 return isom_duplicate_codec_specific_data( specific );
634 lsmash_codec_specific_t *dst = lsmash_create_codec_specific_data( specific->type, format );
635 if( format == LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED )
636 /* structured -> unstructured */
637 switch( specific->type )
639 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG :
640 dst->data.unstructured = lsmash_create_mp4sys_decoder_config( (lsmash_mp4sys_decoder_parameters_t *)specific->data.structured, &dst->size );
641 if( !dst->data.unstructured )
642 goto fail;
643 return dst;
644 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264 :
645 dst->data.unstructured = lsmash_create_h264_specific_info( (lsmash_h264_specific_parameters_t *)specific->data.structured, &dst->size );
646 if( !dst->data.unstructured )
647 goto fail;
648 return dst;
649 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_HEVC :
650 dst->data.unstructured = lsmash_create_hevc_specific_info( (lsmash_hevc_specific_parameters_t *)specific->data.structured, &dst->size );
651 if( !dst->data.unstructured )
652 goto fail;
653 return dst;
654 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_VC_1 :
655 dst->data.unstructured = lsmash_create_vc1_specific_info( (lsmash_vc1_specific_parameters_t *)specific->data.structured, &dst->size );
656 if( !dst->data.unstructured )
657 goto fail;
658 return dst;
659 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_AC_3 :
660 dst->data.unstructured = lsmash_create_ac3_specific_info( (lsmash_ac3_specific_parameters_t *)specific->data.structured, &dst->size );
661 if( !dst->data.unstructured )
662 goto fail;
663 return dst;
664 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_EC_3 :
665 dst->data.unstructured = lsmash_create_eac3_specific_info( (lsmash_eac3_specific_parameters_t *)specific->data.structured, &dst->size );
666 if( !dst->data.unstructured )
667 goto fail;
668 return dst;
669 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS :
670 dst->data.unstructured = lsmash_create_dts_specific_info( (lsmash_dts_specific_parameters_t *)specific->data.structured, &dst->size );
671 if( !dst->data.unstructured )
672 goto fail;
673 return dst;
674 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_ALAC :
675 dst->data.unstructured = lsmash_create_alac_specific_info( (lsmash_alac_specific_parameters_t *)specific->data.structured, &dst->size );
676 if( !dst->data.unstructured )
677 goto fail;
678 return dst;
679 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER :
681 lsmash_bs_t *bs = lsmash_bs_create();
682 if( !bs )
683 goto fail;
684 lsmash_codec_global_header_t *global = specific->data.structured;
685 lsmash_bs_put_be32( bs, ISOM_BASEBOX_COMMON_SIZE + global->header_size );
686 lsmash_bs_put_be32( bs, QT_BOX_TYPE_GLBL.fourcc );
687 lsmash_bs_put_bytes( bs, global->header_size, global->header_data );
688 dst->data.unstructured = lsmash_bs_export_data( bs, &dst->size );
689 lsmash_bs_cleanup( bs );
690 if( !dst->data.unstructured || dst->size != (ISOM_BASEBOX_COMMON_SIZE + global->header_size) )
691 goto fail;
692 return dst;
694 default :
695 break;
697 else if( format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
699 /* unstructured -> structured */
700 extern int mp4sys_construct_decoder_config( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
701 extern int h264_construct_specific_parameters( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
702 extern int hevc_construct_specific_parameters( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
703 extern int vc1_construct_specific_parameters( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
704 extern int ac3_construct_specific_parameters( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
705 extern int eac3_construct_specific_parameters( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
706 extern int dts_construct_specific_parameters( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
707 extern int alac_construct_specific_parameters( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
708 static const struct
710 lsmash_codec_specific_data_type data_type;
711 int (*constructor)( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
712 } codec_specific_format_constructor_table[] =
714 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG, mp4sys_construct_decoder_config },
715 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264, h264_construct_specific_parameters },
716 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_HEVC, hevc_construct_specific_parameters },
717 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_VC_1, vc1_construct_specific_parameters },
718 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_AC_3, ac3_construct_specific_parameters },
719 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_EC_3, eac3_construct_specific_parameters },
720 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS, dts_construct_specific_parameters },
721 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_ALAC, alac_construct_specific_parameters },
722 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER, isom_construct_global_specific_header },
723 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT, isom_construct_audio_channel_layout },
724 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN, NULL }
726 int (*constructor)( lsmash_codec_specific_t *, lsmash_codec_specific_t * ) = NULL;
727 for( int i = 0; codec_specific_format_constructor_table[i].constructor; i++ )
728 if( specific->type == codec_specific_format_constructor_table[i].data_type )
730 constructor = codec_specific_format_constructor_table[i].constructor;
731 break;
733 if( constructor && !constructor( dst, specific ) )
734 return dst;
736 fail:
737 lsmash_destroy_codec_specific_data( dst );
738 return NULL;
741 static inline void isom_set_default_compressorname( char *compressorname, lsmash_codec_type_t sample_type )
743 static struct compressorname_table_tag
745 lsmash_codec_type_t type;
746 char name[33];
747 } compressorname_table[32] = { { LSMASH_CODEC_TYPE_INITIALIZER, { '\0' } } };
748 if( compressorname_table[0].name[0] == '\0' )
750 int i = 0;
751 #define ADD_COMPRESSORNAME_TABLE( type, name ) compressorname_table[i++] = (struct compressorname_table_tag){ type, name }
752 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_AVC1_VIDEO, "\012AVC Coding" );
753 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_AVC2_VIDEO, "\012AVC Coding" );
754 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_AVC3_VIDEO, "\012AVC Coding" );
755 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_AVC4_VIDEO, "\012AVC Coding" );
756 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_AVCP_VIDEO, "\016AVC Parameters" );
757 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_HVC1_VIDEO, "\013HEVC Coding" );
758 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_HEV1_VIDEO, "\013HEVC Coding" );
759 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_SVC1_VIDEO, "\012SVC Coding" );
760 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_MVC1_VIDEO, "\012MVC Coding" );
761 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_MVC2_VIDEO, "\012MVC Coding" );
762 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_APCH_VIDEO, "\023Apple ProRes 422 (HQ)" );
763 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_APCN_VIDEO, "\023Apple ProRes 422 (SD)" );
764 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_APCS_VIDEO, "\023Apple ProRes 422 (LT)" );
765 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_APCO_VIDEO, "\026Apple ProRes 422 (Proxy)" );
766 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_AP4H_VIDEO, "\019Apple ProRes 4444" );
767 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DVPP_VIDEO, "\014DVCPRO - PAL" );
768 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DV5N_VIDEO, "\017DVCPRO50 - NTSC" );
769 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DV5P_VIDEO, "\016DVCPRO50 - PAL" );
770 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DVH2_VIDEO, "\019DVCPRO HD 1080p25" );
771 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DVH3_VIDEO, "\019DVCPRO HD 1080p30" );
772 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DVH5_VIDEO, "\019DVCPRO HD 1080i50" );
773 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DVH6_VIDEO, "\019DVCPRO HD 1080i60" );
774 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DVHP_VIDEO, "\018DVCPRO HD 720p60" );
775 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DVHQ_VIDEO, "\018DVCPRO HD 720p50" );
776 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_ULRA_VIDEO, "\017Ut Video (ULRA)" );
777 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_ULRG_VIDEO, "\017Ut Video (ULRG)" );
778 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_ULY0_VIDEO, "\017Ut Video (ULY0)" );
779 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_ULY2_VIDEO, "\017Ut Video (ULY2)" );
780 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_ULH0_VIDEO, "\017Ut Video (ULH0)" );
781 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_ULH2_VIDEO, "\017Ut Video (ULH2)" );
782 ADD_COMPRESSORNAME_TABLE( LSMASH_CODEC_TYPE_UNSPECIFIED, { '\0' } );
783 #undef ADD_COMPRESSORNAME_TABLE
785 for( int i = 0; compressorname_table[i].name[0] != '\0'; i++ )
786 if( lsmash_check_codec_type_identical( sample_type, compressorname_table[i].type ) )
788 strcpy( compressorname, compressorname_table[i].name );
789 return;
793 lsmash_codec_specific_t *isom_get_codec_specific( lsmash_codec_specific_list_t *opaque, lsmash_codec_specific_data_type type )
795 for( lsmash_entry_t *entry = opaque->list.head; entry; entry = entry->next )
797 lsmash_codec_specific_t *specific = (lsmash_codec_specific_t *)entry->data;
798 if( !specific || specific->type != type )
799 continue;
800 return specific;
802 return NULL;
805 static int isom_check_valid_summary( lsmash_summary_t *summary )
807 if( !summary )
808 return LSMASH_ERR_NAMELESS;
809 isom_box_t temp_box;
810 temp_box.type = summary->sample_type;
811 temp_box.manager = summary->summary_type == LSMASH_SUMMARY_TYPE_AUDIO ? LSMASH_AUDIO_DESCRIPTION: 0;
812 if( isom_is_lpcm_audio( &temp_box ) )
814 if( isom_get_codec_specific( summary->opaque, LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS ) )
815 return 0;
816 return LSMASH_ERR_INVALID_DATA;
818 if( isom_is_uncompressed_ycbcr( summary->sample_type ) )
820 if( isom_get_codec_specific( summary->opaque, LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_FIELD_INFO ) )
822 if( !lsmash_check_codec_type_identical( summary->sample_type, QT_CODEC_TYPE_V216_VIDEO ) )
823 return 0;
825 else
826 return LSMASH_ERR_INVALID_DATA;
828 lsmash_codec_type_t sample_type = summary->sample_type;
829 lsmash_codec_specific_data_type required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNSPECIFIED;
830 if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_AVC1_VIDEO )
831 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_AVC2_VIDEO )
832 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_AVC3_VIDEO )
833 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_AVC4_VIDEO ) )
834 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264;
835 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_HVC1_VIDEO )
836 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_HEV1_VIDEO ) )
837 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_HEVC;
838 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_VC_1_VIDEO ) )
839 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_VC_1 ;
840 else if( lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_ULRA_VIDEO )
841 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_ULRG_VIDEO )
842 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_ULY0_VIDEO )
843 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_ULY2_VIDEO )
844 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_ULH0_VIDEO )
845 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_ULH2_VIDEO ) )
846 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER;
847 else if( lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_V216_VIDEO ) )
848 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_SIGNIFICANT_BITS;
849 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_MP4V_VIDEO )
850 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_MP4A_AUDIO )
851 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_MP4A_AUDIO ) )
852 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG;
853 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_AC_3_AUDIO ) )
854 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_AC_3;
855 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_EC_3_AUDIO ) )
856 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_EC_3;
857 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_DTSC_AUDIO )
858 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_DTSE_AUDIO )
859 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_DTSH_AUDIO )
860 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_DTSL_AUDIO ) )
861 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS;
862 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_ALAC_AUDIO )
863 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_ALAC_AUDIO ) )
864 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_ALAC;
865 if( required_data_type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNSPECIFIED )
866 return 0;
867 return isom_get_codec_specific( summary->opaque, required_data_type ) ? 0 : LSMASH_ERR_INVALID_DATA;
870 static lsmash_box_type_t isom_guess_video_codec_specific_box_type( lsmash_codec_type_t active_codec_type, lsmash_compact_box_type_t fourcc )
872 lsmash_box_type_t box_type = LSMASH_BOX_TYPE_INITIALIZER;
873 box_type.fourcc = fourcc;
874 #define GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( codec_type, predefined_box_type ) \
875 else if( (codec_type.user.fourcc == 0 \
876 || lsmash_check_codec_type_identical( active_codec_type, codec_type )) \
877 && box_type.fourcc == predefined_box_type.fourcc ) \
878 box_type = predefined_box_type
879 if( 0 );
880 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_AVC1_VIDEO, ISOM_BOX_TYPE_AVCC );
881 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_AVC2_VIDEO, ISOM_BOX_TYPE_AVCC );
882 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_AVC3_VIDEO, ISOM_BOX_TYPE_AVCC );
883 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_AVC4_VIDEO, ISOM_BOX_TYPE_AVCC );
884 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_AVCP_VIDEO, ISOM_BOX_TYPE_AVCC );
885 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_HVC1_VIDEO, ISOM_BOX_TYPE_HVCC );
886 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_HEV1_VIDEO, ISOM_BOX_TYPE_HVCC );
887 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_VC_1_VIDEO, ISOM_BOX_TYPE_DVC1 );
888 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_MP4V_VIDEO, ISOM_BOX_TYPE_ESDS );
889 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, ISOM_BOX_TYPE_BTRT );
890 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, QT_BOX_TYPE_FIEL );
891 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, QT_BOX_TYPE_CSPC );
892 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, QT_BOX_TYPE_SGBT );
893 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, QT_BOX_TYPE_GAMA );
894 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, QT_BOX_TYPE_GLBL );
895 #undef GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE
896 return box_type;
899 int isom_setup_visual_description( isom_stsd_t *stsd, lsmash_codec_type_t sample_type, lsmash_video_summary_t *summary )
901 if( !summary
902 || !stsd
903 || !stsd->parent
904 || !stsd->parent->parent
905 || !stsd->parent->parent->parent
906 || !stsd->parent->parent->parent->parent )
907 return LSMASH_ERR_NAMELESS;
908 int err = isom_check_valid_summary( (lsmash_summary_t *)summary );
909 if( err < 0 )
910 return err;
911 isom_visual_entry_t *visual = isom_add_visual_description( stsd, sample_type );
912 if( !visual )
913 return LSMASH_ERR_NAMELESS;
914 visual->data_reference_index = summary->data_ref_index;
915 visual->version = 0;
916 visual->revision_level = 0;
917 visual->vendor = 0;
918 visual->temporalQuality = 0;
919 visual->spatialQuality = 0;
920 visual->width = (uint16_t)summary->width;
921 visual->height = (uint16_t)summary->height;
922 visual->horizresolution = 0x00480000;
923 visual->vertresolution = 0x00480000;
924 visual->dataSize = 0;
925 visual->frame_count = 1;
926 visual->depth = isom_is_qt_video( summary->sample_type ) || isom_is_nalff( summary->sample_type )
927 ? summary->depth : 0x0018;
928 visual->color_table_ID = -1;
929 if( summary->compressorname[0] == '\0' )
930 isom_set_default_compressorname( visual->compressorname, sample_type );
931 else
933 memcpy( visual->compressorname, summary->compressorname, 32 );
934 visual->compressorname[32] = '\0';
936 err = LSMASH_ERR_NAMELESS;
937 for( lsmash_entry_t *entry = summary->opaque->list.head; entry; entry = entry->next )
939 lsmash_codec_specific_t *specific = (lsmash_codec_specific_t *)entry->data;
940 if( !specific )
941 goto fail;
942 if( specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN
943 && specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
944 continue; /* LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN + LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED is not supported. */
945 switch( specific->type )
947 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_COMMON :
949 if( specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED )
950 continue;
951 lsmash_qt_video_common_t *data = (lsmash_qt_video_common_t *)specific->data.structured;
952 visual->revision_level = data->revision_level;
953 visual->vendor = data->vendor;
954 visual->temporalQuality = data->temporalQuality;
955 visual->spatialQuality = data->spatialQuality;
956 visual->horizresolution = data->horizontal_resolution;
957 visual->vertresolution = data->vertical_resolution;
958 visual->dataSize = data->dataSize;
959 visual->frame_count = data->frame_count;
960 visual->color_table_ID = data->color_table_ID;
961 if( data->color_table_ID == 0 )
963 lsmash_qt_color_table_t *src_ct = &data->color_table;
964 uint16_t element_count = LSMASH_MIN( src_ct->size + 1, 256 );
965 isom_qt_color_array_t *dst_array = lsmash_malloc_zero( element_count * sizeof(isom_qt_color_array_t) );
966 if( !dst_array )
968 err = LSMASH_ERR_MEMORY_ALLOC;
969 goto fail;
971 isom_qt_color_table_t *dst_ct = &visual->color_table;
972 dst_ct->array = dst_array;
973 dst_ct->seed = src_ct->seed;
974 dst_ct->flags = src_ct->flags;
975 dst_ct->size = src_ct->size;
976 for( uint16_t i = 0; i < element_count; i++ )
978 dst_array[i].value = src_ct->array[i].unused;
979 dst_array[i].r = src_ct->array[i].r;
980 dst_array[i].g = src_ct->array[i].g;
981 dst_array[i].b = src_ct->array[i].b;
984 break;
986 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_SAMPLE_SCALE :
988 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
989 if( !cs )
990 goto fail;
991 lsmash_isom_sample_scale_t *data = (lsmash_isom_sample_scale_t *)cs->data.structured;
992 isom_stsl_t *stsl = isom_add_stsl( visual );
993 if( !stsl )
995 lsmash_destroy_codec_specific_data( cs );
996 goto fail;
998 stsl->constraint_flag = data->constraint_flag;
999 stsl->scale_method = data->scale_method;
1000 stsl->display_center_x = data->display_center_x;
1001 stsl->display_center_y = data->display_center_y;
1002 lsmash_destroy_codec_specific_data( cs );
1003 break;
1005 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264_BITRATE :
1007 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
1008 if( !cs )
1009 goto fail;
1010 lsmash_h264_bitrate_t *data = (lsmash_h264_bitrate_t *)cs->data.structured;
1011 isom_btrt_t *btrt = isom_add_btrt( visual );
1012 if( !btrt )
1014 lsmash_destroy_codec_specific_data( cs );
1015 goto fail;
1017 btrt->bufferSizeDB = data->bufferSizeDB;
1018 btrt->maxBitrate = data->maxBitrate;
1019 btrt->avgBitrate = data->avgBitrate;
1020 lsmash_destroy_codec_specific_data( cs );
1021 break;
1023 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_FIELD_INFO :
1025 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
1026 if( !cs )
1027 goto fail;
1028 lsmash_qt_field_info_t *data = (lsmash_qt_field_info_t *)cs->data.structured;
1029 isom_fiel_t *fiel = isom_add_fiel( visual );
1030 if( !fiel )
1032 lsmash_destroy_codec_specific_data( cs );
1033 goto fail;
1035 fiel->fields = data->fields;
1036 fiel->detail = data->detail;
1037 lsmash_destroy_codec_specific_data( cs );
1038 break;
1040 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_PIXEL_FORMAT :
1042 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
1043 if( !cs )
1044 goto fail;
1045 lsmash_qt_pixel_format_t *data = (lsmash_qt_pixel_format_t *)cs->data.structured;
1046 isom_cspc_t *cspc = isom_add_cspc( visual );
1047 if( !cspc )
1049 lsmash_destroy_codec_specific_data( cs );
1050 goto fail;
1052 cspc->pixel_format = data->pixel_format;
1053 lsmash_destroy_codec_specific_data( cs );
1054 break;
1056 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_SIGNIFICANT_BITS :
1058 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
1059 if( !cs )
1060 goto fail;
1061 lsmash_qt_significant_bits_t *data = (lsmash_qt_significant_bits_t *)cs->data.structured;
1062 isom_sgbt_t *sgbt = isom_add_sgbt( visual );
1063 if( !sgbt )
1065 lsmash_destroy_codec_specific_data( cs );
1066 goto fail;
1068 sgbt->significantBits = data->significantBits;
1069 lsmash_destroy_codec_specific_data( cs );
1070 break;
1072 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_GAMMA_LEVEL :
1074 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
1075 if( !cs )
1076 goto fail;
1077 lsmash_qt_gamma_t *data = (lsmash_qt_gamma_t *)cs->data.structured;
1078 isom_gama_t *gama = isom_add_gama( visual );
1079 if( !gama )
1081 lsmash_destroy_codec_specific_data( cs );
1082 goto fail;
1084 gama->level = data->level;
1085 lsmash_destroy_codec_specific_data( cs );
1086 break;
1088 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER :
1090 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
1091 if( !cs )
1092 goto fail;
1093 lsmash_codec_global_header_t *data = (lsmash_codec_global_header_t *)cs->data.structured;
1094 isom_glbl_t *glbl = isom_add_glbl( visual );
1095 if( !glbl )
1097 lsmash_destroy_codec_specific_data( cs );
1098 goto fail;
1100 glbl->header_size = data->header_size;
1101 glbl->header_data = lsmash_memdup( data->header_data, data->header_size );
1102 lsmash_destroy_codec_specific_data( cs );
1103 if( !glbl->header_data )
1105 isom_remove_box_by_itself( glbl );
1106 err = LSMASH_ERR_MEMORY_ALLOC;
1107 goto fail;
1109 break;
1111 default :
1113 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
1114 if( !cs )
1115 goto fail;
1116 if( cs->size < ISOM_BASEBOX_COMMON_SIZE )
1118 lsmash_destroy_codec_specific_data( cs );
1119 err = LSMASH_ERR_INVALID_DATA;
1120 goto fail;
1122 uint8_t *data = cs->data.unstructured;
1123 lsmash_compact_box_type_t fourcc = LSMASH_4CC( data[4], data[5], data[6], data[7] );
1124 lsmash_box_type_t box_type = isom_guess_video_codec_specific_box_type( visual->type, fourcc );
1125 /* Append the extension. */
1126 err = isom_add_extension_binary( visual, box_type, LSMASH_BOX_PRECEDENCE_HM, cs->data.unstructured, cs->size );
1127 cs->data.unstructured = NULL; /* Avoid freeing the binary data of the extension. */
1128 lsmash_destroy_codec_specific_data( cs );
1129 if( err < 0 )
1130 goto fail;
1131 break;
1135 isom_trak_t *trak = (isom_trak_t *)visual->parent->parent->parent->parent->parent;
1136 int qt_compatible = trak->file->qt_compatible;
1137 isom_tapt_t *tapt = trak->tapt;
1138 isom_stsl_t *stsl = (isom_stsl_t *)isom_get_extension_box_format( &visual->extensions, ISOM_BOX_TYPE_STSL );
1139 int set_aperture_modes = qt_compatible /* Track Aperture Modes is only available under QuickTime file format. */
1140 && (!stsl || stsl->scale_method == 0) /* Sample scaling method might conflict with this feature. */
1141 && tapt && tapt->clef && tapt->prof && tapt->enof /* Check if required boxes exist. */
1142 && ((isom_stsd_t *)visual->parent)->list.entry_count == 1; /* Multiple sample description might conflict with this, so in that case, disable this feature. */
1143 if( !set_aperture_modes )
1144 isom_remove_box_by_itself( trak->tapt );
1145 int uncompressed_ycbcr = qt_compatible && isom_is_uncompressed_ycbcr( visual->type );
1146 /* Set up Clean Aperture. */
1147 if( set_aperture_modes || uncompressed_ycbcr
1148 || (summary->clap.width.d && summary->clap.height.d && summary->clap.horizontal_offset.d && summary->clap.vertical_offset.d) )
1150 isom_clap_t *clap = isom_add_clap( visual );
1151 if( !clap )
1152 goto fail;
1153 if( summary->clap.width.d && summary->clap.height.d && summary->clap.horizontal_offset.d && summary->clap.vertical_offset.d )
1155 clap->cleanApertureWidthN = summary->clap.width.n;
1156 clap->cleanApertureWidthD = summary->clap.width.d;
1157 clap->cleanApertureHeightN = summary->clap.height.n;
1158 clap->cleanApertureHeightD = summary->clap.height.d;
1159 clap->horizOffN = summary->clap.horizontal_offset.n;
1160 clap->horizOffD = summary->clap.horizontal_offset.d;
1161 clap->vertOffN = summary->clap.vertical_offset.n;
1162 clap->vertOffD = summary->clap.vertical_offset.d;
1164 else
1166 clap->cleanApertureWidthN = summary->width;
1167 clap->cleanApertureWidthD = 1;
1168 clap->cleanApertureHeightN = summary->height;
1169 clap->cleanApertureHeightD = 1;
1170 clap->horizOffN = 0;
1171 clap->horizOffD = 1;
1172 clap->vertOffN = 0;
1173 clap->vertOffD = 1;
1176 /* Set up Pixel Aspect Ratio. */
1177 if( set_aperture_modes || (summary->par_h && summary->par_v) )
1179 isom_pasp_t *pasp = isom_add_pasp( visual );
1180 if( !pasp )
1181 goto fail;
1182 pasp->hSpacing = LSMASH_MAX( summary->par_h, 1 );
1183 pasp->vSpacing = LSMASH_MAX( summary->par_v, 1 );
1185 /* Set up Color Parameter. */
1186 if( uncompressed_ycbcr
1187 || summary->color.primaries_index
1188 || summary->color.transfer_index
1189 || summary->color.matrix_index
1190 || (trak->file->isom_compatible && summary->color.full_range) )
1192 isom_colr_t *colr = isom_add_colr( visual );
1193 if( !colr )
1194 goto fail;
1195 /* Set 'nclc' to parameter type, we don't support 'prof'. */
1196 uint16_t primaries = summary->color.primaries_index;
1197 uint16_t transfer = summary->color.transfer_index;
1198 uint16_t matrix = summary->color.matrix_index;
1199 if( qt_compatible && !trak->file->isom_compatible )
1201 colr->manager |= LSMASH_QTFF_BASE;
1202 colr->type = QT_BOX_TYPE_COLR;
1203 colr->color_parameter_type = QT_COLOR_PARAMETER_TYPE_NCLC;
1204 colr->primaries_index = (primaries == 1 || primaries == 5 || primaries == 6)
1205 ? primaries : QT_PRIMARIES_INDEX_UNSPECIFIED;
1206 colr->transfer_function_index = (transfer == 1 || transfer == 7)
1207 ? transfer : QT_TRANSFER_INDEX_UNSPECIFIED;
1208 colr->matrix_index = (matrix == 1 || matrix == 6 || matrix == 7)
1209 ? matrix : QT_MATRIX_INDEX_UNSPECIFIED;
1211 else
1213 colr->type = ISOM_BOX_TYPE_COLR;
1214 colr->color_parameter_type = ISOM_COLOR_PARAMETER_TYPE_NCLX;
1215 colr->primaries_index = (primaries == 1 || (primaries >= 4 && primaries <= 7))
1216 ? primaries : ISOM_PRIMARIES_INDEX_UNSPECIFIED;
1217 colr->transfer_function_index = (transfer == 1 || (transfer >= 4 && transfer <= 8) || (transfer >= 11 && transfer <= 13))
1218 ? transfer : ISOM_TRANSFER_INDEX_UNSPECIFIED;
1219 colr->matrix_index = (matrix == 1 || (matrix >= 4 && matrix <= 8))
1220 ? matrix : ISOM_MATRIX_INDEX_UNSPECIFIED;
1221 colr->full_range_flag = summary->color.full_range;
1224 /* Set up Track Apeture Modes. */
1225 if( set_aperture_modes )
1227 uint32_t width = visual->width << 16;
1228 uint32_t height = visual->height << 16;
1229 isom_clap_t *clap = (isom_clap_t *)isom_get_extension_box_format( &visual->extensions, ISOM_BOX_TYPE_CLAP );
1230 isom_pasp_t *pasp = (isom_pasp_t *)isom_get_extension_box_format( &visual->extensions, ISOM_BOX_TYPE_PASP );
1231 double clap_width = ((double)clap->cleanApertureWidthN / clap->cleanApertureWidthD) * (1<<16);
1232 double clap_height = ((double)clap->cleanApertureHeightN / clap->cleanApertureHeightD) * (1<<16);
1233 double par = (double)pasp->hSpacing / pasp->vSpacing;
1234 if( par >= 1.0 )
1236 tapt->clef->width = clap_width * par;
1237 tapt->clef->height = clap_height;
1238 tapt->prof->width = width * par;
1239 tapt->prof->height = height;
1241 else
1243 tapt->clef->width = clap_width;
1244 tapt->clef->height = clap_height / par;
1245 tapt->prof->width = width;
1246 tapt->prof->height = height / par;
1248 tapt->enof->width = width;
1249 tapt->enof->height = height;
1251 return 0;
1252 fail:
1253 isom_remove_box_by_itself( visual );
1254 return err;
1257 static int isom_append_audio_es_descriptor_extension( isom_box_t *box, lsmash_audio_summary_t *summary )
1259 uint32_t esds_size = 0;
1260 uint8_t *esds_data = NULL;
1261 lsmash_codec_specific_t *specific = isom_get_codec_specific( summary->opaque, LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG );
1262 if( !specific )
1263 return LSMASH_ERR_NAMELESS;
1264 if( specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED )
1266 esds_size = specific->size;
1267 esds_data = lsmash_memdup( specific->data.unstructured, specific->size );
1268 if( !esds_data )
1269 return LSMASH_ERR_MEMORY_ALLOC;
1271 else
1273 esds_data = lsmash_create_mp4sys_decoder_config( (lsmash_mp4sys_decoder_parameters_t *)specific->data.structured, &esds_size );
1274 if( !esds_data )
1275 return LSMASH_ERR_NAMELESS;
1277 isom_esds_t *esds = isom_add_esds( box );
1278 if( !esds )
1280 lsmash_free( esds_data );
1281 return LSMASH_ERR_NAMELESS;
1283 lsmash_bs_t bs = { 0 };
1284 bs.buffer.data = esds_data + ISOM_FULLBOX_COMMON_SIZE;
1285 bs.buffer.alloc = esds_size - ISOM_FULLBOX_COMMON_SIZE;
1286 bs.buffer.store = bs.buffer.alloc;
1287 esds->ES = mp4sys_get_descriptor( &bs, NULL );
1288 lsmash_free( esds_data );
1289 if( !esds->ES )
1291 isom_remove_box_by_itself( esds );
1292 return LSMASH_ERR_NAMELESS;
1294 return 0;
1297 static int isom_append_channel_layout_extension( lsmash_codec_specific_t *specific, void *parent, uint32_t channels )
1299 assert( parent );
1300 if( isom_get_extension_box( &((isom_box_t *)parent)->extensions, QT_BOX_TYPE_CHAN ) )
1301 return 0; /* Audio Channel Layout Box is already present. */
1302 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
1303 if( !cs )
1304 return LSMASH_ERR_NAMELESS;
1305 lsmash_qt_audio_channel_layout_t *data = (lsmash_qt_audio_channel_layout_t *)cs->data.structured;
1306 lsmash_channel_layout_tag channelLayoutTag = data->channelLayoutTag;
1307 lsmash_channel_bitmap channelBitmap = data->channelBitmap;
1308 if( channelLayoutTag == QT_CHANNEL_LAYOUT_USE_CHANNEL_DESCRIPTIONS /* We don't support the feature of Channel Descriptions. */
1309 || (channelLayoutTag == QT_CHANNEL_LAYOUT_USE_CHANNEL_BITMAP && (!channelBitmap || channelBitmap > QT_CHANNEL_BIT_FULL)) )
1311 channelLayoutTag = QT_CHANNEL_LAYOUT_UNKNOWN | channels;
1312 channelBitmap = 0;
1314 lsmash_destroy_codec_specific_data( cs );
1315 /* Don't create Audio Channel Layout Box if the channel layout is unknown. */
1316 if( (channelLayoutTag ^ QT_CHANNEL_LAYOUT_UNKNOWN) >> 16 )
1318 isom_chan_t *chan = isom_add_chan( parent );
1319 if( !chan )
1320 return LSMASH_ERR_NAMELESS;
1321 chan->channelLayoutTag = channelLayoutTag;
1322 chan->channelBitmap = channelBitmap;
1323 chan->numberChannelDescriptions = 0;
1324 chan->channelDescriptions = NULL;
1326 return 0;
1329 static int isom_set_qtff_mp4a_description( isom_audio_entry_t *audio, lsmash_audio_summary_t *summary )
1331 isom_wave_t *wave = isom_add_wave( audio );
1332 isom_frma_t *frma;
1333 if( !(frma = isom_add_frma( wave ))
1334 || !isom_add_mp4a( wave )
1335 || !isom_add_terminator( wave ) )
1337 lsmash_remove_entry_tail( &audio->extensions, wave->destruct );
1338 return LSMASH_ERR_NAMELESS;
1340 frma->data_format = audio->type.fourcc;
1341 /* Add ES Descriptor Box. */
1342 int err = isom_append_audio_es_descriptor_extension( (isom_box_t *)wave, summary );
1343 if( err < 0 )
1344 return err;
1345 /* */
1346 audio->type = QT_CODEC_TYPE_MP4A_AUDIO;
1347 audio->version = (summary->channels > 2 || summary->frequency > UINT16_MAX) ? 2 : 1;
1348 audio->channelcount = audio->version == 2 ? 3 : LSMASH_MIN( summary->channels, 2 );
1349 audio->samplesize = 16;
1350 audio->compression_ID = QT_AUDIO_COMPRESSION_ID_VARIABLE_COMPRESSION;
1351 audio->packet_size = 0;
1352 if( audio->version == 1 )
1354 audio->samplerate = summary->frequency << 16;
1355 audio->samplesPerPacket = summary->samples_in_frame;
1356 audio->bytesPerPacket = 1; /* Apparently, this field is set to 1. */
1357 audio->bytesPerFrame = audio->bytesPerPacket * summary->channels;
1358 audio->bytesPerSample = 2;
1360 else /* audio->version == 2 */
1362 audio->samplerate = 0x00010000;
1363 audio->sizeOfStructOnly = 72;
1364 audio->audioSampleRate = (union {double d; uint64_t i;}){summary->frequency}.i;
1365 audio->numAudioChannels = summary->channels;
1366 audio->always7F000000 = 0x7F000000;
1367 audio->constBitsPerChannel = 0; /* compressed audio */
1368 audio->formatSpecificFlags = 0;
1369 audio->constBytesPerAudioPacket = 0; /* variable */
1370 audio->constLPCMFramesPerAudioPacket = summary->samples_in_frame;
1372 return 0;
1375 static int isom_set_isom_mp4a_description( isom_audio_entry_t *audio, lsmash_audio_summary_t *summary )
1377 if( summary->summary_type != LSMASH_SUMMARY_TYPE_AUDIO )
1378 return LSMASH_ERR_NAMELESS;
1379 /* Check objectTypeIndication. */
1380 lsmash_mp4sys_object_type_indication objectTypeIndication = lsmash_mp4sys_get_object_type_indication( (lsmash_summary_t *)summary );
1381 switch( objectTypeIndication )
1383 case MP4SYS_OBJECT_TYPE_Audio_ISO_14496_3:
1384 case MP4SYS_OBJECT_TYPE_Audio_ISO_13818_7_Main_Profile:
1385 case MP4SYS_OBJECT_TYPE_Audio_ISO_13818_7_LC_Profile:
1386 case MP4SYS_OBJECT_TYPE_Audio_ISO_13818_7_SSR_Profile:
1387 case MP4SYS_OBJECT_TYPE_Audio_ISO_13818_3: /* Legacy Interface */
1388 case MP4SYS_OBJECT_TYPE_Audio_ISO_11172_3: /* Legacy Interface */
1389 break;
1390 default:
1391 return LSMASH_ERR_NAMELESS;
1393 /* Add ES Descriptor Box. */
1394 int err = isom_append_audio_es_descriptor_extension( (isom_box_t *)audio, summary );
1395 if( err < 0 )
1396 return err;
1397 /* In pure mp4 file, these "template" fields shall be default values according to the spec.
1398 But not pure - hybrid with other spec - mp4 file can take other values.
1399 Which is to say, these template values shall be ignored in terms of mp4, except some object_type_indications.
1400 see 14496-14, "Template fields used". */
1401 audio->type = ISOM_CODEC_TYPE_MP4A_AUDIO;
1402 audio->version = 0;
1403 audio->revision_level = 0;
1404 audio->vendor = 0;
1405 audio->channelcount = 2;
1406 audio->samplesize = 16;
1407 audio->compression_ID = 0;
1408 audio->packet_size = 0;
1409 /* WARNING: This field cannot retain frequency above 65535Hz.
1410 This is not "FIXME", I just honestly implemented what the spec says.
1411 BTW, who ever expects sampling frequency takes fixed-point decimal??? */
1412 audio->samplerate = summary->frequency <= UINT16_MAX ? summary->frequency << 16 : 0;
1413 return 0;
1416 static int isom_set_qtff_lpcm_description( isom_audio_entry_t *audio, lsmash_audio_summary_t *summary )
1418 lsmash_qt_audio_format_specific_flags_t *lpcm = NULL;
1419 for( lsmash_entry_t *entry = summary->opaque->list.head; entry; entry = entry->next )
1421 lsmash_codec_specific_t *specific = (lsmash_codec_specific_t *)entry->data;
1422 if( !specific )
1423 continue;
1424 if( specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS
1425 && specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
1427 lpcm = (lsmash_qt_audio_format_specific_flags_t *)specific->data.structured;
1428 break;
1431 if( !lpcm )
1432 return LSMASH_ERR_NAMELESS;
1433 audio->manager |= LSMASH_QTFF_BASE;
1434 lsmash_codec_type_t sample_type = audio->type;
1435 /* Convert the sample type into 'lpcm' if the description doesn't match the format or version = 2 fields are needed. */
1436 if( (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_RAW_AUDIO )
1437 && (summary->sample_size != 8 || (lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT)))
1438 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_FL32_AUDIO )
1439 && (summary->sample_size != 32 || !(lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT)))
1440 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_FL64_AUDIO )
1441 && (summary->sample_size != 64 || !(lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT)))
1442 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_IN24_AUDIO )
1443 && (summary->sample_size != 24 || (lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT)))
1444 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_IN32_AUDIO )
1445 && (summary->sample_size != 32 || (lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT)))
1446 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_23NI_AUDIO )
1447 && (summary->sample_size != 32 || (lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT) || (lpcm->format_flags & QT_LPCM_FORMAT_FLAG_BIG_ENDIAN)))
1448 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_SOWT_AUDIO )
1449 && (summary->sample_size != 16 || (lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT) || (lpcm->format_flags & QT_LPCM_FORMAT_FLAG_BIG_ENDIAN)))
1450 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_TWOS_AUDIO )
1451 && ((summary->sample_size != 16 && summary->sample_size != 8) || (lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT) || !(lpcm->format_flags & QT_LPCM_FORMAT_FLAG_BIG_ENDIAN)))
1452 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_NONE_AUDIO )
1453 && ((summary->sample_size != 16 && summary->sample_size != 8) || (lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT) || !(lpcm->format_flags & QT_LPCM_FORMAT_FLAG_BIG_ENDIAN)))
1454 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_NOT_SPECIFIED )
1455 && ((summary->sample_size != 16 && summary->sample_size != 8) || (lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT) || !(lpcm->format_flags & QT_LPCM_FORMAT_FLAG_BIG_ENDIAN)))
1456 || (summary->channels > 2 || summary->frequency > UINT16_MAX || summary->sample_size % 8) )
1458 audio->type = QT_CODEC_TYPE_LPCM_AUDIO;
1459 audio->version = 2;
1461 else if( lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_LPCM_AUDIO ) )
1462 audio->version = 2;
1463 else if( summary->sample_size > 16
1464 || (!lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_RAW_AUDIO )
1465 && !lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_TWOS_AUDIO )
1466 && !lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_NONE_AUDIO )
1467 && !lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_NOT_SPECIFIED )) )
1468 audio->version = 1;
1469 /* Set up constBytesPerAudioPacket field.
1470 * We use constBytesPerAudioPacket as the actual size of LPCM audio frame even when version is not 2. */
1471 audio->constBytesPerAudioPacket = (summary->sample_size * summary->channels) / 8;
1472 /* Set up other fields in this description by its version. */
1473 if( audio->version == 2 )
1475 audio->channelcount = 3;
1476 audio->samplesize = 16;
1477 audio->compression_ID = -2;
1478 audio->samplerate = 0x00010000;
1479 audio->sizeOfStructOnly = 72;
1480 audio->audioSampleRate = (union {double d; uint64_t i;}){summary->frequency}.i;
1481 audio->numAudioChannels = summary->channels;
1482 audio->always7F000000 = 0x7F000000;
1483 audio->constBitsPerChannel = summary->sample_size;
1484 audio->constLPCMFramesPerAudioPacket = 1;
1485 audio->formatSpecificFlags = lpcm->format_flags;
1486 if( lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_TWOS_AUDIO ) && summary->sample_size != 8 )
1487 audio->formatSpecificFlags |= QT_LPCM_FORMAT_FLAG_BIG_ENDIAN;
1488 if( lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT )
1489 audio->formatSpecificFlags &= ~QT_LPCM_FORMAT_FLAG_SIGNED_INTEGER;
1490 if( lpcm->format_flags & QT_LPCM_FORMAT_FLAG_PACKED )
1491 audio->formatSpecificFlags &= ~QT_LPCM_FORMAT_FLAG_ALIGNED_HIGH;
1493 else if( audio->version == 1 )
1495 audio->channelcount = summary->channels;
1496 audio->samplesize = 16;
1497 /* Audio formats other than 'raw ' and 'twos' are treated as compressed audio. */
1498 if( lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_RAW_AUDIO )
1499 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_TWOS_AUDIO ) )
1500 audio->compression_ID = QT_AUDIO_COMPRESSION_ID_NOT_COMPRESSED;
1501 else
1502 audio->compression_ID = QT_AUDIO_COMPRESSION_ID_FIXED_COMPRESSION;
1503 audio->samplerate = summary->frequency << 16;
1504 audio->samplesPerPacket = 1;
1505 audio->bytesPerPacket = summary->sample_size / 8;
1506 audio->bytesPerFrame = audio->bytesPerPacket * summary->channels; /* sample_size field in stsz box is NOT used. */
1507 audio->bytesPerSample = 1 + (summary->sample_size != 8);
1508 if( lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_FL32_AUDIO )
1509 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_FL64_AUDIO )
1510 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_IN24_AUDIO )
1511 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_IN32_AUDIO ) )
1513 isom_wave_t *wave = isom_add_wave( audio );
1514 isom_frma_t *frma;
1515 isom_enda_t *enda;
1516 if( !(frma = isom_add_frma( wave ))
1517 || !(enda = isom_add_enda( wave ))
1518 || !isom_add_terminator( wave ) )
1520 lsmash_remove_entry_tail( &audio->extensions, wave->destruct );
1521 return LSMASH_ERR_NAMELESS;
1523 frma->data_format = sample_type.fourcc;
1524 enda->littleEndian = !(lpcm->format_flags & QT_LPCM_FORMAT_FLAG_BIG_ENDIAN);
1527 else /* audio->version == 0 */
1529 audio->channelcount = summary->channels;
1530 audio->samplesize = summary->sample_size;
1531 audio->compression_ID = QT_AUDIO_COMPRESSION_ID_NOT_COMPRESSED;
1532 audio->samplerate = summary->frequency << 16;
1534 return 0;
1537 static int isom_set_isom_dts_description( isom_audio_entry_t *audio, lsmash_audio_summary_t *summary )
1539 audio->version = 0;
1540 audio->revision_level = 0;
1541 audio->vendor = 0;
1542 audio->channelcount = summary->channels;
1543 audio->samplesize = 16;
1544 audio->compression_ID = 0;
1545 audio->packet_size = 0;
1546 switch( summary->frequency )
1548 case 12000 : /* Invalid? (No reference in the spec) */
1549 case 24000 :
1550 case 48000 :
1551 case 96000 :
1552 case 192000 :
1553 case 384000 : /* Invalid? (No reference in the spec) */
1554 audio->samplerate = 48000 << 16;
1555 break;
1556 case 22050 :
1557 case 44100 :
1558 case 88200 :
1559 case 176400 :
1560 case 352800 : /* Invalid? (No reference in the spec) */
1561 audio->samplerate = 44100 << 16;
1562 break;
1563 case 8000 : /* Invalid? (No reference in the spec) */
1564 case 16000 :
1565 case 32000 :
1566 case 64000 :
1567 case 128000 :
1568 audio->samplerate = 32000 << 16;
1569 break;
1570 default :
1571 audio->samplerate = 0;
1572 break;
1574 return 0;
1577 static lsmash_box_type_t isom_guess_audio_codec_specific_box_type( lsmash_codec_type_t active_codec_type, lsmash_compact_box_type_t fourcc )
1579 lsmash_box_type_t box_type = LSMASH_BOX_TYPE_INITIALIZER;
1580 box_type.fourcc = fourcc;
1581 #define GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( codec_type, predefined_box_type ) \
1582 else if( (codec_type.user.fourcc == 0 \
1583 || lsmash_check_codec_type_identical( active_codec_type, codec_type )) \
1584 && box_type.fourcc == predefined_box_type.fourcc ) \
1585 box_type = predefined_box_type
1586 if( 0 );
1587 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_AC_3_AUDIO, ISOM_BOX_TYPE_DAC3 );
1588 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_EC_3_AUDIO, ISOM_BOX_TYPE_DEC3 );
1589 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_DTSC_AUDIO, ISOM_BOX_TYPE_DDTS );
1590 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_DTSE_AUDIO, ISOM_BOX_TYPE_DDTS );
1591 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_DTSH_AUDIO, ISOM_BOX_TYPE_DDTS );
1592 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_DTSL_AUDIO, ISOM_BOX_TYPE_DDTS );
1593 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_ALAC_AUDIO, ISOM_BOX_TYPE_ALAC );
1594 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_MP4A_AUDIO, ISOM_BOX_TYPE_ESDS );
1595 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( QT_CODEC_TYPE_ALAC_AUDIO, QT_BOX_TYPE_ALAC );
1596 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( QT_CODEC_TYPE_MP4A_AUDIO, QT_BOX_TYPE_ESDS );
1597 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( QT_CODEC_TYPE_FULLMP3_AUDIO, QT_CODEC_TYPE_MP3_AUDIO );
1598 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( QT_CODEC_TYPE_ADPCM2_AUDIO, QT_CODEC_TYPE_ADPCM2_AUDIO );
1599 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( QT_CODEC_TYPE_ADPCM17_AUDIO, QT_CODEC_TYPE_ADPCM17_AUDIO );
1600 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( QT_CODEC_TYPE_GSM49_AUDIO, QT_CODEC_TYPE_GSM49_AUDIO );
1601 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, QT_BOX_TYPE_CHAN );
1602 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, QT_BOX_TYPE_GLBL );
1603 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, QT_BOX_TYPE_WAVE );
1604 #undef GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE
1605 return box_type;
1608 typedef struct
1610 uint16_t wFormatTag;
1611 uint16_t nChannels;
1612 uint32_t nSamplesPerSec;
1613 uint32_t nAvgBytesPerSec;
1614 uint16_t nBlockAlign;
1615 uint16_t wBitsPerSample;
1616 uint16_t cbSize;
1617 } wave_format_ex_t;
1619 static lsmash_bs_t *isom_create_waveform_audio_info
1621 wave_format_ex_t *wfx,
1622 lsmash_box_type_t type
1625 lsmash_bs_t *bs = lsmash_bs_create();
1626 if( !bs )
1627 return NULL;
1628 lsmash_bs_put_be32( bs, ISOM_BASEBOX_COMMON_SIZE + 18 + wfx->cbSize );
1629 lsmash_bs_put_be32( bs, type.fourcc );
1630 lsmash_bs_put_le16( bs, wfx->wFormatTag );
1631 lsmash_bs_put_le16( bs, wfx->nChannels );
1632 lsmash_bs_put_le32( bs, wfx->nSamplesPerSec );
1633 lsmash_bs_put_le32( bs, wfx->nAvgBytesPerSec );
1634 lsmash_bs_put_le16( bs, wfx->nBlockAlign );
1635 lsmash_bs_put_le16( bs, wfx->wBitsPerSample );
1636 lsmash_bs_put_le16( bs, wfx->cbSize );
1637 return bs;
1640 static int isom_setup_waveform_audio_info
1642 isom_wave_t *wave,
1643 isom_audio_entry_t *audio,
1644 lsmash_audio_summary_t *summary,
1645 uint32_t samples_per_packet,
1646 uint32_t bytes_per_frame,
1647 uint32_t sample_size
1650 wave_format_ex_t wfx;
1651 wfx.wFormatTag = 0x0000; /* WAVE_FORMAT_UNKNOWN */
1652 wfx.nChannels = summary->channels;
1653 wfx.nSamplesPerSec = summary->frequency;
1654 wfx.nAvgBytesPerSec = 0;
1655 wfx.nBlockAlign = bytes_per_frame;
1656 wfx.wBitsPerSample = sample_size;
1657 wfx.cbSize = 0;
1658 lsmash_bs_t *bs = NULL;
1659 if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ADPCM2_AUDIO ) )
1661 /* ADPCMWAVEFORMAT */
1662 wfx.wFormatTag = 0x0002; /* WAVE_FORMAT_ADPCM */
1663 wfx.cbSize = 32;
1664 bs = isom_create_waveform_audio_info( &wfx, audio->type );
1665 if( !bs )
1666 return LSMASH_ERR_MEMORY_ALLOC;
1667 uint16_t wSamplesPerBlock = samples_per_packet; /* nBlockAlign * 2 / nChannels - 12 */
1668 uint16_t wNumCoef = 7; /* Microsoft ADPCM uses just 7 coefficients. */
1669 static const struct
1671 int16_t iCoef1;
1672 int16_t iCoef2;
1673 } aCoef[7] = { { 256, 0 }, { 512, -256 }, { 0,0 }, { 192,64 }, { 240,0 }, { 460, -208 }, { 392,-232 } };
1674 lsmash_bs_put_le16( bs, wSamplesPerBlock );
1675 lsmash_bs_put_le16( bs, wNumCoef );
1676 for( int i = 0; i < 7; i++ )
1678 lsmash_bs_put_le16( bs, aCoef[i].iCoef1 );
1679 lsmash_bs_put_le16( bs, aCoef[i].iCoef2 );
1682 else if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ADPCM17_AUDIO ) )
1684 /* IMAADPCMWAVEFORMAT */
1685 wfx.wFormatTag = 0x0011; /* WAVE_FORMAT_DVI_ADPCM / WAVE_FORMAT_IMA_ADPCM */
1686 wfx.cbSize = 2;
1687 bs = isom_create_waveform_audio_info( &wfx, audio->type );
1688 if( !bs )
1689 return LSMASH_ERR_MEMORY_ALLOC;
1690 uint16_t wSamplesPerBlock = samples_per_packet;
1691 lsmash_bs_put_le16( bs, wSamplesPerBlock );
1693 else if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_GSM49_AUDIO ) )
1695 /* GSM610WAVEFORMAT */
1696 wfx.wFormatTag = 0x0031; /* WAVE_FORMAT_GSM610 */
1697 wfx.cbSize = 2;
1698 bs = isom_create_waveform_audio_info( &wfx, audio->type );
1699 if( !bs )
1700 return LSMASH_ERR_MEMORY_ALLOC;
1701 uint16_t wSamplesPerBlock = samples_per_packet;
1702 lsmash_bs_put_le16( bs, wSamplesPerBlock );
1704 else if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_FULLMP3_AUDIO )
1705 || lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_MP3_AUDIO ) )
1707 /* MPEGLAYER3WAVEFORMAT */
1708 wfx.wFormatTag = 0x0055; /* WAVE_FORMAT_MPEGLAYER3 */
1709 wfx.nBlockAlign = 1; /* ? */
1710 wfx.wBitsPerSample = 0; /* undefined */
1711 wfx.cbSize = 12;
1712 bs = isom_create_waveform_audio_info( &wfx, audio->type );
1713 if( !bs )
1714 return LSMASH_ERR_MEMORY_ALLOC;
1715 uint16_t wID = 1; /* MPEGLAYER3_ID_MPEG */
1716 uint32_t fdwFlags = 0; /* We don't know whether the stream is padded or not here. */
1717 uint16_t nBlockSize = 0; /* (144 * (bitrate / nSamplesPerSec) + padding) * nFramesPerBlock */
1718 uint16_t nFramesPerBlock = 1; /* the number of audio frames per block */
1719 uint16_t nCodecDelay = 0; /* Encoder delay in samples is unknown. */
1720 lsmash_bs_put_le16( bs, wID );
1721 lsmash_bs_put_le32( bs, fdwFlags );
1722 lsmash_bs_put_le16( bs, nBlockSize );
1723 lsmash_bs_put_le16( bs, nFramesPerBlock );
1724 lsmash_bs_put_le16( bs, nCodecDelay );
1726 if( !bs )
1728 assert( 0 );
1729 return LSMASH_ERR_NAMELESS;
1731 uint32_t wfx_size;
1732 uint8_t *wfx_data = lsmash_bs_export_data( bs, &wfx_size );
1733 lsmash_bs_cleanup( bs );
1734 if( !wfx_data )
1735 return LSMASH_ERR_NAMELESS;
1736 if( wfx_size != ISOM_BASEBOX_COMMON_SIZE + 18 + wfx.cbSize )
1738 lsmash_free( wfx_data );
1739 return LSMASH_ERR_NAMELESS;
1741 int err = isom_add_extension_binary( wave, audio->type, LSMASH_BOX_PRECEDENCE_HM, wfx_data, wfx_size );
1742 if( err < 0 )
1744 lsmash_free( wfx_data );
1745 return err;
1747 return 0;
1750 static int isom_set_qtff_sound_decompression_parameters
1752 isom_audio_entry_t *audio,
1753 lsmash_audio_summary_t *summary,
1754 lsmash_qt_audio_format_specific_flag *format_flags,
1755 uint32_t samples_per_packet,
1756 uint32_t bytes_per_frame,
1757 uint32_t sample_size
1760 /* A 'wave' extension itself shall be absent in the opaque CODEC specific info list.
1761 * So, create a 'wave' extension here and append it as an extension to the audio sample description. */
1762 isom_wave_t *wave = isom_add_wave( audio );
1763 if( !isom_add_frma ( wave )
1764 || !isom_add_terminator( wave ) )
1766 lsmash_remove_entry_tail( &audio->extensions, wave->destruct );
1767 return LSMASH_ERR_NAMELESS;
1769 wave->frma->data_format = audio->type.fourcc;
1770 /* Append extensions from the opaque CODEC specific info list to 'wave' extension. */
1771 int err;
1772 int waveform_audio_info_present = 0;
1773 int requires_waveform_audio_info = isom_is_waveform_audio( audio->type );
1774 for( lsmash_entry_t *entry = summary->opaque->list.head; entry; entry = entry->next )
1776 lsmash_codec_specific_t *specific = (lsmash_codec_specific_t *)entry->data;
1777 if( !specific )
1778 return LSMASH_ERR_NAMELESS;
1779 if( specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN
1780 && specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
1781 continue; /* LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN + LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED is not supported. */
1782 switch( specific->type )
1784 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_COMMON :
1785 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER :
1786 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS :
1787 continue; /* These cannot be an extension for 'wave' extension. */
1788 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT :
1789 /* (Legacy?) ALAC might have an Audio Channel Layout Box inside 'wave' extension. */
1790 #if 1
1791 continue;
1792 #else
1793 if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ALAC_AUDIO ) )
1794 continue;
1795 if( (err = isom_append_channel_layout_extension( specific, wave, summary->channels )) < 0 )
1796 return err;
1797 break;
1798 #endif
1799 default :
1801 assert( specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED
1802 || specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_DECOMPRESSION_PARAMETERS );
1803 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
1804 if( !cs )
1805 return LSMASH_ERR_NAMELESS;
1806 if( cs->size < ISOM_BASEBOX_COMMON_SIZE )
1808 lsmash_destroy_codec_specific_data( cs );
1809 continue;
1811 uint8_t *box_data = cs->data.unstructured;
1812 uint64_t box_size = cs->size;
1813 lsmash_compact_box_type_t fourcc = LSMASH_4CC( box_data[4], box_data[5], box_data[6], box_data[7] );
1814 if( audio->version == 2 && fourcc == QT_BOX_TYPE_ENDA.fourcc )
1816 /* Don't append a 'enda' extension if version == 2.
1817 * Endianness is indicated in QuickTime audio format specific flags. */
1818 if( box_size >= ISOM_BASEBOX_COMMON_SIZE + 2 )
1820 /* Override endianness indicated in format specific flags. */
1821 if( box_data[9] == 1 )
1822 *format_flags &= ~QT_AUDIO_FORMAT_FLAG_BIG_ENDIAN;
1823 else
1824 *format_flags |= QT_AUDIO_FORMAT_FLAG_BIG_ENDIAN;
1826 lsmash_destroy_codec_specific_data( cs );
1827 continue;
1829 lsmash_box_type_t box_type = isom_guess_audio_codec_specific_box_type( audio->type, fourcc );
1830 if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_WAVE ) )
1832 /* It is insane to appened a 'wave' extension to a 'wave' extension. */
1833 lsmash_destroy_codec_specific_data( cs );
1834 continue;
1836 box_type = lsmash_form_qtff_box_type( box_type.fourcc );
1837 /* Determine 'precedence'. */
1838 uint64_t precedence;
1839 if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_FRMA ) )
1840 precedence = LSMASH_BOX_PRECEDENCE_QTFF_FRMA;
1841 else if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_ESDS ) )
1842 precedence = LSMASH_BOX_PRECEDENCE_QTFF_ESDS;
1843 else if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_ENDA ) )
1844 precedence = LSMASH_BOX_PRECEDENCE_QTFF_ENDA;
1845 else if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_MP4A ) )
1846 precedence = LSMASH_BOX_PRECEDENCE_QTFF_MP4A;
1847 else if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_TERMINATOR ) )
1848 precedence = LSMASH_BOX_PRECEDENCE_QTFF_TERMINATOR;
1849 else
1850 precedence = LSMASH_BOX_PRECEDENCE_HM;
1851 /* Append the extension. */
1852 err = isom_add_extension_binary( wave, box_type, precedence, cs->data.unstructured, cs->size );
1853 cs->data.unstructured = NULL; /* Avoid freeing the binary data of the extension. */
1854 lsmash_destroy_codec_specific_data( cs );
1855 if( err < 0 )
1856 return err;
1857 if( isom_is_waveform_audio( box_type ) )
1858 waveform_audio_info_present = 1;
1859 break;
1863 if( requires_waveform_audio_info && !waveform_audio_info_present
1864 && (err = isom_setup_waveform_audio_info( wave, audio, summary, samples_per_packet, bytes_per_frame, sample_size )) < 0 )
1865 return err;
1866 return 0;
1869 static int isom_set_qtff_template_audio_description( isom_audio_entry_t *audio, lsmash_audio_summary_t *summary )
1871 audio->manager |= LSMASH_QTFF_BASE;
1872 audio->type = lsmash_form_qtff_box_type( audio->type.fourcc );
1873 audio->version = (summary->channels > 2 || summary->frequency > UINT16_MAX) ? 2 : 1;
1874 /* Try to get QuickTime audio format specific flags. */
1875 lsmash_qt_audio_format_specific_flag format_flags = QT_AUDIO_FORMAT_FLAG_BIG_ENDIAN;
1876 for( lsmash_entry_t *entry = summary->opaque->list.head; entry; entry = entry->next )
1878 lsmash_codec_specific_t *specific = (lsmash_codec_specific_t *)entry->data;
1879 if( !specific
1880 || !specific->data.structured )
1881 continue;
1882 if( specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS
1883 && specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
1885 /* A format specific flags is found.
1886 * Force audio sample description version == 2. */
1887 format_flags = ((lsmash_qt_audio_format_specific_flags_t *)specific->data.structured)->format_flags;
1888 audio->version = 2;
1889 break;
1892 uint32_t samples_per_packet;
1893 uint32_t bytes_per_frame;
1894 uint32_t sample_size;
1895 if( !((summary->samples_in_frame == 0 || summary->bytes_per_frame == 0 || summary->sample_size == 0)
1896 && isom_get_implicit_qt_fixed_comp_audio_sample_quants( audio, &samples_per_packet, &bytes_per_frame, &sample_size )) )
1898 samples_per_packet = summary->samples_in_frame;
1899 bytes_per_frame = summary->bytes_per_frame;
1900 sample_size = summary->sample_size;
1902 if( !lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_MAC3_AUDIO )
1903 && !lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_MAC6_AUDIO )
1904 && !lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_AGSM_AUDIO )
1905 && !lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ALAW_AUDIO )
1906 && !lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ULAW_AUDIO ) )
1908 int err = isom_set_qtff_sound_decompression_parameters( audio, summary, &format_flags,
1909 samples_per_packet, bytes_per_frame, sample_size );
1910 if( err < 0 )
1911 return err;
1913 /* Set up common audio description fields. */
1914 audio->samplesize = 16;
1915 audio->packet_size = 0;
1916 if( audio->version == 2 )
1918 audio->channelcount = 3;
1919 audio->compression_ID = QT_AUDIO_COMPRESSION_ID_VARIABLE_COMPRESSION;
1920 audio->samplerate = 0x00010000;
1921 audio->sizeOfStructOnly = 72;
1922 audio->audioSampleRate = (union {double d; uint64_t i;}){summary->frequency}.i;
1923 audio->numAudioChannels = summary->channels;
1924 audio->always7F000000 = 0x7F000000;
1925 audio->constBitsPerChannel = 0;
1926 audio->constBytesPerAudioPacket = bytes_per_frame;
1927 audio->constLPCMFramesPerAudioPacket = samples_per_packet;
1928 if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ALAC_AUDIO ) )
1930 switch( sample_size )
1932 case 16 :
1933 audio->formatSpecificFlags = QT_ALAC_FORMAT_FLAG_16BIT_SOURCE_DATA;
1934 break;
1935 case 20 :
1936 audio->formatSpecificFlags = QT_ALAC_FORMAT_FLAG_20BIT_SOURCE_DATA;
1937 break;
1938 case 24 :
1939 audio->formatSpecificFlags = QT_ALAC_FORMAT_FLAG_24BIT_SOURCE_DATA;
1940 break;
1941 case 32 :
1942 audio->formatSpecificFlags = QT_ALAC_FORMAT_FLAG_32BIT_SOURCE_DATA;
1943 break;
1944 default :
1945 break;
1948 else
1950 if( format_flags & QT_AUDIO_FORMAT_FLAG_FLOAT )
1951 format_flags &= ~QT_AUDIO_FORMAT_FLAG_SIGNED_INTEGER;
1952 if( format_flags & QT_AUDIO_FORMAT_FLAG_PACKED )
1953 format_flags &= ~QT_AUDIO_FORMAT_FLAG_ALIGNED_HIGH;
1954 audio->formatSpecificFlags = format_flags;
1957 else /* if( audio->version == 1 ) */
1959 audio->channelcount = LSMASH_MIN( summary->channels, 2 );
1960 audio->compression_ID = QT_AUDIO_COMPRESSION_ID_FIXED_COMPRESSION;
1961 audio->samplerate = summary->frequency << 16;
1962 audio->samplesPerPacket = samples_per_packet;
1963 audio->bytesPerPacket = bytes_per_frame / summary->channels;
1964 audio->bytesPerFrame = bytes_per_frame; /* sample_size field in stsz box is NOT used. */
1965 audio->bytesPerSample = 1 + (sample_size != 8);
1967 return 0;
1970 static void isom_set_samplerate_division_of_media_timescale( isom_audio_entry_t *audio, int strict )
1972 if( audio->parent /* stsd */
1973 && audio->parent->parent /* stbl */
1974 && audio->parent->parent->parent /* minf */
1975 && audio->parent->parent->parent->parent /* mdia */
1976 && lsmash_check_box_type_identical( audio->parent->parent->parent->parent->type, ISOM_BOX_TYPE_MDIA )
1977 && ((isom_mdia_t *)audio->parent->parent->parent->parent)->mdhd )
1979 /* Make an effort to match the timescale with samplerate, or be an integer multiple of it. */
1980 uint32_t orig_timescale = ((isom_mdia_t *)audio->parent->parent->parent->parent)->mdhd->timescale;
1981 uint32_t timescale = orig_timescale;
1982 uint32_t i = 2;
1983 while( timescale > UINT16_MAX && timescale > 1 )
1985 if( timescale % i == 0 )
1986 timescale /= i;
1987 else
1988 i += i > 2 ? 2 : 1;
1990 if( timescale != orig_timescale && strict )
1991 lsmash_log( NULL, LSMASH_LOG_WARNING, "samplerate does not match the media timescale.\n" );
1992 if( timescale <= UINT16_MAX && timescale > 1 )
1994 audio->samplerate = timescale << 16;
1995 return;
1998 audio->samplerate = 0;
2001 static int isom_set_isom_template_audio_description( isom_audio_entry_t *audio, lsmash_audio_summary_t *summary )
2003 audio->version = 0; /* reserved */
2004 audio->revision_level = 0; /* reserved */
2005 audio->vendor = 0; /* reserved */
2006 audio->channelcount = 2; /* template */
2007 audio->samplesize = 16; /* template */
2008 audio->compression_ID = 0; /* pre_defined */
2009 audio->packet_size = 0; /* reserved */
2010 /* template : default output audio sampling rate at playback */
2011 if( summary->frequency <= UINT16_MAX )
2012 audio->samplerate = summary->frequency << 16;
2013 else
2014 isom_set_samplerate_division_of_media_timescale( audio, 0 );
2015 return 0;
2018 static int isom_set_isom_amr_audio_description( isom_audio_entry_t *audio, int wb )
2020 /* For AMR-NB and AMR-WB stream, these fields are not meaningful. */
2021 audio->version = 0; /* always 0 */
2022 audio->revision_level = 0; /* always 0 */
2023 audio->vendor = 0; /* always 0 */
2024 audio->channelcount = 2; /* always 2 although the actual number of channels is always 1 */
2025 audio->samplesize = 16; /* always 16 */
2026 audio->compression_ID = 0; /* always 0 */
2027 audio->packet_size = 0; /* always 0 */
2028 /* Set samplerate by trying to copy from Media Header Box of this media though the
2029 * actual samplerate is 8000 Hz for AMR-NB and 16000 Hz for AMR-WB.
2030 * 3GPP and 3GPP2 has no restriction for media timescale. Therefore, users should
2031 * set suitable media timescale by themselves within the bounds of common sense. */
2032 isom_set_samplerate_division_of_media_timescale( audio, 1 );
2033 if( audio->samplerate == 0 )
2034 /* Set hard-coded but correct samplerate in the CODEC level. */
2035 audio->samplerate = wb ? 8000 : 16000;
2036 return 0;
2039 int isom_setup_audio_description( isom_stsd_t *stsd, lsmash_codec_type_t sample_type, lsmash_audio_summary_t *summary )
2041 if( !stsd || !stsd->file || !summary )
2042 return LSMASH_ERR_NAMELESS;
2043 int err = isom_check_valid_summary( (lsmash_summary_t *)summary );
2044 if( err < 0 )
2045 return err;
2046 isom_audio_entry_t *audio = isom_add_audio_description( stsd, sample_type );
2047 if( !audio )
2048 return LSMASH_ERR_NAMELESS;
2049 audio->data_reference_index = summary->data_ref_index;
2050 lsmash_file_t *file = stsd->file;
2051 lsmash_codec_type_t audio_type = audio->type;
2052 if( lsmash_check_codec_type_identical( audio_type, ISOM_CODEC_TYPE_MP4A_AUDIO )
2053 || lsmash_check_codec_type_identical( audio_type, QT_CODEC_TYPE_MP4A_AUDIO ) )
2055 if( (file->ftyp && file->ftyp->major_brand == ISOM_BRAND_TYPE_QT)
2056 || (!file->ftyp && (file->qt_compatible || (file->moov && !file->moov->iods))) )
2057 err = isom_set_qtff_mp4a_description( audio, summary );
2058 else
2059 err = isom_set_isom_mp4a_description( audio, summary );
2061 else if( isom_is_lpcm_audio( audio ) )
2062 err = isom_set_qtff_lpcm_description( audio, summary );
2063 else if( lsmash_check_codec_type_identical( audio_type, ISOM_CODEC_TYPE_DTSC_AUDIO )
2064 || lsmash_check_codec_type_identical( audio_type, ISOM_CODEC_TYPE_DTSE_AUDIO )
2065 || lsmash_check_codec_type_identical( audio_type, ISOM_CODEC_TYPE_DTSH_AUDIO )
2066 || lsmash_check_codec_type_identical( audio_type, ISOM_CODEC_TYPE_DTSL_AUDIO ) )
2067 err = isom_set_isom_dts_description( audio, summary );
2068 else if( file->qt_compatible )
2069 err = isom_set_qtff_template_audio_description( audio, summary );
2070 else if( lsmash_check_codec_type_identical( audio_type, ISOM_CODEC_TYPE_SAMR_AUDIO ) )
2071 err = isom_set_isom_amr_audio_description( audio, 0 );
2072 else if( lsmash_check_codec_type_identical( audio_type, ISOM_CODEC_TYPE_SAWB_AUDIO ) )
2073 err = isom_set_isom_amr_audio_description( audio, 1 );
2074 else
2075 err = isom_set_isom_template_audio_description( audio, summary );
2076 if( err < 0 )
2077 goto fail;
2078 err = LSMASH_ERR_NAMELESS;
2079 /* Don't use audio_type since audio->type might have changed. */
2080 for( lsmash_entry_t *entry = summary->opaque->list.head; entry; entry = entry->next )
2082 lsmash_codec_specific_t *specific = (lsmash_codec_specific_t *)entry->data;
2083 if( !specific )
2084 goto fail;
2085 if( specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN
2086 && specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
2087 continue; /* LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN + LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED is not supported. */
2088 switch( specific->type )
2090 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_COMMON :
2092 if( specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED )
2093 continue; /* Ignore since not fatal. */
2094 lsmash_qt_audio_common_t *data = (lsmash_qt_audio_common_t *)specific->data.structured;
2095 audio->revision_level = data->revision_level;
2096 audio->vendor = data->vendor;
2097 if( audio->version == 1
2098 && !isom_is_lpcm_audio( audio )
2099 && data->compression_ID != QT_AUDIO_COMPRESSION_ID_NOT_COMPRESSED )
2101 /* Compressed audio must not be set to QT_AUDIO_COMPRESSION_ID_NOT_COMPRESSED. */
2102 audio->compression_ID = data->compression_ID;
2103 if( audio->compression_ID == QT_AUDIO_COMPRESSION_ID_VARIABLE_COMPRESSION )
2105 /* For variable compression, bytesPerPacket and bytesPerFrame are reserved and should be set to 0. */
2106 audio->bytesPerPacket = 0;
2107 audio->bytesPerFrame = 0;
2110 break;
2112 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT :
2114 if( !file->qt_compatible
2115 && !lsmash_check_codec_type_identical( audio->type, ISOM_CODEC_TYPE_ALAC_AUDIO )
2116 && !lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ALAC_AUDIO ) )
2117 continue;
2118 if( (err = isom_append_channel_layout_extension( specific, audio, summary->channels )) < 0 )
2119 goto fail;
2120 break;
2122 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER :
2124 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2125 if( !cs )
2126 goto fail;
2127 lsmash_codec_global_header_t *data = (lsmash_codec_global_header_t *)cs->data.structured;
2128 isom_glbl_t *glbl = isom_add_glbl( audio );
2129 if( !glbl )
2131 lsmash_destroy_codec_specific_data( cs );
2132 goto fail;
2134 glbl->header_size = data->header_size;
2135 glbl->header_data = lsmash_memdup( data->header_data, data->header_size );
2136 lsmash_destroy_codec_specific_data( cs );
2137 if( !glbl->header_data )
2139 isom_remove_box_by_itself( glbl );
2140 err = LSMASH_ERR_MEMORY_ALLOC;
2141 goto fail;
2143 break;
2145 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS :
2146 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_DECOMPRESSION_PARAMETERS :
2147 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG :
2148 break; /* shall be set up already */
2149 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_ALAC :
2150 if( file->qt_compatible )
2151 continue; /* shall be set up already */
2152 default :
2154 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
2155 if( !cs )
2156 goto fail;
2157 if( cs->size < ISOM_BASEBOX_COMMON_SIZE )
2159 lsmash_destroy_codec_specific_data( cs );
2160 continue;
2162 uint8_t *box_data = cs->data.unstructured;
2163 lsmash_compact_box_type_t fourcc = LSMASH_4CC( box_data[4], box_data[5], box_data[6], box_data[7] );
2164 lsmash_box_type_t box_type = isom_guess_audio_codec_specific_box_type( audio->type, fourcc );
2165 if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_WAVE ) )
2167 /* CODEC specific info shall be already inside 'wave' extension. */
2168 lsmash_destroy_codec_specific_data( cs );
2169 continue;
2171 /* Append the extension. */
2172 err = isom_add_extension_binary( audio, box_type, LSMASH_BOX_PRECEDENCE_HM, cs->data.unstructured, cs->size );
2173 cs->data.unstructured = NULL; /* Avoid freeing the binary data of the extension. */
2174 lsmash_destroy_codec_specific_data( cs );
2175 if( err < 0 )
2176 goto fail;
2177 break;
2181 if( audio->version == 0 )
2182 audio->compression_ID = QT_AUDIO_COMPRESSION_ID_NOT_COMPRESSED;
2183 else if( audio->version == 2 )
2184 audio->compression_ID = QT_AUDIO_COMPRESSION_ID_VARIABLE_COMPRESSION;
2185 return 0;
2186 fail:
2187 isom_remove_box_by_itself( audio );
2188 return err;
2191 int isom_setup_tx3g_description( isom_stsd_t *stsd, lsmash_summary_t *summary )
2193 isom_tx3g_entry_t *tx3g = isom_add_tx3g_description( stsd );
2194 if( !tx3g )
2195 return LSMASH_ERR_NAMELESS;
2196 /* We create a dummy font record to make valid font_ID in the sample description.
2197 * The specification (3GPP TS 26.245) does not forbid the value 0 for the identifier,
2198 * but we set 1 to it as track_ID begins from 1. */
2199 tx3g->data_reference_index = summary->data_ref_index;
2200 tx3g->font_ID = 1; /* ID of the default font record */
2201 int err = LSMASH_ERR_MEMORY_ALLOC;
2202 isom_ftab_t *ftab = isom_add_ftab( tx3g );
2203 if( !ftab )
2205 err = LSMASH_ERR_NAMELESS;
2206 goto fail;
2208 isom_font_record_t *font = lsmash_malloc( sizeof(isom_font_record_t) );
2209 if( !font )
2210 goto fail;
2211 if( lsmash_add_entry( ftab->list, font ) < 0 )
2213 lsmash_free( font );
2214 goto fail;
2216 const char font_names[] = "Serif,Sans-serif,Monospace";
2217 font->font_ID = 1;
2218 font->font_name_length = sizeof(font_names);
2219 font->font_name = lsmash_memdup( font_names, sizeof(font_names) );
2220 if( !font->font_name )
2221 goto fail;
2222 return 0;
2223 fail:
2224 isom_remove_box_by_itself( tx3g );
2225 return err;
2228 static lsmash_codec_specific_data_type isom_get_codec_specific_data_type( lsmash_compact_box_type_t extension_fourcc )
2230 static struct codec_specific_data_type_table_tag
2232 lsmash_compact_box_type_t extension_fourcc;
2233 lsmash_codec_specific_data_type data_type;
2234 } codec_specific_data_type_table[32] = { { 0, LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN } };
2235 if( codec_specific_data_type_table[0].data_type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN )
2237 int i = 0;
2238 #define ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( extension_type, data_type ) \
2239 codec_specific_data_type_table[i++] = (struct codec_specific_data_type_table_tag){ extension_type.fourcc, data_type }
2240 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_AVCC, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264 );
2241 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_HVCC, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_HEVC );
2242 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_DVC1, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_VC_1 );
2243 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_DAC3, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_AC_3 );
2244 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_DEC3, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_EC_3 );
2245 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_DDTS, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS );
2246 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_ALAC, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_ALAC );
2247 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_ESDS, LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG );
2248 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_STSL, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_SAMPLE_SCALE );
2249 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_BTRT, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264_BITRATE );
2250 //ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_ALAC, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_ALAC );
2251 //ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_ESDS, LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG );
2252 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_FIEL, LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_FIELD_INFO );
2253 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_CSPC, LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_PIXEL_FORMAT );
2254 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_SGBT, LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_SIGNIFICANT_BITS );
2255 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_GAMA, LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_GAMMA_LEVEL );
2256 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_CHAN, LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT );
2257 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_GLBL, LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER );
2258 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( LSMASH_BOX_TYPE_UNSPECIFIED, LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN );
2259 #undef ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT
2261 lsmash_codec_specific_data_type data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN;
2262 for( int i = 0; codec_specific_data_type_table[i].data_type != LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN; i++ )
2263 if( extension_fourcc == codec_specific_data_type_table[i].extension_fourcc )
2265 data_type = codec_specific_data_type_table[i].data_type;
2266 break;
2268 return data_type;
2271 lsmash_summary_t *isom_create_video_summary_from_description( isom_sample_entry_t *sample_entry )
2273 if( !sample_entry )
2274 return NULL;
2275 isom_visual_entry_t *visual = (isom_visual_entry_t *)sample_entry;
2276 lsmash_video_summary_t *summary = (lsmash_video_summary_t *)lsmash_create_summary( LSMASH_SUMMARY_TYPE_VIDEO );
2277 if( !summary )
2278 return NULL;
2279 summary->sample_type = visual->type;
2280 summary->data_ref_index = visual->data_reference_index;
2281 summary->width = visual->width;
2282 summary->height = visual->height;
2283 summary->depth = visual->depth;
2284 memcpy( summary->compressorname, visual->compressorname, 32 );
2285 summary->compressorname[32] = '\0';
2286 if( isom_is_qt_video( summary->sample_type ) )
2288 lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_COMMON,
2289 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2290 if( !specific )
2291 goto fail;
2292 lsmash_qt_video_common_t *data = (lsmash_qt_video_common_t *)specific->data.structured;
2293 data->revision_level = visual->revision_level;
2294 data->vendor = visual->vendor;
2295 data->temporalQuality = visual->temporalQuality;
2296 data->spatialQuality = visual->spatialQuality;
2297 data->horizontal_resolution = visual->horizresolution;
2298 data->vertical_resolution = visual->vertresolution;
2299 data->dataSize = visual->dataSize;
2300 data->frame_count = visual->frame_count;
2301 data->color_table_ID = visual->color_table_ID;
2302 if( visual->color_table_ID == 0 )
2304 isom_qt_color_table_t *src_ct = &visual->color_table;
2305 if( !src_ct->array )
2307 lsmash_destroy_codec_specific_data( specific );
2308 goto fail;
2310 uint16_t element_count = LSMASH_MIN( src_ct->size + 1, 256 );
2311 lsmash_qt_color_table_t *dst_ct = &data->color_table;
2312 dst_ct->seed = src_ct->seed;
2313 dst_ct->flags = src_ct->flags;
2314 dst_ct->size = src_ct->size;
2315 for( uint16_t i = 0; i < element_count; i++ )
2317 dst_ct->array[i].unused = src_ct->array[i].value;
2318 dst_ct->array[i].r = src_ct->array[i].r;
2319 dst_ct->array[i].g = src_ct->array[i].g;
2320 dst_ct->array[i].b = src_ct->array[i].b;
2323 if( lsmash_add_entry( &summary->opaque->list, specific ) < 0 )
2325 lsmash_destroy_codec_specific_data( specific );
2326 goto fail;
2329 for( lsmash_entry_t *entry = visual->extensions.head; entry; entry = entry->next )
2331 isom_box_t *box = (isom_box_t *)entry->data;
2332 if( !box )
2333 continue;
2334 if( !(box->manager & LSMASH_BINARY_CODED_BOX) )
2336 lsmash_codec_specific_t *specific = NULL;
2337 if( lsmash_check_box_type_identical( box->type, ISOM_BOX_TYPE_CLAP ) )
2339 isom_clap_t *clap = (isom_clap_t *)box;
2340 summary->clap.width.n = clap->cleanApertureWidthN;
2341 summary->clap.width.d = clap->cleanApertureWidthD;
2342 summary->clap.height.n = clap->cleanApertureHeightN;
2343 summary->clap.height.d = clap->cleanApertureHeightD;
2344 summary->clap.horizontal_offset.n = clap->horizOffN;
2345 summary->clap.horizontal_offset.d = clap->horizOffD;
2346 summary->clap.vertical_offset.n = clap->vertOffN;
2347 summary->clap.vertical_offset.d = clap->vertOffD;
2348 continue;
2350 else if( lsmash_check_box_type_identical( box->type, ISOM_BOX_TYPE_PASP ) )
2352 isom_pasp_t *pasp = (isom_pasp_t *)box;
2353 summary->par_h = pasp->hSpacing;
2354 summary->par_v = pasp->vSpacing;
2355 continue;
2357 else if( lsmash_check_box_type_identical( box->type, ISOM_BOX_TYPE_COLR )
2358 || lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_COLR ) )
2360 isom_colr_t *colr = (isom_colr_t *)box;
2361 summary->color.primaries_index = colr->primaries_index;
2362 summary->color.transfer_index = colr->transfer_function_index;
2363 summary->color.matrix_index = colr->matrix_index;
2364 summary->color.full_range = colr->full_range_flag;
2365 continue;
2367 else if( lsmash_check_box_type_identical( box->type, ISOM_BOX_TYPE_STSL ) )
2369 specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_SAMPLE_SCALE,
2370 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2371 if( !specific )
2372 goto fail;
2373 isom_stsl_t *stsl = (isom_stsl_t *)box;
2374 lsmash_isom_sample_scale_t *data = (lsmash_isom_sample_scale_t *)specific->data.structured;
2375 data->constraint_flag = stsl->constraint_flag;
2376 data->scale_method = stsl->scale_method;
2377 data->display_center_x = stsl->display_center_x;
2378 data->display_center_y = stsl->display_center_y;
2380 else if( lsmash_check_box_type_identical( box->type, ISOM_BOX_TYPE_BTRT ) )
2382 specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264_BITRATE,
2383 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2384 if( !specific )
2385 goto fail;
2386 isom_btrt_t *btrt = (isom_btrt_t *)box;
2387 lsmash_h264_bitrate_t *data = (lsmash_h264_bitrate_t *)specific->data.structured;
2388 data->bufferSizeDB = btrt->bufferSizeDB;
2389 data->maxBitrate = btrt->maxBitrate;
2390 data->avgBitrate = btrt->avgBitrate;
2392 else if( lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_FIEL ) )
2394 specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_FIELD_INFO,
2395 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2396 if( !specific )
2397 goto fail;
2398 isom_fiel_t *fiel = (isom_fiel_t *)box;
2399 lsmash_qt_field_info_t *data = (lsmash_qt_field_info_t *)specific->data.structured;
2400 data->fields = fiel->fields;
2401 data->detail = fiel->detail;
2403 else if( lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_CSPC ) )
2405 specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_PIXEL_FORMAT,
2406 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2407 if( !specific )
2408 goto fail;
2409 isom_cspc_t *cspc = (isom_cspc_t *)box;
2410 lsmash_qt_pixel_format_t *data = (lsmash_qt_pixel_format_t *)specific->data.structured;
2411 data->pixel_format = cspc->pixel_format;
2413 else if( lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_SGBT ) )
2415 specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_SIGNIFICANT_BITS,
2416 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2417 if( !specific )
2418 goto fail;
2419 isom_sgbt_t *sgbt = (isom_sgbt_t *)box;
2420 lsmash_qt_significant_bits_t *data = (lsmash_qt_significant_bits_t *)specific->data.structured;
2421 data->significantBits = sgbt->significantBits;
2423 else if( lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_GLBL ) )
2425 specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER,
2426 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2427 if( !specific )
2428 goto fail;
2429 isom_glbl_t *glbl = (isom_glbl_t *)box;
2430 lsmash_codec_global_header_t *data = (lsmash_codec_global_header_t *)specific->data.structured;
2431 data->header_size = glbl->header_size;
2432 data->header_data = lsmash_memdup( glbl->header_data, glbl->header_size );
2433 if( !data->header_data )
2435 lsmash_destroy_codec_specific_data( specific );
2436 goto fail;
2439 else
2440 continue;
2441 if( lsmash_add_entry( &summary->opaque->list, specific ) < 0 )
2443 lsmash_destroy_codec_specific_data( specific );
2444 goto fail;
2447 else
2449 if( box->size < ISOM_BASEBOX_COMMON_SIZE )
2450 continue;
2451 uint8_t *data = box->binary;
2452 lsmash_compact_box_type_t fourcc = LSMASH_4CC( data[4], data[5], data[6], data[7] );
2453 lsmash_codec_specific_data_type type = isom_get_codec_specific_data_type( fourcc );
2454 lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( type, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
2455 if( !specific )
2456 goto fail;
2457 specific->size = box->size;
2458 specific->data.unstructured = lsmash_memdup( box->binary, box->size );
2459 if( !specific->data.unstructured
2460 || lsmash_add_entry( &summary->opaque->list, specific ) < 0 )
2462 lsmash_destroy_codec_specific_data( specific );
2463 goto fail;
2467 return (lsmash_summary_t *)summary;
2468 fail:
2469 lsmash_cleanup_summary( (lsmash_summary_t *)summary );
2470 return NULL;
2473 static int isom_append_structured_mp4sys_decoder_config( lsmash_codec_specific_list_t *opaque, isom_esds_t *esds )
2475 lsmash_bs_t *bs = lsmash_bs_create();
2476 if( !bs )
2477 return LSMASH_ERR_MEMORY_ALLOC;
2478 /* Put box size, type, version and flags fields. */
2479 lsmash_bs_put_be32( bs, 0 );
2480 lsmash_bs_put_be32( bs, ISOM_BOX_TYPE_ESDS.fourcc );
2481 lsmash_bs_put_be32( bs, 0 );
2482 /* Put ES Descriptor. */
2483 mp4sys_update_descriptor_size( esds->ES );
2484 mp4sys_write_descriptor( bs, esds->ES );
2485 /* Export ES Descriptor Box as binary string. */
2486 uint32_t esds_size;
2487 uint8_t *esds_data = lsmash_bs_export_data( bs, &esds_size );
2488 lsmash_bs_cleanup( bs );
2489 if( !esds_data )
2490 return LSMASH_ERR_NAMELESS;
2491 /* Update box size. */
2492 LSMASH_SET_BE32( esds_data, esds_size );
2493 lsmash_codec_specific_data_type type = isom_get_codec_specific_data_type( ISOM_BOX_TYPE_ESDS.fourcc );
2494 lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( type, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
2495 if( !specific )
2497 lsmash_free( esds_data );
2498 return LSMASH_ERR_NAMELESS;
2500 specific->data.unstructured = esds_data;
2501 specific->size = esds_size;
2502 /* Convert unstructured CODEC specific data format into structured, and append it to the opaque list. */
2503 lsmash_codec_specific_t *conv = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2504 lsmash_destroy_codec_specific_data( specific );
2505 if( !conv )
2506 return LSMASH_ERR_NAMELESS;
2507 if( lsmash_add_entry( &opaque->list, conv ) < 0 )
2509 lsmash_destroy_codec_specific_data( conv );
2510 return LSMASH_ERR_MEMORY_ALLOC;
2512 return 0;
2515 lsmash_summary_t *isom_create_audio_summary_from_description( isom_sample_entry_t *sample_entry )
2517 if( !sample_entry || !sample_entry->file || !sample_entry->parent )
2518 return NULL;
2519 isom_audio_entry_t *audio = (isom_audio_entry_t *)sample_entry;
2520 lsmash_audio_summary_t *summary = (lsmash_audio_summary_t *)lsmash_create_summary( LSMASH_SUMMARY_TYPE_AUDIO );
2521 if( !summary )
2522 return NULL;
2523 summary->sample_type = audio->type;
2524 summary->data_ref_index = audio->data_reference_index;
2525 summary->sample_size = audio->samplesize;
2526 summary->channels = audio->channelcount;
2527 summary->frequency = audio->samplerate >> 16;
2528 if( ((isom_stsd_t *)audio->parent)->version == 0
2529 && audio->file->qt_compatible
2530 && isom_is_qt_audio( audio->type ) )
2532 if( audio->version == 0 )
2533 isom_get_implicit_qt_fixed_comp_audio_sample_quants( audio, &summary->samples_in_frame, &summary->bytes_per_frame, &summary->sample_size );
2534 else if( audio->version == 1 )
2536 summary->channels = audio->bytesPerPacket ? audio->bytesPerFrame / audio->bytesPerPacket : audio->channelcount;
2537 summary->sample_size = audio->bytesPerPacket * 8;
2538 summary->samples_in_frame = audio->samplesPerPacket;
2539 summary->bytes_per_frame = audio->bytesPerFrame;
2541 else if( audio->version == 2 )
2543 summary->frequency = (union {uint64_t i; double d;}){audio->audioSampleRate}.d;
2544 summary->channels = audio->numAudioChannels;
2545 summary->sample_size = audio->constBitsPerChannel;
2546 summary->samples_in_frame = audio->constLPCMFramesPerAudioPacket;
2547 summary->bytes_per_frame = audio->constBytesPerAudioPacket;
2549 lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_COMMON,
2550 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2551 if( !specific )
2552 goto fail;
2553 lsmash_qt_audio_common_t *common = (lsmash_qt_audio_common_t *)specific->data.structured;
2554 common->revision_level = audio->revision_level;
2555 common->vendor = audio->vendor;
2556 common->compression_ID = audio->compression_ID;
2557 if( lsmash_add_entry( &summary->opaque->list, specific ) < 0 )
2559 lsmash_destroy_codec_specific_data( specific );
2560 goto fail;
2562 if( isom_is_lpcm_audio( audio ) )
2564 specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS,
2565 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2566 if( !specific )
2567 goto fail;
2568 lsmash_qt_audio_format_specific_flags_t *data = (lsmash_qt_audio_format_specific_flags_t *)specific->data.structured;
2569 if( audio->version == 2 )
2570 data->format_flags = audio->formatSpecificFlags;
2571 else
2573 data->format_flags = 0;
2574 /* Here, don't override samplesize.
2575 * We should trust samplesize field in the description for misused CODEC indentifier. */
2576 lsmash_codec_type_t audio_type = audio->type;
2577 if( lsmash_check_codec_type_identical( audio_type, QT_CODEC_TYPE_FL32_AUDIO )
2578 || lsmash_check_codec_type_identical( audio_type, QT_CODEC_TYPE_FL64_AUDIO ) )
2579 data->format_flags = QT_LPCM_FORMAT_FLAG_FLOAT;
2580 else if( lsmash_check_codec_type_identical( audio_type, QT_CODEC_TYPE_TWOS_AUDIO )
2581 || lsmash_check_codec_type_identical( audio_type, QT_CODEC_TYPE_NONE_AUDIO )
2582 || lsmash_check_codec_type_identical( audio_type, QT_CODEC_TYPE_NOT_SPECIFIED ) )
2584 if( lsmash_check_codec_type_identical( audio_type, QT_CODEC_TYPE_TWOS_AUDIO ) )
2585 data->format_flags = QT_LPCM_FORMAT_FLAG_BIG_ENDIAN | QT_AUDIO_FORMAT_FLAG_SIGNED_INTEGER;
2586 if( summary->sample_size > 8 )
2587 data->format_flags = QT_LPCM_FORMAT_FLAG_BIG_ENDIAN;
2590 isom_wave_t *wave = (isom_wave_t *)isom_get_extension_box_format( &audio->extensions, QT_BOX_TYPE_WAVE );
2591 if( wave && wave->enda && !wave->enda->littleEndian )
2592 data->format_flags |= QT_LPCM_FORMAT_FLAG_BIG_ENDIAN;
2593 if( lsmash_add_entry( &summary->opaque->list, specific ) < 0 )
2595 lsmash_destroy_codec_specific_data( specific );
2596 goto fail;
2599 else if( audio->version == 2
2600 && (lsmash_check_codec_type_identical( audio->type, ISOM_CODEC_TYPE_ALAC_AUDIO )
2601 || lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ALAC_AUDIO )) )
2602 switch( audio->formatSpecificFlags )
2604 case QT_ALAC_FORMAT_FLAG_16BIT_SOURCE_DATA :
2605 summary->sample_size = 16;
2606 break;
2607 case QT_ALAC_FORMAT_FLAG_20BIT_SOURCE_DATA :
2608 summary->sample_size = 20;
2609 break;
2610 case QT_ALAC_FORMAT_FLAG_24BIT_SOURCE_DATA :
2611 summary->sample_size = 24;
2612 break;
2613 case QT_ALAC_FORMAT_FLAG_32BIT_SOURCE_DATA :
2614 summary->sample_size = 32;
2615 break;
2616 default :
2617 break;
2620 else if( lsmash_check_codec_type_identical( audio->type, ISOM_CODEC_TYPE_SAMR_AUDIO ) )
2622 summary->channels = 1;
2623 summary->frequency = 8000;
2625 else if( lsmash_check_codec_type_identical( audio->type, ISOM_CODEC_TYPE_SAWB_AUDIO ) )
2627 summary->channels = 1;
2628 summary->frequency = 16000;
2630 uint32_t actual_sampling_rate = 0;
2631 for( lsmash_entry_t *entry = audio->extensions.head; entry; entry = entry->next )
2633 isom_box_t *box = (isom_box_t *)entry->data;
2634 if( !box )
2635 continue;
2636 if( !(box->manager & LSMASH_BINARY_CODED_BOX) )
2638 if( lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_CHAN ) )
2640 lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT,
2641 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2642 if( !specific )
2643 goto fail;
2644 isom_chan_t *chan = (isom_chan_t *)box;
2645 lsmash_qt_audio_channel_layout_t *data = (lsmash_qt_audio_channel_layout_t *)specific->data.structured;
2646 data->channelLayoutTag = chan->channelLayoutTag;
2647 data->channelBitmap = chan->channelBitmap;
2648 if( lsmash_add_entry( &summary->opaque->list, specific ) < 0 )
2650 lsmash_destroy_codec_specific_data( specific );
2651 goto fail;
2654 else if( lsmash_check_box_type_identical( box->type, ISOM_BOX_TYPE_ESDS )
2655 || lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_ESDS ) )
2657 isom_esds_t *esds = (isom_esds_t *)box;
2658 if( mp4sys_setup_summary_from_DecoderSpecificInfo( summary, esds->ES ) < 0
2659 || isom_append_structured_mp4sys_decoder_config( summary->opaque, esds ) < 0 )
2660 goto fail;
2662 else if( lsmash_check_box_type_identical( box->type, ISOM_BOX_TYPE_SRAT ) )
2664 isom_srat_t *srat = (isom_srat_t *)box;
2665 actual_sampling_rate = srat->sampling_rate;
2667 else if( lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_WAVE ) )
2669 /* Don't append 'wave' extension itself to the opaque CODEC specific info list. */
2670 isom_wave_t *wave = (isom_wave_t *)box;
2671 lsmash_bs_t *bs = lsmash_bs_create();
2672 if( !bs )
2673 goto fail;
2674 for( lsmash_entry_t *wave_entry = wave->extensions.head; wave_entry; wave_entry = wave_entry->next )
2676 isom_box_t *wave_ext = (isom_box_t *)wave_entry->data;
2677 if( !wave_ext )
2678 continue;
2679 lsmash_box_type_t box_type = LSMASH_BOX_TYPE_INITIALIZER;
2680 if( !(wave_ext->manager & LSMASH_BINARY_CODED_BOX) )
2682 box_type = wave_ext->type;
2683 if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_ENDA ) )
2685 isom_enda_t *enda = (isom_enda_t *)wave_ext;
2686 isom_bs_put_box_common( bs, enda );
2687 lsmash_bs_put_be16( bs, enda->littleEndian );
2689 else if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_MP4A ) )
2691 isom_mp4a_t *mp4a = (isom_mp4a_t *)wave_ext;
2692 isom_bs_put_box_common( bs, mp4a );
2693 lsmash_bs_put_be32( bs, mp4a->unknown );
2695 else if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_CHAN ) )
2697 isom_chan_t *chan = (isom_chan_t *)wave_ext;
2698 isom_bs_put_box_common( bs, chan );
2699 lsmash_bs_put_be32( bs, chan->channelLayoutTag );
2700 lsmash_bs_put_be32( bs, chan->channelBitmap );
2701 lsmash_bs_put_be32( bs, chan->numberChannelDescriptions );
2702 if( chan->channelDescriptions )
2703 for( uint32_t i = 0; i < chan->numberChannelDescriptions; i++ )
2705 isom_channel_description_t *channelDescriptions = (isom_channel_description_t *)(&chan->channelDescriptions[i]);
2706 lsmash_bs_put_be32( bs, channelDescriptions->channelLabel );
2707 lsmash_bs_put_be32( bs, channelDescriptions->channelFlags );
2708 lsmash_bs_put_be32( bs, channelDescriptions->coordinates[0] );
2709 lsmash_bs_put_be32( bs, channelDescriptions->coordinates[1] );
2710 lsmash_bs_put_be32( bs, channelDescriptions->coordinates[2] );
2713 else if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_ESDS ) )
2715 isom_esds_t *esds = (isom_esds_t *)wave_ext;
2716 if( !esds
2717 || mp4sys_setup_summary_from_DecoderSpecificInfo( summary, esds->ES ) < 0
2718 || isom_append_structured_mp4sys_decoder_config( summary->opaque, esds ) < 0 )
2720 lsmash_bs_cleanup( bs );
2721 goto fail;
2723 continue;
2725 else
2726 /* Skip Format Box and Terminator Box since they are mandatory and fixed structure. */
2727 continue;
2729 else
2731 if( wave_ext->size < ISOM_BASEBOX_COMMON_SIZE )
2732 continue;
2733 uint8_t *data = wave_ext->binary;
2734 box_type.fourcc = LSMASH_4CC( data[4], data[5], data[6], data[7] );
2735 lsmash_bs_put_bytes( bs, wave_ext->size, wave_ext->binary );
2737 /* Export as binary string. */
2738 uint32_t box_size;
2739 uint8_t *box_data = lsmash_bs_export_data( bs, &box_size );
2740 lsmash_bs_empty( bs );
2741 if( !box_data )
2743 lsmash_bs_cleanup( bs );
2744 goto fail;
2746 /* Append as an unstructured CODEC specific info. */
2747 lsmash_codec_specific_data_type type;
2748 if( box_type.fourcc == QT_BOX_TYPE_CHAN.fourcc )
2749 /* Complete audio channel layout is stored as binary string.
2750 * We distinguish it from one of the outside of 'wave' extension here. */
2751 type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_DECOMPRESSION_PARAMETERS;
2752 else
2754 type = isom_get_codec_specific_data_type( box_type.fourcc );
2755 if( type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN )
2756 type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_DECOMPRESSION_PARAMETERS;
2758 lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( type, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
2759 if( !specific )
2761 lsmash_free( box_data );
2762 lsmash_bs_cleanup( bs );
2763 goto fail;
2765 specific->data.unstructured = box_data;
2766 specific->size = box_size;
2767 if( lsmash_add_entry( &summary->opaque->list, specific ) < 0 )
2769 lsmash_destroy_codec_specific_data( specific );
2770 lsmash_bs_cleanup( bs );
2771 goto fail;
2774 lsmash_bs_cleanup( bs );
2777 else
2779 if( box->size < ISOM_BASEBOX_COMMON_SIZE )
2780 continue;
2781 uint8_t *data = box->binary;
2782 lsmash_compact_box_type_t fourcc = LSMASH_4CC( data[4], data[5], data[6], data[7] );
2783 lsmash_codec_specific_data_type type = isom_get_codec_specific_data_type( fourcc );
2784 lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( type, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
2785 if( !specific )
2786 goto fail;
2787 specific->size = box->size;
2788 specific->data.unstructured = lsmash_memdup( box->binary, box->size );
2789 if( !specific->data.unstructured
2790 || lsmash_add_entry( &summary->opaque->list, specific ) < 0 )
2792 lsmash_destroy_codec_specific_data( specific );
2793 goto fail;
2795 if( specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS
2796 || specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_AC_3
2797 || specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_EC_3 )
2799 specific = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2800 if( !specific )
2801 goto fail;
2802 switch( specific->type )
2804 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS :
2806 lsmash_dts_specific_parameters_t *param = (lsmash_dts_specific_parameters_t *)specific->data.structured;
2807 summary->sample_size = param->pcmSampleDepth;
2808 summary->samples_in_frame = (summary->frequency * (512 << param->FrameDuration)) / param->DTSSamplingFrequency;
2809 break;
2811 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_AC_3 :
2813 lsmash_ac3_specific_parameters_t *param = (lsmash_ac3_specific_parameters_t *)specific->data.structured;
2814 summary->frequency = ac3_get_sample_rate( param );
2815 summary->channels = ac3_get_channel_count( param );
2816 summary->samples_in_frame = 1536;
2817 break;
2819 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_EC_3 :
2821 lsmash_eac3_specific_parameters_t *param = (lsmash_eac3_specific_parameters_t *)specific->data.structured;
2822 eac3_update_sample_rate( &summary->frequency, param, NULL );
2823 eac3_update_channel_count( &summary->channels, param );
2824 summary->samples_in_frame = 1536;
2825 break;
2827 default :
2828 break;
2830 lsmash_destroy_codec_specific_data( specific );
2834 /* Set the actual sampling rate. */
2835 if( actual_sampling_rate )
2836 summary->frequency = actual_sampling_rate;
2837 return (lsmash_summary_t *)summary;
2838 fail:
2839 lsmash_cleanup_summary( (lsmash_summary_t *)summary );
2840 return NULL;
2843 lsmash_codec_specific_t *lsmash_get_codec_specific_data( lsmash_summary_t *summary, uint32_t extension_number )
2845 if( !summary || !summary->opaque )
2846 return NULL;
2847 uint32_t i = 0;
2848 for( lsmash_entry_t *entry = summary->opaque->list.head; entry; entry = entry->next )
2849 if( ++i == extension_number )
2850 return (lsmash_codec_specific_t *)entry->data;
2851 return NULL;
2854 uint32_t lsmash_count_codec_specific_data( lsmash_summary_t *summary )
2856 if( !summary || !summary->opaque )
2857 return 0;
2858 return summary->opaque->list.entry_count;
2861 int isom_compare_opaque_extensions( lsmash_summary_t *a, lsmash_summary_t *b )
2863 assert( a && b );
2864 uint32_t in_number_of_extensions = lsmash_count_codec_specific_data( a );
2865 uint32_t out_number_of_extensions = lsmash_count_codec_specific_data( b );
2866 if( out_number_of_extensions != in_number_of_extensions )
2867 return 1;
2868 uint32_t active_number_of_extensions = in_number_of_extensions;
2869 uint32_t identical_count = 0;
2870 for( uint32_t j = 1; j <= in_number_of_extensions; j++ )
2872 lsmash_codec_specific_t *in_cs_orig = lsmash_get_codec_specific_data( a, j );
2873 lsmash_codec_specific_t *in_cs;
2874 lsmash_codec_specific_format compare_format = LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED;
2875 if( in_cs_orig->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
2877 if( in_cs_orig->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_COMMON
2878 || in_cs_orig->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_COMMON
2879 || in_cs_orig->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS )
2881 compare_format = LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED;
2882 in_cs = in_cs_orig;
2884 else
2886 in_cs = lsmash_convert_codec_specific_format( in_cs_orig, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
2887 if( !in_cs )
2889 /* We don't support the format converter of this data type. */
2890 --active_number_of_extensions;
2891 continue;
2895 else
2896 in_cs = in_cs_orig;
2897 for( uint32_t k = 1; k <= out_number_of_extensions; k++ )
2899 lsmash_codec_specific_t *out_cs_orig = lsmash_get_codec_specific_data( b, k );
2900 if( out_cs_orig->type != in_cs_orig->type )
2901 continue;
2902 lsmash_codec_specific_t *out_cs;
2903 if( out_cs_orig->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
2905 if( compare_format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
2906 out_cs = out_cs_orig;
2907 else
2909 out_cs = lsmash_convert_codec_specific_format( out_cs_orig, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
2910 if( !out_cs )
2911 continue;
2914 else
2915 out_cs = out_cs_orig;
2916 int identical;
2917 if( compare_format == LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED )
2918 identical = out_cs->size == in_cs->size && !memcmp( out_cs->data.unstructured, in_cs->data.unstructured, in_cs->size );
2919 else
2921 if( in_cs->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_COMMON )
2923 lsmash_qt_video_common_t *in_data = (lsmash_qt_video_common_t *)in_cs->data.structured;
2924 lsmash_qt_video_common_t *out_data = (lsmash_qt_video_common_t *)out_cs->data.structured;
2925 identical = in_data->revision_level == out_data->revision_level
2926 && in_data->vendor == out_data->vendor
2927 && in_data->temporalQuality == out_data->temporalQuality
2928 && in_data->spatialQuality == out_data->spatialQuality
2929 && in_data->horizontal_resolution == out_data->horizontal_resolution
2930 && in_data->vertical_resolution == out_data->vertical_resolution
2931 && in_data->dataSize == out_data->dataSize
2932 && in_data->frame_count == out_data->frame_count
2933 && in_data->color_table_ID == out_data->color_table_ID;
2935 else if( in_cs->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_COMMON )
2937 lsmash_qt_audio_common_t *in_data = (lsmash_qt_audio_common_t *)in_cs->data.structured;
2938 lsmash_qt_audio_common_t *out_data = (lsmash_qt_audio_common_t *)out_cs->data.structured;
2939 identical = in_data->revision_level == out_data->revision_level
2940 && in_data->vendor == out_data->vendor
2941 && in_data->compression_ID == out_data->compression_ID;
2943 else
2945 lsmash_qt_audio_format_specific_flags_t *in_data = (lsmash_qt_audio_format_specific_flags_t *)in_cs->data.structured;
2946 lsmash_qt_audio_format_specific_flags_t *out_data = (lsmash_qt_audio_format_specific_flags_t *)out_cs->data.structured;
2947 identical = (in_data->format_flags == out_data->format_flags);
2950 if( out_cs != out_cs_orig )
2951 lsmash_destroy_codec_specific_data( out_cs );
2952 if( identical )
2954 ++identical_count;
2955 break;
2958 if( in_cs != in_cs_orig )
2959 lsmash_destroy_codec_specific_data( in_cs );
2961 return (identical_count != active_number_of_extensions);
2964 int isom_get_implicit_qt_fixed_comp_audio_sample_quants
2966 isom_audio_entry_t *audio,
2967 uint32_t *samples_per_packet,
2968 uint32_t *constant_bytes_per_frame,
2969 uint32_t *sample_size
2972 if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_MAC3_AUDIO ) )
2974 *samples_per_packet = 6;
2975 *constant_bytes_per_frame = 2 * audio->channelcount;
2976 *sample_size = 8;
2978 else if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_MAC6_AUDIO ) )
2980 *samples_per_packet = 6;
2981 *constant_bytes_per_frame = audio->channelcount;
2982 *sample_size = 8;
2984 else if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ADPCM17_AUDIO ) )
2986 *samples_per_packet = 64;
2987 *constant_bytes_per_frame = 34 * audio->channelcount;
2988 *sample_size = 16;
2990 else if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_AGSM_AUDIO ) )
2992 *samples_per_packet = 160;
2993 *constant_bytes_per_frame = 33;
2994 *sample_size = 16;
2996 else if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ALAW_AUDIO )
2997 || lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ULAW_AUDIO ) )
2999 *samples_per_packet = 1;
3000 *constant_bytes_per_frame = audio->channelcount;
3001 *sample_size = 16;
3003 else
3004 return 0;
3005 return 1;