write: Fix type size for mdcv luminance
[L-SMASH.git] / codecs / description.c
blobfac2e3b6e2407fc34559548e30c07bbb54493ad5
1 /*****************************************************************************
2 * description.c
3 *****************************************************************************
4 * Copyright (C) 2012-2017 L-SMASH project
6 * Authors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 *****************************************************************************/
21 /* This file is available under an ISC license. */
23 #include "common/internal.h" /* must be placed first */
25 #include <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_AP4X_VIDEO )
55 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_CFHD_VIDEO )
56 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_CIVD_VIDEO )
57 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVC_VIDEO )
58 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVCP_VIDEO )
59 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVPP_VIDEO )
60 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DV5N_VIDEO )
61 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DV5P_VIDEO )
62 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVH2_VIDEO )
63 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVH3_VIDEO )
64 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVH5_VIDEO )
65 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVH6_VIDEO )
66 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVHP_VIDEO )
67 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVHQ_VIDEO )
68 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DV10_VIDEO )
69 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVOO_VIDEO )
70 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVOR_VIDEO )
71 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVTV_VIDEO )
72 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_DVVT_VIDEO )
73 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_FLIC_VIDEO )
74 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_GIF_VIDEO )
75 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_H261_VIDEO )
76 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_H263_VIDEO )
77 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_HD10_VIDEO )
78 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_JPEG_VIDEO )
79 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_M105_VIDEO )
80 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_MJPA_VIDEO )
81 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_MJPB_VIDEO )
82 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_PNG_VIDEO )
83 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_PNTG_VIDEO )
84 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_RAW_VIDEO )
85 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_RLE_VIDEO )
86 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_RPZA_VIDEO )
87 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_SHR0_VIDEO )
88 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_SHR1_VIDEO )
89 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_SHR2_VIDEO )
90 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_SHR3_VIDEO )
91 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_SHR4_VIDEO )
92 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_SVQ1_VIDEO )
93 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_SVQ3_VIDEO )
94 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_TGA_VIDEO )
95 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_TIFF_VIDEO )
96 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ULRA_VIDEO )
97 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ULRG_VIDEO )
98 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ULY2_VIDEO )
99 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ULY0_VIDEO )
100 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ULH2_VIDEO )
101 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_ULH0_VIDEO )
102 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_UQY2_VIDEO )
103 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V210_VIDEO )
104 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V216_VIDEO )
105 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V308_VIDEO )
106 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V408_VIDEO )
107 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_V410_VIDEO )
108 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_YUV2_VIDEO )
109 || lsmash_check_codec_type_identical( type, QT_CODEC_TYPE_WRLE_VIDEO );
112 static int isom_is_nalff( lsmash_codec_type_t type )
114 return lsmash_check_codec_type_identical( type, ISOM_CODEC_TYPE_AVC1_VIDEO )
115 || lsmash_check_codec_type_identical( type, ISOM_CODEC_TYPE_AVC2_VIDEO )
116 || lsmash_check_codec_type_identical( type, ISOM_CODEC_TYPE_AVC3_VIDEO )
117 || lsmash_check_codec_type_identical( type, ISOM_CODEC_TYPE_AVC4_VIDEO )
118 || lsmash_check_codec_type_identical( type, ISOM_CODEC_TYPE_AVCP_VIDEO )
119 || lsmash_check_codec_type_identical( type, ISOM_CODEC_TYPE_HVC1_VIDEO )
120 || lsmash_check_codec_type_identical( type, ISOM_CODEC_TYPE_HEV1_VIDEO );
123 static int isom_is_dts_audio( lsmash_codec_type_t type )
125 return lsmash_check_codec_type_identical( type, ISOM_CODEC_TYPE_DTSC_AUDIO )
126 || lsmash_check_codec_type_identical( type, ISOM_CODEC_TYPE_DTSE_AUDIO )
127 || lsmash_check_codec_type_identical( type, ISOM_CODEC_TYPE_DTSH_AUDIO )
128 || lsmash_check_codec_type_identical( type, ISOM_CODEC_TYPE_DTSL_AUDIO )
129 || lsmash_check_codec_type_identical( type, ISOM_CODEC_TYPE_DTSX_AUDIO )
130 || lsmash_check_codec_type_identical( type, ISOM_CODEC_TYPE_DTSEL_AUDIO )
131 || lsmash_check_codec_type_identical( type, ISOM_CODEC_TYPE_DTSDL_AUDIO );
134 int lsmash_convert_crop_into_clap( lsmash_crop_t crop, uint32_t width, uint32_t height, lsmash_clap_t *clap )
136 if( !clap || crop.top.d == 0 || crop.bottom.d == 0 || crop.left.d == 0 || crop.right.d == 0 )
137 return LSMASH_ERR_FUNCTION_PARAM;
138 uint64_t vertical_crop_lcm = lsmash_get_lcm( crop.top.d, crop.bottom.d );
139 uint64_t horizontal_crop_lcm = lsmash_get_lcm( crop.left.d, crop.right.d );
140 lsmash_rational_u64_t clap_height;
141 lsmash_rational_u64_t clap_width;
142 lsmash_rational_s64_t clap_horizontal_offset;
143 lsmash_rational_s64_t clap_vertical_offset;
144 clap_height.d = vertical_crop_lcm;
145 clap_width.d = horizontal_crop_lcm;
146 clap_horizontal_offset.d = 2 * vertical_crop_lcm;
147 clap_vertical_offset.d = 2 * horizontal_crop_lcm;
148 clap_height.n = height * vertical_crop_lcm
149 - (crop.top.n * (vertical_crop_lcm / crop.top.d) + crop.bottom.n * (vertical_crop_lcm / crop.bottom.d));
150 clap_width.n = width * horizontal_crop_lcm
151 - (crop.left.n * (horizontal_crop_lcm / crop.left.d) + crop.right.n * (horizontal_crop_lcm / crop.right.d));
152 clap_horizontal_offset.n = (int64_t)(crop.left.n * (horizontal_crop_lcm / crop.left.d))
153 - crop.right.n * (horizontal_crop_lcm / crop.right.d);
154 clap_vertical_offset.n = (int64_t)(crop.top.n * (vertical_crop_lcm / crop.top.d))
155 - crop.bottom.n * (vertical_crop_lcm / crop.bottom.d);
156 lsmash_reduce_fraction( &clap_height.n, &clap_height.d );
157 lsmash_reduce_fraction( &clap_width.n, &clap_width.d );
158 lsmash_reduce_fraction_su( &clap_vertical_offset.n, &clap_vertical_offset.d );
159 lsmash_reduce_fraction_su( &clap_horizontal_offset.n, &clap_horizontal_offset.d );
160 clap->height = (lsmash_rational_u32_t){ clap_height.n, clap_height.d };
161 clap->width = (lsmash_rational_u32_t){ clap_width.n, clap_width.d };
162 clap->vertical_offset = (lsmash_rational_s32_t){ clap_vertical_offset.n, clap_vertical_offset.d };
163 clap->horizontal_offset = (lsmash_rational_s32_t){ clap_horizontal_offset.n, clap_horizontal_offset.d };
164 return 0;
167 int lsmash_convert_clap_into_crop( lsmash_clap_t clap, uint32_t width, uint32_t height, lsmash_crop_t *crop )
169 if( !crop || clap.height.d == 0 || clap.vertical_offset.d == 0 || clap.width.d == 0 || clap.horizontal_offset.d == 0 )
170 return LSMASH_ERR_FUNCTION_PARAM;
171 uint64_t clap_vertical_lcm = lsmash_get_lcm( clap.height.d, clap.vertical_offset.d );
172 uint64_t clap_horizontal_lcm = lsmash_get_lcm( clap.width.d, clap.horizontal_offset.d );
173 lsmash_rational_u64_t crop_top;
174 lsmash_rational_u64_t crop_bottom;
175 lsmash_rational_u64_t crop_left;
176 lsmash_rational_u64_t crop_right;
177 crop_top.d = 2 * clap_vertical_lcm;
178 crop_bottom.d = 2 * clap_vertical_lcm;
179 crop_left.d = 2 * clap_horizontal_lcm;
180 crop_right.d = 2 * clap_horizontal_lcm;
181 crop_top.n = (height * crop_top.d - clap.height.n * (crop_top.d / clap.height.d)) / 2
182 + clap.vertical_offset.n * (crop_top.d / clap.vertical_offset.d);
183 crop_bottom.n = (height * crop_bottom.d - clap.height.n * (crop_bottom.d / clap.height.d)) / 2
184 - clap.vertical_offset.n * (crop_bottom.d / clap.vertical_offset.d);
185 crop_left.n = (width * crop_left.d - clap.width.n * (crop_left.d / clap.width.d)) / 2
186 + clap.horizontal_offset.n * (crop_left.d / clap.horizontal_offset.d);
187 crop_right.n = (width * crop_right.d - clap.width.n * (crop_right.d / clap.width.d)) / 2
188 - clap.horizontal_offset.n * (crop_right.d / clap.horizontal_offset.d);
189 lsmash_reduce_fraction( &crop_top.n, &crop_top.d );
190 lsmash_reduce_fraction( &crop_bottom.n, &crop_bottom.d );
191 lsmash_reduce_fraction( &crop_left.n, &crop_left.d );
192 lsmash_reduce_fraction( &crop_right.n, &crop_right.d );
193 crop->top = (lsmash_rational_u32_t){ crop_top.n, crop_top.d };
194 crop->bottom = (lsmash_rational_u32_t){ crop_bottom.n, crop_bottom.d };
195 crop->left = (lsmash_rational_u32_t){ crop_left.n, crop_left.d };
196 crop->right = (lsmash_rational_u32_t){ crop_right.n, crop_right.d };
197 return 0;
200 static void isom_destruct_nothing( void *data )
202 /* Do nothing. */;
205 static int isom_initialize_structured_codec_specific_data( lsmash_codec_specific_t *specific )
207 extern void mp4sys_destruct_decoder_config( void * );
208 extern void h264_destruct_specific_data( void * );
209 extern void hevc_destruct_specific_data( void * );
210 extern void vc1_destruct_specific_data( void * );
211 extern void dts_destruct_specific_data( void * );
212 switch( specific->type )
214 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG :
215 specific->size = sizeof(lsmash_mp4sys_decoder_parameters_t);
216 specific->destruct = mp4sys_destruct_decoder_config;
217 break;
218 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264 :
219 specific->size = sizeof(lsmash_h264_specific_parameters_t);
220 specific->destruct = h264_destruct_specific_data;
221 break;
222 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_HEVC :
223 specific->size = sizeof(lsmash_hevc_specific_parameters_t);
224 specific->destruct = hevc_destruct_specific_data;
225 break;
226 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_VC_1 :
227 specific->size = sizeof(lsmash_vc1_specific_parameters_t);
228 specific->destruct = vc1_destruct_specific_data;
229 break;
230 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_AC_3 :
231 specific->size = sizeof(lsmash_ac3_specific_parameters_t);
232 specific->destruct = lsmash_free;
233 break;
234 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_EC_3 :
235 specific->size = sizeof(lsmash_eac3_specific_parameters_t);
236 specific->destruct = lsmash_free;
237 break;
238 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS :
239 specific->size = sizeof(lsmash_dts_specific_parameters_t);
240 specific->destruct = dts_destruct_specific_data;
241 break;
242 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_ALAC :
243 specific->size = sizeof(lsmash_alac_specific_parameters_t);
244 specific->destruct = lsmash_free;
245 break;
246 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_SAMPLE_SCALE :
247 specific->size = sizeof(lsmash_isom_sample_scale_t);
248 specific->destruct = lsmash_free;
249 break;
250 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264_BITRATE :
251 specific->size = sizeof(lsmash_h264_bitrate_t);
252 specific->destruct = lsmash_free;
253 break;
254 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_COMMON :
255 specific->size = sizeof(lsmash_qt_video_common_t);
256 specific->destruct = lsmash_free;
257 break;
258 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_COMMON :
259 specific->size = sizeof(lsmash_qt_audio_common_t);
260 specific->destruct = lsmash_free;
261 break;
262 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS :
263 specific->size = sizeof(lsmash_qt_audio_format_specific_flags_t);
264 specific->destruct = lsmash_free;
265 break;
266 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER :
267 specific->size = sizeof(lsmash_codec_global_header_t);
268 specific->destruct = global_destruct_specific_data;
269 break;
270 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_FIELD_INFO :
271 specific->size = sizeof(lsmash_qt_field_info_t);
272 specific->destruct = lsmash_free;
273 break;
274 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_PIXEL_FORMAT :
275 specific->size = sizeof(lsmash_qt_pixel_format_t);
276 specific->destruct = lsmash_free;
277 break;
278 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_SIGNIFICANT_BITS :
279 specific->size = sizeof(lsmash_qt_significant_bits_t);
280 specific->destruct = lsmash_free;
281 break;
282 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT :
283 specific->size = sizeof(lsmash_qt_audio_channel_layout_t);
284 specific->destruct = lsmash_free;
285 break;
286 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_RTP_HINT_COMMON:
287 specific->size = sizeof(lsmash_isom_rtp_reception_hint_t);
288 specific->destruct = lsmash_free;
289 break;
290 default :
291 specific->size = 0;
292 specific->destruct = isom_destruct_nothing;
293 return 0;
295 specific->data.structured = lsmash_malloc_zero( specific->size );
296 if( !specific->data.structured )
298 specific->size = 0;
299 specific->destruct = NULL;
300 return LSMASH_ERR_MEMORY_ALLOC;
302 return 0;
305 static inline int isom_initialize_codec_specific_data( lsmash_codec_specific_t *specific,
306 lsmash_codec_specific_data_type type,
307 lsmash_codec_specific_format format )
309 specific->type = type;
310 specific->format = format;
311 if( format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
313 int err = isom_initialize_structured_codec_specific_data( specific );
314 if( err < 0 )
315 return err;
317 else
319 specific->data.unstructured = NULL;
320 specific->size = 0;
321 specific->destruct = (lsmash_codec_specific_destructor_t)lsmash_free;
323 return 0;
326 void lsmash_destroy_codec_specific_data( lsmash_codec_specific_t *specific )
328 if( !specific )
329 return;
330 if( specific->destruct )
332 if( specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
334 if( specific->data.structured )
335 specific->destruct( specific->data.structured );
337 else
339 if( specific->data.unstructured )
340 specific->destruct( specific->data.unstructured );
343 lsmash_free( specific );
346 lsmash_codec_specific_t *lsmash_create_codec_specific_data( lsmash_codec_specific_data_type type, lsmash_codec_specific_format format )
348 lsmash_codec_specific_t *specific = lsmash_malloc( sizeof(lsmash_codec_specific_t) );
349 if( !specific )
350 return NULL;
351 if( isom_initialize_codec_specific_data( specific, type, format ) < 0 )
353 lsmash_destroy_codec_specific_data( specific );
354 return NULL;
356 return specific;
359 static int isom_duplicate_structured_specific_data( lsmash_codec_specific_t *dst, lsmash_codec_specific_t *src )
361 extern int mp4sys_copy_decoder_config( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
362 extern int h264_copy_codec_specific( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
363 extern int hevc_copy_codec_specific( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
364 extern int vc1_copy_codec_specific( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
365 extern int dts_copy_codec_specific( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
366 void *src_data = src->data.structured;
367 void *dst_data = dst->data.structured;
368 switch( src->type )
370 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG :
371 return mp4sys_copy_decoder_config( dst, src );
372 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264 :
373 return h264_copy_codec_specific( dst, src );
374 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_HEVC :
375 return hevc_copy_codec_specific( dst, src );
376 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_VC_1 :
377 return vc1_copy_codec_specific( dst, src );
378 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_AC_3 :
379 *(lsmash_ac3_specific_parameters_t *)dst_data = *(lsmash_ac3_specific_parameters_t *)src_data;
380 return 0;
381 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_EC_3 :
382 *(lsmash_eac3_specific_parameters_t *)dst_data = *(lsmash_eac3_specific_parameters_t *)src_data;
383 return 0;
384 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS :
385 return dts_copy_codec_specific( dst, src );
386 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_ALAC :
387 *(lsmash_alac_specific_parameters_t *)dst_data = *(lsmash_alac_specific_parameters_t *)src_data;
388 return 0;
389 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_SAMPLE_SCALE :
390 *(lsmash_isom_sample_scale_t *)dst_data = *(lsmash_isom_sample_scale_t *)src_data;
391 return 0;
392 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264_BITRATE :
393 *(lsmash_h264_bitrate_t *)dst_data = *(lsmash_h264_bitrate_t *)src_data;
394 return 0;
395 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_COMMON :
396 *(lsmash_qt_video_common_t *)dst_data = *(lsmash_qt_video_common_t *)src_data;
397 return 0;
398 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_COMMON :
399 *(lsmash_qt_audio_common_t *)dst_data = *(lsmash_qt_audio_common_t *)src_data;
400 return 0;
401 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS :
402 *(lsmash_qt_audio_format_specific_flags_t *)dst_data = *(lsmash_qt_audio_format_specific_flags_t *)src_data;
403 return 0;
404 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER :
406 lsmash_codec_global_header_t *src_global = (lsmash_codec_global_header_t *)src_data;
407 if( src_global->header_data && src_global->header_size )
409 lsmash_codec_global_header_t *dst_global = (lsmash_codec_global_header_t *)dst_data;
410 dst_global->header_data = lsmash_memdup( src_global->header_data, src_global->header_size );
411 if( !dst_global->header_data )
412 return LSMASH_ERR_MEMORY_ALLOC;
413 dst_global->header_size = src_global->header_size;
415 return 0;
417 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_FIELD_INFO :
418 *(lsmash_qt_field_info_t *)dst_data = *(lsmash_qt_field_info_t *)src_data;
419 return 0;
420 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_PIXEL_FORMAT :
421 *(lsmash_qt_pixel_format_t *)dst_data = *(lsmash_qt_pixel_format_t *)src_data;
422 return 0;
423 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_SIGNIFICANT_BITS :
424 *(lsmash_qt_significant_bits_t *)dst_data = *(lsmash_qt_significant_bits_t *)src_data;
425 return 0;
426 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_GAMMA_LEVEL :
427 *(lsmash_qt_gamma_t *)dst_data = *(lsmash_qt_gamma_t *)src_data;
428 return 0;
429 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_CONTENT_LIGHT_LEVEL_INFO :
430 *(lsmash_qt_content_light_level_info_t *)dst_data = *(lsmash_qt_content_light_level_info_t *)src_data;
431 return 0;
432 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_MASTERING_DISPLAY_COLOR_VOLUME :
433 *(lsmash_qt_mastering_display_color_volume_t *)dst_data = *(lsmash_qt_mastering_display_color_volume_t *)src_data;
434 return 0;
435 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT :
436 *(lsmash_qt_audio_channel_layout_t *)dst_data = *(lsmash_qt_audio_channel_layout_t *)src_data;
437 return 0;
438 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_RTP_HINT_COMMON:
439 *(lsmash_isom_rtp_reception_hint_t *)dst_data = *(lsmash_isom_rtp_reception_hint_t *)src_data;
440 return 0;
441 default :
442 return LSMASH_ERR_NAMELESS;
446 lsmash_codec_specific_t *isom_duplicate_codec_specific_data( lsmash_codec_specific_t *specific )
448 if( !specific )
449 return NULL;
450 lsmash_codec_specific_t *dup = lsmash_create_codec_specific_data( specific->type, specific->format );
451 if( !dup )
452 return NULL;
453 if( specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
455 if( isom_duplicate_structured_specific_data( dup, specific ) < 0 )
457 lsmash_destroy_codec_specific_data( dup );
458 return NULL;
461 else
463 dup->data.unstructured = lsmash_memdup( specific->data.unstructured, specific->size );
464 if( !dup->data.unstructured )
466 lsmash_destroy_codec_specific_data( dup );
467 return NULL;
470 dup->size = specific->size;
471 return dup;
474 static int isom_construct_global_specific_header( lsmash_codec_specific_t *dst, lsmash_codec_specific_t *src )
476 if( src->size < ISOM_BASEBOX_COMMON_SIZE )
477 return LSMASH_ERR_INVALID_DATA;
478 lsmash_codec_global_header_t *global = (lsmash_codec_global_header_t *)dst->data.structured;
479 uint8_t *data = src->data.unstructured;
480 uint64_t size = LSMASH_GET_BE32( data );
481 data += ISOM_BASEBOX_COMMON_SIZE;
482 if( size == 1 )
484 size = LSMASH_GET_BE64( data );
485 data += 8;
487 if( size != src->size )
488 return LSMASH_ERR_INVALID_DATA;
489 global->header_size = size - ISOM_BASEBOX_COMMON_SIZE;
490 if( data != src->data.unstructured + ISOM_BASEBOX_COMMON_SIZE )
491 global->header_size -= 8; /* largesize */
492 if( global->header_size )
494 global->header_data = lsmash_memdup( data, global->header_size );
495 if( !global->header_data )
496 return LSMASH_ERR_MEMORY_ALLOC;
498 return 0;
501 static int isom_construct_audio_channel_layout( lsmash_codec_specific_t *dst, lsmash_codec_specific_t *src )
503 if( src->size < ISOM_FULLBOX_COMMON_SIZE + 12 )
504 return LSMASH_ERR_INVALID_DATA;
505 lsmash_qt_audio_channel_layout_t *layout = (lsmash_qt_audio_channel_layout_t *)dst->data.structured;
506 uint8_t *data = src->data.unstructured;
507 uint64_t size = LSMASH_GET_BE32( data );
508 data += ISOM_FULLBOX_COMMON_SIZE;
509 if( size == 1 )
511 size = LSMASH_GET_BE64( data );
512 data += 8;
514 if( size != src->size )
515 return LSMASH_ERR_INVALID_DATA;
516 layout->channelLayoutTag = LSMASH_GET_BE32( &data[0] );
517 layout->channelBitmap = LSMASH_GET_BE32( &data[4] );
518 return 0;
521 #if 0
522 static int codec_construct_qt_audio_decompression_info( lsmash_codec_specific_t *dst, lsmash_codec_specific_t *src )
524 if( src->size < ISOM_BASEBOX_COMMON_SIZE )
525 return LSMASH_ERR_INVALID_DATA;
526 uint8_t *data = src->data.unstructured;
527 uint64_t size;
528 uint32_t type;
529 uint32_t offset = isom_read_box_size_and_type_from_binary_string( &data, &size, &type );
530 if( size != src->size )
531 return LSMASH_ERR_INVALID_DATA;
532 uint8_t *end = src->data.unstructured + src->size;
533 isom_wave_t *wave = isom_add_wave( isom_non_existing_audio_entry() );
534 if( LSMASH_IS_NON_EXISTING_BOX( wave ) )
535 return LSMASH_ERR_MEMORY_ALLOC;
536 wave->type = QT_BOX_TYPE_WAVE;
537 for( uint8_t *pos = data; pos + ISOM_BASEBOX_COMMON_SIZE <= end; )
539 offset = isom_read_box_size_and_type_from_binary_string( &pos, &size, &type );
540 switch( type )
542 case QT_BOX_TYPE_FRMA :
544 if( pos + 4 > end )
545 return LSMASH_ERR_INVALID_DATA;
546 isom_frma_t *frma = isom_add_frma( wave );
547 if( LSMASH_IS_NON_EXISTING_BOX( frma ) )
548 return LSMASH_ERR_NAMELESS;
549 frma->data_format = LSMASH_GET_BE32( pos );
550 pos += 4;
551 break;
553 case QT_BOX_TYPE_ENDA :
555 if( pos + 2 > end )
556 return LSMASH_ERR_INVALID_DATA;
557 isom_enda_t *enda = isom_add_enda( wave );
558 if( LSMASH_IS_NON_EXISTING_BOX( enda ) )
559 return LSMASH_ERR_NAMELESS;
560 enda->littleEndian = LSMASH_GET_BE16( pos );
561 break;
563 case QT_BOX_TYPE_MP4A :
565 if( pos + 4 > end )
566 return LSMASH_ERR_INVALID_DATA;
567 isom_mp4a_t *mp4a = isom_add_mp4a( wave );
568 if( LSMASH_IS_NON_EXISTING_BOX( mp4a ) )
569 return LSMASH_ERR_NAMELESS;
570 mp4a->unknown = LSMASH_GET_BE32( pos );
571 pos += 4;
572 break;
574 case QT_BOX_TYPE_TERMINATOR :
576 if( LSMASH_IS_BOX_ADDITION_FAILURE( isom_add_terminator( wave ) ) )
577 return LSMASH_ERR_NAMELESS;
578 break;
580 default :
582 isom_unknown_box_t *box = lsmash_malloc_zero( sizeof(isom_unknown_box_t) );
583 if( LSMASH_IS_NON_EXISTING_BOX( box ) )
584 return LSMASH_ERR_MEMORY_ALLOC;
585 isom_init_box_common( box, wave, type, isom_remove_unknown_box );
586 box->unknown_size = size - offset;
587 box->unknown_field = lsmash_memdup( pos, box->unknown_size );
588 if( !box->unknown_field )
590 isom_remove_box_by_itself( box );
591 return LSMASH_ERR_MEMORY_ALLOC;
593 if( lsmash_list_add_entry( &wave->extensions, box ) < 0 )
595 isom_remove_unknown_box( box );
596 return LSMASH_ERR_MEMORY_ALLOC;
598 pos += box->unknown_size;
599 break;
603 return 0;
605 #endif
607 /* structured <-> unstructured conversion might be irreversible by CODEC
608 * since structured formats we defined don't always have all contents included in unstructured data. */
609 lsmash_codec_specific_t *lsmash_convert_codec_specific_format( lsmash_codec_specific_t *specific, lsmash_codec_specific_format format )
611 if( !specific || format == LSMASH_CODEC_SPECIFIC_FORMAT_UNSPECIFIED )
612 return NULL;
613 if( format == specific->format )
614 return isom_duplicate_codec_specific_data( specific );
615 lsmash_codec_specific_t *dst = lsmash_create_codec_specific_data( specific->type, format );
616 if( !dst )
617 return NULL;
618 if( format == LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED )
619 /* structured -> unstructured */
620 switch( specific->type )
622 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG :
623 dst->data.unstructured = lsmash_create_mp4sys_decoder_config( (lsmash_mp4sys_decoder_parameters_t *)specific->data.structured, &dst->size );
624 if( !dst->data.unstructured )
625 goto fail;
626 return dst;
627 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264 :
628 dst->data.unstructured = lsmash_create_h264_specific_info( (lsmash_h264_specific_parameters_t *)specific->data.structured, &dst->size );
629 if( !dst->data.unstructured )
630 goto fail;
631 return dst;
632 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_HEVC :
633 dst->data.unstructured = lsmash_create_hevc_specific_info( (lsmash_hevc_specific_parameters_t *)specific->data.structured, &dst->size );
634 if( !dst->data.unstructured )
635 goto fail;
636 return dst;
637 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_VC_1 :
638 dst->data.unstructured = lsmash_create_vc1_specific_info( (lsmash_vc1_specific_parameters_t *)specific->data.structured, &dst->size );
639 if( !dst->data.unstructured )
640 goto fail;
641 return dst;
642 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_AC_3 :
643 dst->data.unstructured = lsmash_create_ac3_specific_info( (lsmash_ac3_specific_parameters_t *)specific->data.structured, &dst->size );
644 if( !dst->data.unstructured )
645 goto fail;
646 return dst;
647 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_EC_3 :
648 dst->data.unstructured = lsmash_create_eac3_specific_info( (lsmash_eac3_specific_parameters_t *)specific->data.structured, &dst->size );
649 if( !dst->data.unstructured )
650 goto fail;
651 return dst;
652 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS :
653 dst->data.unstructured = lsmash_create_dts_specific_info( (lsmash_dts_specific_parameters_t *)specific->data.structured, &dst->size );
654 if( !dst->data.unstructured )
655 goto fail;
656 return dst;
657 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_ALAC :
658 dst->data.unstructured = lsmash_create_alac_specific_info( (lsmash_alac_specific_parameters_t *)specific->data.structured, &dst->size );
659 if( !dst->data.unstructured )
660 goto fail;
661 return dst;
662 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER :
664 lsmash_bs_t *bs = lsmash_bs_create();
665 if( !bs )
666 goto fail;
667 lsmash_codec_global_header_t *global = specific->data.structured;
668 lsmash_bs_put_be32( bs, ISOM_BASEBOX_COMMON_SIZE + global->header_size );
669 lsmash_bs_put_be32( bs, QT_BOX_TYPE_GLBL.fourcc );
670 lsmash_bs_put_bytes( bs, global->header_size, global->header_data );
671 dst->data.unstructured = lsmash_bs_export_data( bs, &dst->size );
672 lsmash_bs_cleanup( bs );
673 if( !dst->data.unstructured || dst->size != (ISOM_BASEBOX_COMMON_SIZE + global->header_size) )
674 goto fail;
675 return dst;
677 default :
678 break;
680 else if( format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
682 /* unstructured -> structured */
683 extern int mp4sys_construct_decoder_config( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
684 extern int h264_construct_specific_parameters( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
685 extern int hevc_construct_specific_parameters( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
686 extern int vc1_construct_specific_parameters( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
687 extern int ac3_construct_specific_parameters( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
688 extern int eac3_construct_specific_parameters( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
689 extern int dts_construct_specific_parameters( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
690 extern int alac_construct_specific_parameters( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
691 static const struct
693 lsmash_codec_specific_data_type data_type;
694 int (*constructor)( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
695 } codec_specific_format_constructor_table[] =
697 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG, mp4sys_construct_decoder_config },
698 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264, h264_construct_specific_parameters },
699 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_HEVC, hevc_construct_specific_parameters },
700 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_VC_1, vc1_construct_specific_parameters },
701 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_AC_3, ac3_construct_specific_parameters },
702 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_EC_3, eac3_construct_specific_parameters },
703 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS, dts_construct_specific_parameters },
704 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_ALAC, alac_construct_specific_parameters },
705 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER, isom_construct_global_specific_header },
706 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT, isom_construct_audio_channel_layout },
707 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN, NULL }
709 int (*constructor)( lsmash_codec_specific_t *, lsmash_codec_specific_t * ) = NULL;
710 for( int i = 0; codec_specific_format_constructor_table[i].constructor; i++ )
711 if( specific->type == codec_specific_format_constructor_table[i].data_type )
713 constructor = codec_specific_format_constructor_table[i].constructor;
714 break;
716 if( constructor && !constructor( dst, specific ) )
717 return dst;
719 fail:
720 lsmash_destroy_codec_specific_data( dst );
721 return NULL;
724 static inline void isom_set_default_compressorname( char *compressorname, lsmash_codec_type_t sample_type )
726 static struct compressorname_table_tag
728 lsmash_codec_type_t type;
729 char name[33];
730 } compressorname_table[33] = { { LSMASH_CODEC_TYPE_INITIALIZER, { '\0' } } };
731 if( compressorname_table[0].name[0] == '\0' )
733 int i = 0;
734 #define ADD_COMPRESSORNAME_TABLE( type, name ) compressorname_table[i++] = (struct compressorname_table_tag){ type, name }
735 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_AVC1_VIDEO, "\012AVC Coding" );
736 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_AVC2_VIDEO, "\012AVC Coding" );
737 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_AVC3_VIDEO, "\012AVC Coding" );
738 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_AVC4_VIDEO, "\012AVC Coding" );
739 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_AVCP_VIDEO, "\016AVC Parameters" );
740 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_HVC1_VIDEO, "\013HEVC Coding" );
741 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_HEV1_VIDEO, "\013HEVC Coding" );
742 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_SVC1_VIDEO, "\012SVC Coding" );
743 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_MVC1_VIDEO, "\012MVC Coding" );
744 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_MVC2_VIDEO, "\012MVC Coding" );
745 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_APCH_VIDEO, "\023Apple ProRes 422 (HQ)" );
746 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_APCN_VIDEO, "\023Apple ProRes 422 (SD)" );
747 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_APCS_VIDEO, "\023Apple ProRes 422 (LT)" );
748 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_APCO_VIDEO, "\026Apple ProRes 422 (Proxy)" );
749 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_AP4H_VIDEO, "\019Apple ProRes 4444" );
750 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_AP4X_VIDEO, "\022Apple ProRes 4444 XQ" );
751 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DVPP_VIDEO, "\014DVCPRO - PAL" );
752 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DV5N_VIDEO, "\017DVCPRO50 - NTSC" );
753 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DV5P_VIDEO, "\016DVCPRO50 - PAL" );
754 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DVH2_VIDEO, "\019DVCPRO HD 1080p25" );
755 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DVH3_VIDEO, "\019DVCPRO HD 1080p30" );
756 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DVH5_VIDEO, "\019DVCPRO HD 1080i50" );
757 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DVH6_VIDEO, "\019DVCPRO HD 1080i60" );
758 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DVHP_VIDEO, "\018DVCPRO HD 720p60" );
759 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DVHQ_VIDEO, "\018DVCPRO HD 720p50" );
760 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_ULRA_VIDEO, "\017Ut Video (ULRA)" );
761 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_ULRG_VIDEO, "\017Ut Video (ULRG)" );
762 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_ULY0_VIDEO, "\017Ut Video (ULY0)" );
763 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_ULY2_VIDEO, "\017Ut Video (ULY2)" );
764 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_ULH0_VIDEO, "\017Ut Video (ULH0)" );
765 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_ULH2_VIDEO, "\017Ut Video (ULH2)" );
766 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_UQY2_VIDEO, "\021Ut Video Pro (UQY2)" );
767 ADD_COMPRESSORNAME_TABLE( LSMASH_CODEC_TYPE_UNSPECIFIED, { '\0' } );
768 #undef ADD_COMPRESSORNAME_TABLE
770 for( int i = 0; compressorname_table[i].name[0] != '\0'; i++ )
771 if( lsmash_check_codec_type_identical( sample_type, compressorname_table[i].type ) )
773 strcpy( compressorname, compressorname_table[i].name );
774 return;
778 lsmash_codec_specific_t *isom_get_codec_specific( lsmash_codec_specific_list_t *opaque, lsmash_codec_specific_data_type type )
780 for( lsmash_entry_t *entry = opaque->list.head; entry; entry = entry->next )
782 lsmash_codec_specific_t *specific = (lsmash_codec_specific_t *)entry->data;
783 if( !specific || specific->type != type )
784 continue;
785 return specific;
787 return NULL;
790 static int isom_check_valid_summary( lsmash_summary_t *summary )
792 if( !summary )
793 return LSMASH_ERR_NAMELESS;
794 isom_box_t temp_box;
795 temp_box.type = summary->sample_type;
796 temp_box.manager = summary->summary_type == LSMASH_SUMMARY_TYPE_AUDIO ? LSMASH_AUDIO_DESCRIPTION: 0;
797 if( isom_is_lpcm_audio( &temp_box ) )
799 if( isom_get_codec_specific( summary->opaque, LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS ) )
800 return 0;
801 return LSMASH_ERR_INVALID_DATA;
803 if( isom_is_uncompressed_ycbcr( summary->sample_type ) )
805 if( isom_get_codec_specific( summary->opaque, LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_FIELD_INFO ) )
807 if( !lsmash_check_codec_type_identical( summary->sample_type, QT_CODEC_TYPE_V216_VIDEO ) )
808 return 0;
810 else
811 return LSMASH_ERR_INVALID_DATA;
813 lsmash_codec_type_t sample_type = summary->sample_type;
814 lsmash_codec_specific_data_type required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNSPECIFIED;
815 if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_AVC1_VIDEO )
816 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_AVC2_VIDEO )
817 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_AVC3_VIDEO )
818 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_AVC4_VIDEO ) )
819 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264;
820 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_HVC1_VIDEO )
821 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_HEV1_VIDEO ) )
822 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_HEVC;
823 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_VC_1_VIDEO ) )
824 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_VC_1 ;
825 else if( lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_ULRA_VIDEO )
826 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_ULRG_VIDEO )
827 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_ULY0_VIDEO )
828 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_ULY2_VIDEO )
829 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_ULH0_VIDEO )
830 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_ULH2_VIDEO )
831 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_UQY2_VIDEO ) )
832 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER;
833 else if( lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_V216_VIDEO ) )
834 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_SIGNIFICANT_BITS;
835 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_MP4V_VIDEO )
836 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_MP4A_AUDIO )
837 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_MP4A_AUDIO ) )
838 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG;
839 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_AC_3_AUDIO ) )
840 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_AC_3;
841 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_EC_3_AUDIO ) )
842 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_EC_3;
843 else if( isom_is_dts_audio( sample_type ) )
844 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS;
845 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_ALAC_AUDIO )
846 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_ALAC_AUDIO ) )
847 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_ALAC;
848 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_RRTP_HINT ) )
849 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_RTP_HINT_COMMON;
850 if( required_data_type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNSPECIFIED )
851 return 0;
852 return isom_get_codec_specific( summary->opaque, required_data_type ) ? 0 : LSMASH_ERR_INVALID_DATA;
855 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 )
857 lsmash_box_type_t box_type = LSMASH_BOX_TYPE_INITIALIZER;
858 box_type.fourcc = fourcc;
859 #define GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( codec_type, predefined_box_type ) \
860 else if( (codec_type.user.fourcc == 0 \
861 || lsmash_check_codec_type_identical( active_codec_type, codec_type )) \
862 && box_type.fourcc == predefined_box_type.fourcc ) \
863 box_type = predefined_box_type
864 if( 0 );
865 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_AVC1_VIDEO, ISOM_BOX_TYPE_AVCC );
866 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_AVC2_VIDEO, ISOM_BOX_TYPE_AVCC );
867 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_AVC3_VIDEO, ISOM_BOX_TYPE_AVCC );
868 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_AVC4_VIDEO, ISOM_BOX_TYPE_AVCC );
869 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_AVCP_VIDEO, ISOM_BOX_TYPE_AVCC );
870 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_HVC1_VIDEO, ISOM_BOX_TYPE_HVCC );
871 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_HEV1_VIDEO, ISOM_BOX_TYPE_HVCC );
872 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_VC_1_VIDEO, ISOM_BOX_TYPE_DVC1 );
873 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_MP4V_VIDEO, ISOM_BOX_TYPE_ESDS );
874 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, ISOM_BOX_TYPE_BTRT );
875 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, QT_BOX_TYPE_FIEL );
876 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, QT_BOX_TYPE_CSPC );
877 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, QT_BOX_TYPE_SGBT );
878 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, QT_BOX_TYPE_GAMA );
879 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, QT_BOX_TYPE_GLBL );
880 #undef GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE
881 return box_type;
884 static int isom_setup_visual_description( isom_stsd_t *stsd, lsmash_video_summary_t *summary )
886 if( !summary || LSMASH_IS_NON_EXISTING_BOX( stsd->parent->parent->parent->parent ) )
887 return LSMASH_ERR_NAMELESS;
888 int err = isom_check_valid_summary( (lsmash_summary_t *)summary );
889 if( err < 0 )
890 return err;
891 isom_visual_entry_t *visual = isom_add_visual_description( stsd, summary->sample_type );
892 if( LSMASH_IS_NON_EXISTING_BOX( visual ) )
893 return LSMASH_ERR_NAMELESS;
894 visual->data_reference_index = summary->data_ref_index;
895 visual->version = 0;
896 visual->revision_level = 0;
897 visual->vendor = 0;
898 visual->temporalQuality = 0;
899 visual->spatialQuality = 0;
900 visual->width = (uint16_t)summary->width;
901 visual->height = (uint16_t)summary->height;
902 visual->horizresolution = 0x00480000;
903 visual->vertresolution = 0x00480000;
904 visual->dataSize = 0;
905 visual->frame_count = 1;
906 visual->depth = isom_is_qt_video( visual->type ) || isom_is_nalff( visual->type )
907 ? summary->depth : 0x0018;
908 visual->color_table_ID = -1;
909 if( summary->compressorname[0] == '\0' )
910 isom_set_default_compressorname( visual->compressorname, visual->type );
911 else
913 memcpy( visual->compressorname, summary->compressorname, 32 );
914 visual->compressorname[32] = '\0';
916 err = LSMASH_ERR_NAMELESS;
917 for( lsmash_entry_t *entry = summary->opaque->list.head; entry; entry = entry->next )
919 lsmash_codec_specific_t *specific = (lsmash_codec_specific_t *)entry->data;
920 if( !specific )
921 goto fail;
922 if( specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN
923 && specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
924 continue; /* LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN + LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED is not supported. */
925 switch( specific->type )
927 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_COMMON :
929 if( specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED )
930 continue;
931 lsmash_qt_video_common_t *data = (lsmash_qt_video_common_t *)specific->data.structured;
932 visual->revision_level = data->revision_level;
933 visual->vendor = data->vendor;
934 visual->temporalQuality = data->temporalQuality;
935 visual->spatialQuality = data->spatialQuality;
936 visual->horizresolution = data->horizontal_resolution;
937 visual->vertresolution = data->vertical_resolution;
938 visual->dataSize = data->dataSize;
939 visual->frame_count = data->frame_count;
940 visual->color_table_ID = data->color_table_ID;
941 if( data->color_table_ID == 0 )
943 lsmash_qt_color_table_t *src_ct = &data->color_table;
944 uint16_t element_count = LSMASH_MIN( src_ct->size + 1, 256 );
945 isom_qt_color_array_t *dst_array = lsmash_malloc_zero( element_count * sizeof(isom_qt_color_array_t) );
946 if( !dst_array )
948 err = LSMASH_ERR_MEMORY_ALLOC;
949 goto fail;
951 isom_qt_color_table_t *dst_ct = &visual->color_table;
952 dst_ct->array = dst_array;
953 dst_ct->seed = src_ct->seed;
954 dst_ct->flags = src_ct->flags;
955 dst_ct->size = src_ct->size;
956 for( uint16_t i = 0; i < element_count; i++ )
958 dst_array[i].value = src_ct->array[i].unused;
959 dst_array[i].r = src_ct->array[i].r;
960 dst_array[i].g = src_ct->array[i].g;
961 dst_array[i].b = src_ct->array[i].b;
964 break;
966 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_SAMPLE_SCALE :
968 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
969 if( !cs )
970 goto fail;
971 lsmash_isom_sample_scale_t *data = (lsmash_isom_sample_scale_t *)cs->data.structured;
972 isom_stsl_t *stsl = isom_add_stsl( visual );
973 if( LSMASH_IS_NON_EXISTING_BOX( stsl ) )
975 lsmash_destroy_codec_specific_data( cs );
976 goto fail;
978 stsl->constraint_flag = data->constraint_flag;
979 stsl->scale_method = data->scale_method;
980 stsl->display_center_x = data->display_center_x;
981 stsl->display_center_y = data->display_center_y;
982 lsmash_destroy_codec_specific_data( cs );
983 break;
985 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264_BITRATE :
987 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
988 if( !cs )
989 goto fail;
990 lsmash_h264_bitrate_t *data = (lsmash_h264_bitrate_t *)cs->data.structured;
991 isom_btrt_t *btrt = isom_add_btrt( visual );
992 if( LSMASH_IS_NON_EXISTING_BOX( btrt ) )
994 lsmash_destroy_codec_specific_data( cs );
995 goto fail;
997 btrt->bufferSizeDB = data->bufferSizeDB;
998 btrt->maxBitrate = data->maxBitrate;
999 btrt->avgBitrate = data->avgBitrate;
1000 lsmash_destroy_codec_specific_data( cs );
1001 break;
1003 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_FIELD_INFO :
1005 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
1006 if( !cs )
1007 goto fail;
1008 lsmash_qt_field_info_t *data = (lsmash_qt_field_info_t *)cs->data.structured;
1009 isom_fiel_t *fiel = isom_add_fiel( visual );
1010 if( LSMASH_IS_NON_EXISTING_BOX( fiel ) )
1012 lsmash_destroy_codec_specific_data( cs );
1013 goto fail;
1015 fiel->fields = data->fields;
1016 fiel->detail = data->detail;
1017 lsmash_destroy_codec_specific_data( cs );
1018 break;
1020 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_PIXEL_FORMAT :
1022 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
1023 if( !cs )
1024 goto fail;
1025 lsmash_qt_pixel_format_t *data = (lsmash_qt_pixel_format_t *)cs->data.structured;
1026 isom_cspc_t *cspc = isom_add_cspc( visual );
1027 if( LSMASH_IS_NON_EXISTING_BOX( cspc ) )
1029 lsmash_destroy_codec_specific_data( cs );
1030 goto fail;
1032 cspc->pixel_format = data->pixel_format;
1033 lsmash_destroy_codec_specific_data( cs );
1034 break;
1036 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_SIGNIFICANT_BITS :
1038 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
1039 if( !cs )
1040 goto fail;
1041 lsmash_qt_significant_bits_t *data = (lsmash_qt_significant_bits_t *)cs->data.structured;
1042 isom_sgbt_t *sgbt = isom_add_sgbt( visual );
1043 if( LSMASH_IS_NON_EXISTING_BOX( sgbt ) )
1045 lsmash_destroy_codec_specific_data( cs );
1046 goto fail;
1048 sgbt->significantBits = data->significantBits;
1049 lsmash_destroy_codec_specific_data( cs );
1050 break;
1052 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_GAMMA_LEVEL :
1054 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
1055 if( !cs )
1056 goto fail;
1057 lsmash_qt_gamma_t *data = (lsmash_qt_gamma_t *)cs->data.structured;
1058 isom_gama_t *gama = isom_add_gama( visual );
1059 if( LSMASH_IS_NON_EXISTING_BOX( gama ) )
1061 lsmash_destroy_codec_specific_data( cs );
1062 goto fail;
1064 gama->level = data->level;
1065 lsmash_destroy_codec_specific_data( cs );
1066 break;
1068 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_CONTENT_LIGHT_LEVEL_INFO :
1070 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
1071 if( !cs )
1072 goto fail;
1073 lsmash_qt_content_light_level_info_t *data = (lsmash_qt_content_light_level_info_t *)cs->data.structured;
1074 isom_clli_t *clli = isom_add_clli( visual );
1075 if( LSMASH_IS_NON_EXISTING_BOX( clli ) )
1077 lsmash_destroy_codec_specific_data( cs );
1078 goto fail;
1080 clli->max_content_light_level = data->max_content_light_level;
1081 clli->max_pic_average_light_level = data->max_pic_average_light_level;
1082 lsmash_destroy_codec_specific_data( cs );
1083 break;
1085 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_MASTERING_DISPLAY_COLOR_VOLUME :
1087 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
1088 if( !cs )
1089 goto fail;
1090 lsmash_qt_mastering_display_color_volume_t *data = (lsmash_qt_mastering_display_color_volume_t *)cs->data.structured;
1091 isom_mdcv_t *mdcv = isom_add_mdcv( visual );
1092 if( LSMASH_IS_NON_EXISTING_BOX( mdcv ) )
1094 lsmash_destroy_codec_specific_data( cs );
1095 goto fail;
1097 mdcv->display_primaries_g_x = data->display_primaries_g_x;
1098 mdcv->display_primaries_g_y = data->display_primaries_g_y;
1099 mdcv->display_primaries_b_x = data->display_primaries_b_x;
1100 mdcv->display_primaries_b_y = data->display_primaries_b_y;
1101 mdcv->display_primaries_r_x = data->display_primaries_r_x;
1102 mdcv->display_primaries_r_y = data->display_primaries_r_y;
1103 mdcv->white_point_x = data->white_point_x;
1104 mdcv->white_point_y = data->white_point_y;
1105 mdcv->max_display_mastering_luminance = data->max_display_mastering_luminance;
1106 mdcv->min_display_mastering_luminance = data->min_display_mastering_luminance;
1107 lsmash_destroy_codec_specific_data( cs );
1108 break;
1110 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER :
1112 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
1113 if( !cs )
1114 goto fail;
1115 lsmash_codec_global_header_t *data = (lsmash_codec_global_header_t *)cs->data.structured;
1116 isom_glbl_t *glbl = isom_add_glbl( visual );
1117 if( LSMASH_IS_NON_EXISTING_BOX( glbl ) )
1119 lsmash_destroy_codec_specific_data( cs );
1120 goto fail;
1122 glbl->header_size = data->header_size;
1123 glbl->header_data = lsmash_memdup( data->header_data, data->header_size );
1124 lsmash_destroy_codec_specific_data( cs );
1125 if( !glbl->header_data )
1127 isom_remove_box_by_itself( glbl );
1128 err = LSMASH_ERR_MEMORY_ALLOC;
1129 goto fail;
1131 break;
1133 default :
1135 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
1136 if( !cs )
1137 goto fail;
1138 if( cs->size < ISOM_BASEBOX_COMMON_SIZE )
1140 lsmash_destroy_codec_specific_data( cs );
1141 err = LSMASH_ERR_INVALID_DATA;
1142 goto fail;
1144 uint8_t *data = cs->data.unstructured;
1145 lsmash_compact_box_type_t fourcc = LSMASH_4CC( data[4], data[5], data[6], data[7] );
1146 lsmash_box_type_t box_type = isom_guess_video_codec_specific_box_type( visual->type, fourcc );
1147 /* Append the extension. */
1148 err = isom_add_extension_binary( visual, box_type, LSMASH_BOX_PRECEDENCE_HM, cs->data.unstructured, cs->size );
1149 cs->data.unstructured = NULL; /* Avoid freeing the binary data of the extension. */
1150 lsmash_destroy_codec_specific_data( cs );
1151 if( err < 0 )
1152 goto fail;
1153 break;
1157 isom_trak_t *trak = (isom_trak_t *)visual->parent->parent->parent->parent->parent;
1158 int qt_compatible = trak->file->qt_compatible;
1159 isom_tapt_t *tapt = trak->tapt;
1160 isom_stsl_t *stsl = (isom_stsl_t *)isom_get_extension_box_format( &visual->extensions, ISOM_BOX_TYPE_STSL );
1161 int set_aperture_modes = qt_compatible /* Track Aperture Modes is only available under QuickTime file format. */
1162 && (LSMASH_IS_NON_EXISTING_BOX( stsl ) || stsl->scale_method == 0) /* Sample scaling method might conflict with this feature. */
1163 && LSMASH_IS_EXISTING_BOX( tapt->clef )
1164 && LSMASH_IS_EXISTING_BOX( tapt->prof )
1165 && LSMASH_IS_EXISTING_BOX( tapt->enof ) /* Check if required boxes exist. */
1166 && ((isom_stsd_t *)visual->parent)->list.entry_count == 1; /* Multiple sample description might conflict with this, so in that case, disable this feature. */
1167 if( !set_aperture_modes )
1168 isom_remove_box_by_itself( trak->tapt );
1169 int uncompressed_ycbcr = qt_compatible && isom_is_uncompressed_ycbcr( visual->type );
1170 /* Set up Clean Aperture. */
1171 if( set_aperture_modes || uncompressed_ycbcr
1172 || (summary->clap.width.d && summary->clap.height.d && summary->clap.horizontal_offset.d && summary->clap.vertical_offset.d) )
1174 isom_clap_t *clap = isom_add_clap( visual );
1175 if( LSMASH_IS_NON_EXISTING_BOX( clap ) )
1176 goto fail;
1177 if( summary->clap.width.d && summary->clap.height.d && summary->clap.horizontal_offset.d && summary->clap.vertical_offset.d )
1179 clap->cleanApertureWidthN = summary->clap.width.n;
1180 clap->cleanApertureWidthD = summary->clap.width.d;
1181 clap->cleanApertureHeightN = summary->clap.height.n;
1182 clap->cleanApertureHeightD = summary->clap.height.d;
1183 clap->horizOffN = summary->clap.horizontal_offset.n;
1184 clap->horizOffD = summary->clap.horizontal_offset.d;
1185 clap->vertOffN = summary->clap.vertical_offset.n;
1186 clap->vertOffD = summary->clap.vertical_offset.d;
1188 else
1190 clap->cleanApertureWidthN = summary->width;
1191 clap->cleanApertureWidthD = 1;
1192 clap->cleanApertureHeightN = summary->height;
1193 clap->cleanApertureHeightD = 1;
1194 clap->horizOffN = 0;
1195 clap->horizOffD = 1;
1196 clap->vertOffN = 0;
1197 clap->vertOffD = 1;
1200 /* Set up Pixel Aspect Ratio. */
1201 if( set_aperture_modes || (summary->par_h && summary->par_v) )
1203 isom_pasp_t *pasp = isom_add_pasp( visual );
1204 if( LSMASH_IS_NON_EXISTING_BOX( pasp ) )
1205 goto fail;
1206 pasp->hSpacing = LSMASH_MAX( summary->par_h, 1 );
1207 pasp->vSpacing = LSMASH_MAX( summary->par_v, 1 );
1209 /* Set up Color Parameter. */
1210 if( uncompressed_ycbcr
1211 || summary->color.primaries_index
1212 || summary->color.transfer_index
1213 || summary->color.matrix_index
1214 || (trak->file->isom_compatible && summary->color.full_range) )
1216 isom_colr_t *colr = isom_add_colr( visual );
1217 if( LSMASH_IS_NON_EXISTING_BOX( colr ) )
1218 goto fail;
1219 /* Set 'nclc' to parameter type, we don't support 'prof'. */
1220 uint16_t primaries = summary->color.primaries_index;
1221 uint16_t transfer = summary->color.transfer_index;
1222 uint16_t matrix = summary->color.matrix_index;
1223 if( qt_compatible && !trak->file->isom_compatible )
1225 colr->manager |= LSMASH_QTFF_BASE;
1226 colr->type = QT_BOX_TYPE_COLR;
1227 colr->color_parameter_type = QT_COLOR_PARAMETER_TYPE_NCLC;
1228 colr->primaries_index = (primaries == 1 || primaries == 5 || primaries == 6)
1229 ? primaries : QT_PRIMARIES_INDEX_UNSPECIFIED;
1230 colr->transfer_function_index = (transfer == 1 || transfer == 7)
1231 ? transfer : QT_TRANSFER_INDEX_UNSPECIFIED;
1232 colr->matrix_index = (matrix == 1 || matrix == 6 || matrix == 7)
1233 ? matrix : QT_MATRIX_INDEX_UNSPECIFIED;
1235 else
1237 colr->type = ISOM_BOX_TYPE_COLR;
1238 colr->color_parameter_type = ISOM_COLOR_PARAMETER_TYPE_NCLX;
1239 colr->primaries_index = (primaries == 1 || (primaries >= 4 && primaries <= 7))
1240 ? primaries : ISOM_PRIMARIES_INDEX_UNSPECIFIED;
1241 colr->transfer_function_index = (transfer == 1 || (transfer >= 4 && transfer <= 8) || (transfer >= 11 && transfer <= 13))
1242 ? transfer : ISOM_TRANSFER_INDEX_UNSPECIFIED;
1243 colr->matrix_index = (matrix == 1 || (matrix >= 4 && matrix <= 8))
1244 ? matrix : ISOM_MATRIX_INDEX_UNSPECIFIED;
1245 colr->full_range_flag = summary->color.full_range;
1248 /* Set up Track Apeture Modes. */
1249 if( set_aperture_modes )
1251 uint32_t width = visual->width << 16;
1252 uint32_t height = visual->height << 16;
1253 isom_clap_t *clap = (isom_clap_t *)isom_get_extension_box_format( &visual->extensions, ISOM_BOX_TYPE_CLAP );
1254 isom_pasp_t *pasp = (isom_pasp_t *)isom_get_extension_box_format( &visual->extensions, ISOM_BOX_TYPE_PASP );
1255 double clap_width = ((double)clap->cleanApertureWidthN / clap->cleanApertureWidthD) * (1<<16);
1256 double clap_height = ((double)clap->cleanApertureHeightN / clap->cleanApertureHeightD) * (1<<16);
1257 double par = (double)pasp->hSpacing / pasp->vSpacing;
1258 if( par >= 1.0 )
1260 tapt->clef->width = clap_width * par;
1261 tapt->clef->height = clap_height;
1262 tapt->prof->width = width * par;
1263 tapt->prof->height = height;
1265 else
1267 tapt->clef->width = clap_width;
1268 tapt->clef->height = clap_height / par;
1269 tapt->prof->width = width;
1270 tapt->prof->height = height / par;
1272 tapt->enof->width = width;
1273 tapt->enof->height = height;
1275 return 0;
1276 fail:
1277 isom_remove_box_by_itself( visual );
1278 return err;
1281 static int isom_append_audio_es_descriptor_extension( isom_box_t *box, lsmash_audio_summary_t *summary )
1283 uint32_t esds_size = 0;
1284 uint8_t *esds_data = NULL;
1285 lsmash_codec_specific_t *specific = isom_get_codec_specific( summary->opaque, LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG );
1286 if( !specific )
1287 return LSMASH_ERR_NAMELESS;
1288 if( specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED )
1290 esds_size = specific->size;
1291 esds_data = lsmash_memdup( specific->data.unstructured, specific->size );
1292 if( !esds_data )
1293 return LSMASH_ERR_MEMORY_ALLOC;
1295 else
1297 esds_data = lsmash_create_mp4sys_decoder_config( (lsmash_mp4sys_decoder_parameters_t *)specific->data.structured, &esds_size );
1298 if( !esds_data )
1299 return LSMASH_ERR_NAMELESS;
1301 isom_esds_t *esds = isom_add_esds( box );
1302 if( LSMASH_IS_NON_EXISTING_BOX( esds ) )
1304 lsmash_free( esds_data );
1305 return LSMASH_ERR_NAMELESS;
1307 lsmash_bs_t bs = { 0 };
1308 bs.buffer.data = esds_data + ISOM_FULLBOX_COMMON_SIZE;
1309 bs.buffer.alloc = esds_size - ISOM_FULLBOX_COMMON_SIZE;
1310 bs.buffer.store = bs.buffer.alloc;
1311 esds->ES = mp4sys_get_descriptor( &bs, NULL );
1312 lsmash_free( esds_data );
1313 if( !esds->ES )
1315 isom_remove_box_by_itself( esds );
1316 return LSMASH_ERR_NAMELESS;
1318 return 0;
1321 static int isom_append_channel_layout_extension( lsmash_codec_specific_t *specific, void *parent, uint32_t channels )
1323 assert( LSMASH_IS_EXISTING_BOX( (isom_box_t *)parent ) );
1324 if( isom_get_extension_box( &((isom_box_t *)parent)->extensions, QT_BOX_TYPE_CHAN ) )
1325 return 0; /* Audio Channel Layout Box is already present. */
1326 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
1327 if( !cs )
1328 return LSMASH_ERR_NAMELESS;
1329 lsmash_qt_audio_channel_layout_t *data = (lsmash_qt_audio_channel_layout_t *)cs->data.structured;
1330 lsmash_channel_layout_tag channelLayoutTag = data->channelLayoutTag;
1331 lsmash_channel_bitmap channelBitmap = data->channelBitmap;
1332 if( channelLayoutTag == QT_CHANNEL_LAYOUT_USE_CHANNEL_DESCRIPTIONS /* We don't support the feature of Channel Descriptions. */
1333 || (channelLayoutTag == QT_CHANNEL_LAYOUT_USE_CHANNEL_BITMAP && (!channelBitmap || channelBitmap > QT_CHANNEL_BIT_FULL)) )
1335 channelLayoutTag = QT_CHANNEL_LAYOUT_UNKNOWN | channels;
1336 channelBitmap = 0;
1338 lsmash_destroy_codec_specific_data( cs );
1339 /* Don't create Audio Channel Layout Box if the channel layout is unknown. */
1340 if( (channelLayoutTag ^ QT_CHANNEL_LAYOUT_UNKNOWN) >> 16 )
1342 isom_chan_t *chan = isom_add_chan( parent );
1343 if( LSMASH_IS_NON_EXISTING_BOX( chan ) )
1344 return LSMASH_ERR_NAMELESS;
1345 chan->channelLayoutTag = channelLayoutTag;
1346 chan->channelBitmap = channelBitmap;
1347 chan->numberChannelDescriptions = 0;
1348 chan->channelDescriptions = NULL;
1350 return 0;
1353 static int isom_set_qtff_mp4a_description( isom_audio_entry_t *audio, lsmash_audio_summary_t *summary )
1355 isom_wave_t *wave;
1356 isom_frma_t *frma;
1357 isom_mp4a_t *mp4a;
1358 isom_terminator_t *terminator;
1359 if( (wave = isom_add_wave( audio ), LSMASH_IS_NON_EXISTING_BOX( wave ))
1360 || (frma = isom_add_frma( wave ), LSMASH_IS_NON_EXISTING_BOX( frma ))
1361 || (mp4a = isom_add_mp4a( wave ), LSMASH_IS_NON_EXISTING_BOX( mp4a ))
1362 || (terminator = isom_add_terminator( wave ), LSMASH_IS_NON_EXISTING_BOX( terminator )) )
1364 lsmash_list_remove_entry_tail( &audio->extensions );
1365 return LSMASH_ERR_NAMELESS;
1367 frma->data_format = audio->type.fourcc;
1368 /* Add ES Descriptor Box. */
1369 int err = isom_append_audio_es_descriptor_extension( (isom_box_t *)wave, summary );
1370 if( err < 0 )
1371 return err;
1372 /* */
1373 audio->type = QT_CODEC_TYPE_MP4A_AUDIO;
1374 audio->version = (summary->channels > 2 || summary->frequency > UINT16_MAX) ? 2 : 1;
1375 audio->channelcount = audio->version == 2 ? 3 : LSMASH_MIN( summary->channels, 2 );
1376 audio->samplesize = 16;
1377 audio->compression_ID = QT_AUDIO_COMPRESSION_ID_VARIABLE_COMPRESSION;
1378 audio->packet_size = 0;
1379 if( audio->version == 1 )
1381 audio->samplerate = summary->frequency << 16;
1382 audio->samplesPerPacket = summary->samples_in_frame;
1383 audio->bytesPerPacket = 1; /* Apparently, this field is set to 1. */
1384 audio->bytesPerFrame = audio->bytesPerPacket * summary->channels;
1385 audio->bytesPerSample = 2;
1387 else /* audio->version == 2 */
1389 audio->samplerate = 0x00010000;
1390 audio->sizeOfStructOnly = 72;
1391 audio->audioSampleRate = (union {double d; uint64_t i;}){summary->frequency}.i;
1392 audio->numAudioChannels = summary->channels;
1393 audio->always7F000000 = 0x7F000000;
1394 audio->constBitsPerChannel = 0; /* compressed audio */
1395 audio->formatSpecificFlags = 0;
1396 audio->constBytesPerAudioPacket = 0; /* variable */
1397 audio->constLPCMFramesPerAudioPacket = summary->samples_in_frame;
1399 return 0;
1402 static int isom_set_isom_mp4a_description( isom_audio_entry_t *audio, lsmash_audio_summary_t *summary )
1404 if( summary->summary_type != LSMASH_SUMMARY_TYPE_AUDIO )
1405 return LSMASH_ERR_NAMELESS;
1406 /* Check objectTypeIndication. */
1407 lsmash_mp4sys_object_type_indication objectTypeIndication = lsmash_mp4sys_get_object_type_indication( (lsmash_summary_t *)summary );
1408 switch( objectTypeIndication )
1410 case MP4SYS_OBJECT_TYPE_Audio_ISO_14496_3:
1411 case MP4SYS_OBJECT_TYPE_Audio_ISO_13818_7_Main_Profile:
1412 case MP4SYS_OBJECT_TYPE_Audio_ISO_13818_7_LC_Profile:
1413 case MP4SYS_OBJECT_TYPE_Audio_ISO_13818_7_SSR_Profile:
1414 case MP4SYS_OBJECT_TYPE_Audio_ISO_13818_3: /* Legacy Interface */
1415 case MP4SYS_OBJECT_TYPE_Audio_ISO_11172_3: /* Legacy Interface */
1416 break;
1417 default:
1418 return LSMASH_ERR_NAMELESS;
1420 /* Add ES Descriptor Box. */
1421 int err = isom_append_audio_es_descriptor_extension( (isom_box_t *)audio, summary );
1422 if( err < 0 )
1423 return err;
1424 /* In pure mp4 file, these "template" fields shall be default values according to the spec.
1425 But not pure - hybrid with other spec - mp4 file can take other values.
1426 Which is to say, these template values shall be ignored in terms of mp4, except some object_type_indications.
1427 see 14496-14, "Template fields used". */
1428 audio->type = ISOM_CODEC_TYPE_MP4A_AUDIO;
1429 audio->version = 0;
1430 audio->revision_level = 0;
1431 audio->vendor = 0;
1432 audio->channelcount = 2;
1433 audio->samplesize = 16;
1434 audio->compression_ID = 0;
1435 audio->packet_size = 0;
1436 /* WARNING: This field cannot retain frequency above 65535Hz.
1437 This is not "FIXME", I just honestly implemented what the spec says.
1438 BTW, who ever expects sampling frequency takes fixed-point decimal??? */
1439 audio->samplerate = summary->frequency <= UINT16_MAX ? summary->frequency << 16 : 0;
1440 return 0;
1443 static int isom_set_qtff_lpcm_description( isom_audio_entry_t *audio, lsmash_audio_summary_t *summary )
1445 lsmash_qt_audio_format_specific_flags_t *lpcm = NULL;
1446 for( lsmash_entry_t *entry = summary->opaque->list.head; entry; entry = entry->next )
1448 lsmash_codec_specific_t *specific = (lsmash_codec_specific_t *)entry->data;
1449 if( !specific )
1450 continue;
1451 if( specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS
1452 && specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
1454 lpcm = (lsmash_qt_audio_format_specific_flags_t *)specific->data.structured;
1455 break;
1458 if( !lpcm )
1459 return LSMASH_ERR_NAMELESS;
1460 audio->manager |= LSMASH_QTFF_BASE;
1461 lsmash_codec_type_t sample_type = audio->type;
1462 /* Convert the sample type into 'lpcm' if the description doesn't match the format or version = 2 fields are needed. */
1463 if( (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_RAW_AUDIO )
1464 && (summary->sample_size != 8 || (lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT)))
1465 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_FL32_AUDIO )
1466 && (summary->sample_size != 32 || !(lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT)))
1467 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_FL64_AUDIO )
1468 && (summary->sample_size != 64 || !(lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT)))
1469 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_IN24_AUDIO )
1470 && (summary->sample_size != 24 || (lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT)))
1471 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_IN32_AUDIO )
1472 && (summary->sample_size != 32 || (lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT)))
1473 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_23NI_AUDIO )
1474 && (summary->sample_size != 32 || (lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT) || (lpcm->format_flags & QT_LPCM_FORMAT_FLAG_BIG_ENDIAN)))
1475 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_SOWT_AUDIO )
1476 && (summary->sample_size != 16 || (lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT) || (lpcm->format_flags & QT_LPCM_FORMAT_FLAG_BIG_ENDIAN)))
1477 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_TWOS_AUDIO )
1478 && ((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)))
1479 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_NONE_AUDIO )
1480 && ((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)))
1481 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_NOT_SPECIFIED )
1482 && ((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)))
1483 || (summary->channels > 2 || summary->frequency > UINT16_MAX || summary->sample_size % 8) )
1485 audio->type = QT_CODEC_TYPE_LPCM_AUDIO;
1486 audio->version = 2;
1488 else if( lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_LPCM_AUDIO ) )
1489 audio->version = 2;
1490 else if( summary->sample_size > 16
1491 || (!lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_RAW_AUDIO )
1492 && !lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_TWOS_AUDIO )
1493 && !lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_NONE_AUDIO )
1494 && !lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_NOT_SPECIFIED )) )
1495 audio->version = 1;
1496 /* Set up constBytesPerAudioPacket field.
1497 * We use constBytesPerAudioPacket as the actual size of LPCM audio frame even when version is not 2. */
1498 audio->constBytesPerAudioPacket = (summary->sample_size * summary->channels) / 8;
1499 /* Set up other fields in this description by its version. */
1500 if( audio->version == 2 )
1502 audio->channelcount = 3;
1503 audio->samplesize = 16;
1504 audio->compression_ID = -2;
1505 audio->samplerate = 0x00010000;
1506 audio->sizeOfStructOnly = 72;
1507 audio->audioSampleRate = (union {double d; uint64_t i;}){summary->frequency}.i;
1508 audio->numAudioChannels = summary->channels;
1509 audio->always7F000000 = 0x7F000000;
1510 audio->constBitsPerChannel = summary->sample_size;
1511 audio->constLPCMFramesPerAudioPacket = 1;
1512 audio->formatSpecificFlags = lpcm->format_flags;
1513 if( lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_TWOS_AUDIO ) && summary->sample_size != 8 )
1514 audio->formatSpecificFlags |= QT_LPCM_FORMAT_FLAG_BIG_ENDIAN;
1515 if( lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT )
1516 audio->formatSpecificFlags &= ~QT_LPCM_FORMAT_FLAG_SIGNED_INTEGER;
1517 if( lpcm->format_flags & QT_LPCM_FORMAT_FLAG_PACKED )
1518 audio->formatSpecificFlags &= ~QT_LPCM_FORMAT_FLAG_ALIGNED_HIGH;
1520 else if( audio->version == 1 )
1522 audio->channelcount = summary->channels;
1523 audio->samplesize = 16;
1524 /* Audio formats other than 'raw ' and 'twos' are treated as compressed audio. */
1525 if( lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_RAW_AUDIO )
1526 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_TWOS_AUDIO ) )
1527 audio->compression_ID = QT_AUDIO_COMPRESSION_ID_NOT_COMPRESSED;
1528 else
1529 audio->compression_ID = QT_AUDIO_COMPRESSION_ID_FIXED_COMPRESSION;
1530 audio->samplerate = summary->frequency << 16;
1531 audio->samplesPerPacket = 1;
1532 audio->bytesPerPacket = summary->sample_size / 8;
1533 audio->bytesPerFrame = audio->bytesPerPacket * summary->channels; /* sample_size field in stsz box is NOT used. */
1534 audio->bytesPerSample = 1 + (summary->sample_size != 8);
1535 if( lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_FL32_AUDIO )
1536 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_FL64_AUDIO )
1537 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_IN24_AUDIO )
1538 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_IN32_AUDIO ) )
1540 isom_wave_t *wave;
1541 isom_frma_t *frma;
1542 isom_enda_t *enda;
1543 isom_terminator_t *terminator;
1544 if( (wave = isom_add_wave( audio ), LSMASH_IS_NON_EXISTING_BOX( wave ))
1545 || (frma = isom_add_frma( wave ), LSMASH_IS_NON_EXISTING_BOX( frma ))
1546 || (enda = isom_add_enda( wave ), LSMASH_IS_NON_EXISTING_BOX( enda ))
1547 || (terminator = isom_add_terminator( wave ), LSMASH_IS_NON_EXISTING_BOX( terminator )) )
1549 lsmash_list_remove_entry_tail( &audio->extensions );
1550 return LSMASH_ERR_NAMELESS;
1552 frma->data_format = sample_type.fourcc;
1553 enda->littleEndian = !(lpcm->format_flags & QT_LPCM_FORMAT_FLAG_BIG_ENDIAN);
1556 else /* audio->version == 0 */
1558 audio->channelcount = summary->channels;
1559 audio->samplesize = summary->sample_size;
1560 audio->compression_ID = QT_AUDIO_COMPRESSION_ID_NOT_COMPRESSED;
1561 audio->samplerate = summary->frequency << 16;
1563 return 0;
1566 static int isom_set_isom_dts_audio_description( isom_audio_entry_t *audio, lsmash_audio_summary_t *summary )
1568 audio->version = 0;
1569 audio->revision_level = 0;
1570 audio->vendor = 0;
1571 audio->channelcount = summary->channels;
1572 audio->samplesize = 16;
1573 audio->compression_ID = 0;
1574 audio->packet_size = 0;
1575 switch( summary->frequency )
1577 case 12000 : /* Invalid? (No reference in the spec) */
1578 case 24000 :
1579 case 48000 :
1580 case 96000 :
1581 case 192000 :
1582 case 384000 : /* Invalid? (No reference in the spec) */
1583 audio->samplerate = 48000 << 16;
1584 break;
1585 case 22050 :
1586 case 44100 :
1587 case 88200 :
1588 case 176400 :
1589 case 352800 : /* Invalid? (No reference in the spec) */
1590 audio->samplerate = 44100 << 16;
1591 break;
1592 case 8000 : /* Invalid? (No reference in the spec) */
1593 case 16000 :
1594 case 32000 :
1595 case 64000 :
1596 case 128000 :
1597 audio->samplerate = 32000 << 16;
1598 break;
1599 default :
1600 audio->samplerate = 0;
1601 break;
1603 return 0;
1606 static int isom_set_hint_summary( isom_hint_entry_t *hint, lsmash_hint_summary_t *summary )
1608 hint->hinttrackversion = summary->version;
1609 hint->highestcompatibleversion = summary->highestcompatibleversion;
1610 hint->maxpacketsize = summary->maxpacketsize;
1611 return 0;
1614 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 )
1616 lsmash_box_type_t box_type = LSMASH_BOX_TYPE_INITIALIZER;
1617 box_type.fourcc = fourcc;
1618 #define GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( codec_type, predefined_box_type ) \
1619 else if( (codec_type.user.fourcc == 0 \
1620 || lsmash_check_codec_type_identical( active_codec_type, codec_type )) \
1621 && box_type.fourcc == predefined_box_type.fourcc ) \
1622 box_type = predefined_box_type
1623 if( 0 );
1624 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_AC_3_AUDIO, ISOM_BOX_TYPE_DAC3 );
1625 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_EC_3_AUDIO, ISOM_BOX_TYPE_DEC3 );
1626 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_DTSC_AUDIO, ISOM_BOX_TYPE_DDTS );
1627 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_DTSE_AUDIO, ISOM_BOX_TYPE_DDTS );
1628 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_DTSH_AUDIO, ISOM_BOX_TYPE_DDTS );
1629 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_DTSL_AUDIO, ISOM_BOX_TYPE_DDTS );
1630 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_DTSX_AUDIO, ISOM_BOX_TYPE_DDTS );
1631 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_DTSEL_AUDIO, ISOM_BOX_TYPE_DDTS );
1632 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_DTSDL_AUDIO, ISOM_BOX_TYPE_DDTS );
1633 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_ALAC_AUDIO, ISOM_BOX_TYPE_ALAC );
1634 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_MP4A_AUDIO, ISOM_BOX_TYPE_ESDS );
1635 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( QT_CODEC_TYPE_ALAC_AUDIO, QT_BOX_TYPE_ALAC );
1636 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( QT_CODEC_TYPE_MP4A_AUDIO, QT_BOX_TYPE_ESDS );
1637 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( QT_CODEC_TYPE_FULLMP3_AUDIO, QT_CODEC_TYPE_MP3_AUDIO );
1638 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( QT_CODEC_TYPE_ADPCM2_AUDIO, QT_CODEC_TYPE_ADPCM2_AUDIO );
1639 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( QT_CODEC_TYPE_ADPCM17_AUDIO, QT_CODEC_TYPE_ADPCM17_AUDIO );
1640 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( QT_CODEC_TYPE_GSM49_AUDIO, QT_CODEC_TYPE_GSM49_AUDIO );
1641 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, QT_BOX_TYPE_CHAN );
1642 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, QT_BOX_TYPE_GLBL );
1643 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, QT_BOX_TYPE_WAVE );
1644 #undef GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE
1645 return box_type;
1648 typedef struct
1650 uint16_t wFormatTag;
1651 uint16_t nChannels;
1652 uint32_t nSamplesPerSec;
1653 uint32_t nAvgBytesPerSec;
1654 uint16_t nBlockAlign;
1655 uint16_t wBitsPerSample;
1656 uint16_t cbSize;
1657 } wave_format_ex_t;
1659 static lsmash_bs_t *isom_create_waveform_audio_info
1661 wave_format_ex_t *wfx,
1662 lsmash_box_type_t type
1665 lsmash_bs_t *bs = lsmash_bs_create();
1666 if( !bs )
1667 return NULL;
1668 lsmash_bs_put_be32( bs, ISOM_BASEBOX_COMMON_SIZE + 18 + wfx->cbSize );
1669 lsmash_bs_put_be32( bs, type.fourcc );
1670 lsmash_bs_put_le16( bs, wfx->wFormatTag );
1671 lsmash_bs_put_le16( bs, wfx->nChannels );
1672 lsmash_bs_put_le32( bs, wfx->nSamplesPerSec );
1673 lsmash_bs_put_le32( bs, wfx->nAvgBytesPerSec );
1674 lsmash_bs_put_le16( bs, wfx->nBlockAlign );
1675 lsmash_bs_put_le16( bs, wfx->wBitsPerSample );
1676 lsmash_bs_put_le16( bs, wfx->cbSize );
1677 return bs;
1680 static int isom_setup_waveform_audio_info
1682 isom_wave_t *wave,
1683 isom_audio_entry_t *audio,
1684 lsmash_audio_summary_t *summary,
1685 uint32_t samples_per_packet,
1686 uint32_t bytes_per_frame,
1687 uint32_t sample_size
1690 wave_format_ex_t wfx;
1691 wfx.wFormatTag = 0x0000; /* WAVE_FORMAT_UNKNOWN */
1692 wfx.nChannels = summary->channels;
1693 wfx.nSamplesPerSec = summary->frequency;
1694 wfx.nAvgBytesPerSec = 0;
1695 wfx.nBlockAlign = bytes_per_frame;
1696 wfx.wBitsPerSample = sample_size;
1697 wfx.cbSize = 0;
1698 lsmash_bs_t *bs = NULL;
1699 if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ADPCM2_AUDIO ) )
1701 /* ADPCMWAVEFORMAT */
1702 wfx.wFormatTag = 0x0002; /* WAVE_FORMAT_ADPCM */
1703 wfx.cbSize = 32;
1704 bs = isom_create_waveform_audio_info( &wfx, audio->type );
1705 if( !bs )
1706 return LSMASH_ERR_MEMORY_ALLOC;
1707 uint16_t wSamplesPerBlock = samples_per_packet; /* nBlockAlign * 2 / nChannels - 12 */
1708 uint16_t wNumCoef = 7; /* Microsoft ADPCM uses just 7 coefficients. */
1709 static const struct
1711 int16_t iCoef1;
1712 int16_t iCoef2;
1713 } aCoef[7] = { { 256, 0 }, { 512, -256 }, { 0,0 }, { 192,64 }, { 240,0 }, { 460, -208 }, { 392,-232 } };
1714 lsmash_bs_put_le16( bs, wSamplesPerBlock );
1715 lsmash_bs_put_le16( bs, wNumCoef );
1716 for( int i = 0; i < 7; i++ )
1718 lsmash_bs_put_le16( bs, aCoef[i].iCoef1 );
1719 lsmash_bs_put_le16( bs, aCoef[i].iCoef2 );
1722 else if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ADPCM17_AUDIO ) )
1724 /* IMAADPCMWAVEFORMAT */
1725 wfx.wFormatTag = 0x0011; /* WAVE_FORMAT_DVI_ADPCM / WAVE_FORMAT_IMA_ADPCM */
1726 wfx.cbSize = 2;
1727 bs = isom_create_waveform_audio_info( &wfx, audio->type );
1728 if( !bs )
1729 return LSMASH_ERR_MEMORY_ALLOC;
1730 uint16_t wSamplesPerBlock = samples_per_packet;
1731 lsmash_bs_put_le16( bs, wSamplesPerBlock );
1733 else if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_GSM49_AUDIO ) )
1735 /* GSM610WAVEFORMAT */
1736 wfx.wFormatTag = 0x0031; /* WAVE_FORMAT_GSM610 */
1737 wfx.cbSize = 2;
1738 bs = isom_create_waveform_audio_info( &wfx, audio->type );
1739 if( !bs )
1740 return LSMASH_ERR_MEMORY_ALLOC;
1741 uint16_t wSamplesPerBlock = samples_per_packet;
1742 lsmash_bs_put_le16( bs, wSamplesPerBlock );
1744 else if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_FULLMP3_AUDIO )
1745 || lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_MP3_AUDIO ) )
1747 /* MPEGLAYER3WAVEFORMAT */
1748 wfx.wFormatTag = 0x0055; /* WAVE_FORMAT_MPEGLAYER3 */
1749 wfx.nBlockAlign = 1; /* ? */
1750 wfx.wBitsPerSample = 0; /* undefined */
1751 wfx.cbSize = 12;
1752 bs = isom_create_waveform_audio_info( &wfx, audio->type );
1753 if( !bs )
1754 return LSMASH_ERR_MEMORY_ALLOC;
1755 uint16_t wID = 1; /* MPEGLAYER3_ID_MPEG */
1756 uint32_t fdwFlags = 0; /* We don't know whether the stream is padded or not here. */
1757 uint16_t nBlockSize = 0; /* (144 * (bitrate / nSamplesPerSec) + padding) * nFramesPerBlock */
1758 uint16_t nFramesPerBlock = 1; /* the number of audio frames per block */
1759 uint16_t nCodecDelay = 0; /* Encoder delay in samples is unknown. */
1760 lsmash_bs_put_le16( bs, wID );
1761 lsmash_bs_put_le32( bs, fdwFlags );
1762 lsmash_bs_put_le16( bs, nBlockSize );
1763 lsmash_bs_put_le16( bs, nFramesPerBlock );
1764 lsmash_bs_put_le16( bs, nCodecDelay );
1766 if( !bs )
1768 assert( 0 );
1769 return LSMASH_ERR_NAMELESS;
1771 uint32_t wfx_size;
1772 uint8_t *wfx_data = lsmash_bs_export_data( bs, &wfx_size );
1773 lsmash_bs_cleanup( bs );
1774 if( !wfx_data )
1775 return LSMASH_ERR_NAMELESS;
1776 if( wfx_size != ISOM_BASEBOX_COMMON_SIZE + 18 + wfx.cbSize )
1778 lsmash_free( wfx_data );
1779 return LSMASH_ERR_NAMELESS;
1781 int err = isom_add_extension_binary( wave, audio->type, LSMASH_BOX_PRECEDENCE_HM, wfx_data, wfx_size );
1782 if( err < 0 )
1784 lsmash_free( wfx_data );
1785 return err;
1787 return 0;
1790 static int isom_set_qtff_sound_decompression_parameters
1792 isom_audio_entry_t *audio,
1793 lsmash_audio_summary_t *summary,
1794 lsmash_qt_audio_format_specific_flag *format_flags,
1795 uint32_t samples_per_packet,
1796 uint32_t bytes_per_frame,
1797 uint32_t sample_size
1800 /* A 'wave' extension itself shall be absent in the opaque CODEC specific info list.
1801 * So, create a 'wave' extension here and append it as an extension to the audio sample description. */
1802 isom_wave_t *wave = isom_add_wave( audio );
1803 if( LSMASH_IS_NON_EXISTING_BOX( wave ) )
1804 return LSMASH_ERR_NAMELESS;
1805 if( LSMASH_IS_BOX_ADDITION_FAILURE( isom_add_frma ( wave ) )
1806 || LSMASH_IS_BOX_ADDITION_FAILURE( isom_add_terminator( wave ) ) )
1808 lsmash_list_remove_entry_tail( &audio->extensions );
1809 return LSMASH_ERR_NAMELESS;
1811 wave->frma->data_format = audio->type.fourcc;
1812 /* Append extensions from the opaque CODEC specific info list to 'wave' extension. */
1813 int err;
1814 int waveform_audio_info_present = 0;
1815 int requires_waveform_audio_info = isom_is_waveform_audio( audio->type );
1816 for( lsmash_entry_t *entry = summary->opaque->list.head; entry; entry = entry->next )
1818 lsmash_codec_specific_t *specific = (lsmash_codec_specific_t *)entry->data;
1819 if( !specific )
1820 return LSMASH_ERR_NAMELESS;
1821 if( specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN
1822 && specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
1823 continue; /* LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN + LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED is not supported. */
1824 switch( specific->type )
1826 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_COMMON :
1827 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER :
1828 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS :
1829 continue; /* These cannot be an extension for 'wave' extension. */
1830 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT :
1831 /* (Legacy?) ALAC might have an Audio Channel Layout Box inside 'wave' extension. */
1832 #if 1
1833 continue;
1834 #else
1835 if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ALAC_AUDIO ) )
1836 continue;
1837 if( (err = isom_append_channel_layout_extension( specific, wave, summary->channels )) < 0 )
1838 return err;
1839 break;
1840 #endif
1841 default :
1843 assert( specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED
1844 || specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_DECOMPRESSION_PARAMETERS );
1845 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
1846 if( !cs )
1847 return LSMASH_ERR_NAMELESS;
1848 if( cs->size < ISOM_BASEBOX_COMMON_SIZE )
1850 lsmash_destroy_codec_specific_data( cs );
1851 continue;
1853 uint8_t *box_data = cs->data.unstructured;
1854 uint64_t box_size = cs->size;
1855 lsmash_compact_box_type_t fourcc = LSMASH_4CC( box_data[4], box_data[5], box_data[6], box_data[7] );
1856 if( audio->version == 2 && fourcc == QT_BOX_TYPE_ENDA.fourcc )
1858 /* Don't append a 'enda' extension if version == 2.
1859 * Endianness is indicated in QuickTime audio format specific flags. */
1860 if( box_size >= ISOM_BASEBOX_COMMON_SIZE + 2 )
1862 /* Override endianness indicated in format specific flags. */
1863 if( box_data[9] == 1 )
1864 *format_flags &= ~QT_AUDIO_FORMAT_FLAG_BIG_ENDIAN;
1865 else
1866 *format_flags |= QT_AUDIO_FORMAT_FLAG_BIG_ENDIAN;
1868 lsmash_destroy_codec_specific_data( cs );
1869 continue;
1871 lsmash_box_type_t box_type = isom_guess_audio_codec_specific_box_type( audio->type, fourcc );
1872 if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_WAVE ) )
1874 /* It is insane to appened a 'wave' extension to a 'wave' extension. */
1875 lsmash_destroy_codec_specific_data( cs );
1876 continue;
1878 box_type = lsmash_form_qtff_box_type( box_type.fourcc );
1879 /* Determine 'precedence'. */
1880 uint64_t precedence;
1881 if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_FRMA ) )
1882 precedence = LSMASH_BOX_PRECEDENCE_QTFF_FRMA;
1883 else if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_ESDS ) )
1884 precedence = LSMASH_BOX_PRECEDENCE_QTFF_ESDS;
1885 else if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_ENDA ) )
1886 precedence = LSMASH_BOX_PRECEDENCE_QTFF_ENDA;
1887 else if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_MP4A ) )
1888 precedence = LSMASH_BOX_PRECEDENCE_QTFF_MP4A;
1889 else if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_TERMINATOR ) )
1890 precedence = LSMASH_BOX_PRECEDENCE_QTFF_TERMINATOR;
1891 else
1892 precedence = LSMASH_BOX_PRECEDENCE_HM;
1893 /* Append the extension. */
1894 err = isom_add_extension_binary( wave, box_type, precedence, cs->data.unstructured, cs->size );
1895 cs->data.unstructured = NULL; /* Avoid freeing the binary data of the extension. */
1896 lsmash_destroy_codec_specific_data( cs );
1897 if( err < 0 )
1898 return err;
1899 if( isom_is_waveform_audio( box_type ) )
1900 waveform_audio_info_present = 1;
1901 break;
1905 if( requires_waveform_audio_info && !waveform_audio_info_present
1906 && (err = isom_setup_waveform_audio_info( wave, audio, summary, samples_per_packet, bytes_per_frame, sample_size )) < 0 )
1907 return err;
1908 return 0;
1911 static int isom_set_qtff_template_audio_description( isom_audio_entry_t *audio, lsmash_audio_summary_t *summary )
1913 audio->manager |= LSMASH_QTFF_BASE;
1914 audio->type = lsmash_form_qtff_box_type( audio->type.fourcc );
1915 audio->version = (summary->channels > 2 || summary->frequency > UINT16_MAX) ? 2 : 1;
1916 /* Try to get QuickTime audio format specific flags. */
1917 lsmash_qt_audio_format_specific_flag format_flags = QT_AUDIO_FORMAT_FLAG_BIG_ENDIAN;
1918 for( lsmash_entry_t *entry = summary->opaque->list.head; entry; entry = entry->next )
1920 lsmash_codec_specific_t *specific = (lsmash_codec_specific_t *)entry->data;
1921 if( !specific
1922 || !specific->data.structured )
1923 continue;
1924 if( specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS
1925 && specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
1927 /* A format specific flags is found.
1928 * Force audio sample description version == 2. */
1929 format_flags = ((lsmash_qt_audio_format_specific_flags_t *)specific->data.structured)->format_flags;
1930 audio->version = 2;
1931 break;
1934 uint32_t samples_per_packet;
1935 uint32_t bytes_per_frame;
1936 uint32_t sample_size;
1937 if( !((summary->samples_in_frame == 0 || summary->bytes_per_frame == 0 || summary->sample_size == 0)
1938 && isom_get_implicit_qt_fixed_comp_audio_sample_quants( audio, &samples_per_packet, &bytes_per_frame, &sample_size )) )
1940 samples_per_packet = summary->samples_in_frame;
1941 bytes_per_frame = summary->bytes_per_frame;
1942 sample_size = summary->sample_size;
1944 if( !lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_MAC3_AUDIO )
1945 && !lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_MAC6_AUDIO )
1946 && !lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_AGSM_AUDIO )
1947 && !lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ALAW_AUDIO )
1948 && !lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ULAW_AUDIO ) )
1950 int err = isom_set_qtff_sound_decompression_parameters( audio, summary, &format_flags,
1951 samples_per_packet, bytes_per_frame, sample_size );
1952 if( err < 0 )
1953 return err;
1955 /* Set up common audio description fields. */
1956 audio->samplesize = 16;
1957 audio->packet_size = 0;
1958 if( audio->version == 2 )
1960 audio->channelcount = 3;
1961 audio->compression_ID = QT_AUDIO_COMPRESSION_ID_VARIABLE_COMPRESSION;
1962 audio->samplerate = 0x00010000;
1963 audio->sizeOfStructOnly = 72;
1964 audio->audioSampleRate = (union {double d; uint64_t i;}){summary->frequency}.i;
1965 audio->numAudioChannels = summary->channels;
1966 audio->always7F000000 = 0x7F000000;
1967 audio->constBitsPerChannel = 0;
1968 audio->constBytesPerAudioPacket = bytes_per_frame;
1969 audio->constLPCMFramesPerAudioPacket = samples_per_packet;
1970 if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ALAC_AUDIO ) )
1972 switch( sample_size )
1974 case 16 :
1975 audio->formatSpecificFlags = QT_ALAC_FORMAT_FLAG_16BIT_SOURCE_DATA;
1976 break;
1977 case 20 :
1978 audio->formatSpecificFlags = QT_ALAC_FORMAT_FLAG_20BIT_SOURCE_DATA;
1979 break;
1980 case 24 :
1981 audio->formatSpecificFlags = QT_ALAC_FORMAT_FLAG_24BIT_SOURCE_DATA;
1982 break;
1983 case 32 :
1984 audio->formatSpecificFlags = QT_ALAC_FORMAT_FLAG_32BIT_SOURCE_DATA;
1985 break;
1986 default :
1987 break;
1990 else
1992 if( format_flags & QT_AUDIO_FORMAT_FLAG_FLOAT )
1993 format_flags &= ~QT_AUDIO_FORMAT_FLAG_SIGNED_INTEGER;
1994 if( format_flags & QT_AUDIO_FORMAT_FLAG_PACKED )
1995 format_flags &= ~QT_AUDIO_FORMAT_FLAG_ALIGNED_HIGH;
1996 audio->formatSpecificFlags = format_flags;
1999 else /* if( audio->version == 1 ) */
2001 audio->channelcount = LSMASH_MIN( summary->channels, 2 );
2002 audio->compression_ID = QT_AUDIO_COMPRESSION_ID_FIXED_COMPRESSION;
2003 audio->samplerate = summary->frequency << 16;
2004 audio->samplesPerPacket = samples_per_packet;
2005 audio->bytesPerPacket = bytes_per_frame / summary->channels;
2006 audio->bytesPerFrame = bytes_per_frame; /* sample_size field in stsz box is NOT used. */
2007 audio->bytesPerSample = 1 + (sample_size != 8);
2009 return 0;
2012 static void isom_set_samplerate_division_of_media_timescale( isom_audio_entry_t *audio, int strict )
2014 isom_mdia_t *mdia = (isom_mdia_t *)audio->parent->parent->parent->parent; /* audio_entry->stsd->stbl->minf->mdia */
2015 if( lsmash_check_box_type_identical( mdia->type, ISOM_BOX_TYPE_MDIA )
2016 && LSMASH_IS_EXISTING_BOX( mdia->mdhd ) )
2018 /* Make an effort to match the timescale with samplerate, or be an integer multiple of it. */
2019 uint32_t orig_timescale = ((isom_mdia_t *)audio->parent->parent->parent->parent)->mdhd->timescale;
2020 uint32_t timescale = orig_timescale;
2021 uint32_t i = 2;
2022 while( timescale > UINT16_MAX && timescale > 1 )
2024 if( timescale % i == 0 )
2025 timescale /= i;
2026 else
2027 i += i > 2 ? 2 : 1;
2029 if( timescale != orig_timescale && strict )
2030 lsmash_log( NULL, LSMASH_LOG_WARNING, "samplerate does not match the media timescale.\n" );
2031 if( timescale <= UINT16_MAX && timescale > 1 )
2033 audio->samplerate = timescale << 16;
2034 return;
2037 audio->samplerate = 0;
2040 static int isom_set_isom_template_audio_description( isom_audio_entry_t *audio, lsmash_audio_summary_t *summary )
2042 audio->version = 0; /* reserved */
2043 audio->revision_level = 0; /* reserved */
2044 audio->vendor = 0; /* reserved */
2045 audio->channelcount = 2; /* template */
2046 audio->samplesize = 16; /* template */
2047 audio->compression_ID = 0; /* pre_defined */
2048 audio->packet_size = 0; /* reserved */
2049 /* template : default output audio sampling rate at playback */
2050 if( summary->frequency <= UINT16_MAX )
2051 audio->samplerate = summary->frequency << 16;
2052 else
2053 isom_set_samplerate_division_of_media_timescale( audio, 0 );
2054 return 0;
2057 static int isom_set_isom_amr_audio_description( isom_audio_entry_t *audio, int wb )
2059 /* For AMR-NB and AMR-WB stream, these fields are not meaningful. */
2060 audio->version = 0; /* always 0 */
2061 audio->revision_level = 0; /* always 0 */
2062 audio->vendor = 0; /* always 0 */
2063 audio->channelcount = 2; /* always 2 although the actual number of channels is always 1 */
2064 audio->samplesize = 16; /* always 16 */
2065 audio->compression_ID = 0; /* always 0 */
2066 audio->packet_size = 0; /* always 0 */
2067 /* Set samplerate by trying to copy from Media Header Box of this media though the
2068 * actual samplerate is 8000 Hz for AMR-NB and 16000 Hz for AMR-WB.
2069 * 3GPP and 3GPP2 has no restriction for media timescale. Therefore, users should
2070 * set suitable media timescale by themselves within the bounds of common sense. */
2071 isom_set_samplerate_division_of_media_timescale( audio, 1 );
2072 if( audio->samplerate == 0 )
2073 /* Set hard-coded but correct samplerate in the CODEC level. */
2074 audio->samplerate = wb ? 8000 : 16000;
2075 return 0;
2078 static int isom_set_isom_alac_audio_description( isom_audio_entry_t *audio, lsmash_audio_summary_t *summary )
2080 return isom_set_isom_template_audio_description( audio, summary );
2083 static int isom_set_qtff_alac_audio_description( isom_audio_entry_t *audio, lsmash_audio_summary_t *summary )
2085 return isom_set_qtff_template_audio_description( audio, summary );
2088 static int isom_set_isom_eac3_audio_description( isom_audio_entry_t *audio, lsmash_audio_summary_t *summary )
2090 return isom_set_isom_template_audio_description( audio, summary );
2093 static int isom_setup_audio_description( isom_stsd_t *stsd, lsmash_audio_summary_t *summary )
2095 if( LSMASH_IS_NON_EXISTING_BOX( stsd->file ) || !summary )
2096 return LSMASH_ERR_NAMELESS;
2097 int err = isom_check_valid_summary( (lsmash_summary_t *)summary );
2098 if( err < 0 )
2099 return err;
2100 isom_audio_entry_t *audio = isom_add_audio_description( stsd, summary->sample_type );
2101 if( LSMASH_IS_NON_EXISTING_BOX( audio ) )
2102 return LSMASH_ERR_NAMELESS;
2103 audio->data_reference_index = summary->data_ref_index;
2104 lsmash_file_t *file = stsd->file;
2105 lsmash_codec_type_t audio_type = audio->type;
2106 if( lsmash_check_codec_type_identical( audio_type, ISOM_CODEC_TYPE_MP4A_AUDIO )
2107 || lsmash_check_codec_type_identical( audio_type, QT_CODEC_TYPE_MP4A_AUDIO ) )
2109 if( (LSMASH_IS_EXISTING_BOX( file->ftyp ) && file->ftyp->major_brand == ISOM_BRAND_TYPE_QT)
2110 || (LSMASH_IS_NON_EXISTING_BOX( file->ftyp )
2111 && (file->qt_compatible || (LSMASH_IS_EXISTING_BOX( file->moov ) && LSMASH_IS_NON_EXISTING_BOX( file->moov->iods )))) )
2112 err = isom_set_qtff_mp4a_description( audio, summary );
2113 else
2114 err = isom_set_isom_mp4a_description( audio, summary );
2116 else if( isom_is_lpcm_audio( audio ) )
2117 err = isom_set_qtff_lpcm_description( audio, summary );
2118 else if( file->isom_compatible && lsmash_check_codec_type_identical( audio_type, ISOM_CODEC_TYPE_ALAC_AUDIO ) )
2119 err = isom_set_isom_alac_audio_description( audio, summary );
2120 else if( file->qt_compatible && lsmash_check_codec_type_identical( audio_type, QT_CODEC_TYPE_ALAC_AUDIO ) )
2121 err = isom_set_qtff_alac_audio_description( audio, summary );
2122 else if( audio->type.fourcc == ISOM_CODEC_TYPE_ALAC_AUDIO.fourcc )
2124 if( file->qt_compatible )
2125 err = isom_set_qtff_alac_audio_description( audio, summary );
2126 else
2127 err = isom_set_isom_alac_audio_description( audio, summary );
2129 else if( isom_is_dts_audio( audio_type ) )
2130 err = isom_set_isom_dts_audio_description( audio, summary );
2131 else if( lsmash_check_codec_type_identical( audio_type, ISOM_CODEC_TYPE_EC_3_AUDIO ) )
2132 err = isom_set_isom_eac3_audio_description( audio, summary );
2133 else if( file->qt_compatible )
2134 err = isom_set_qtff_template_audio_description( audio, summary );
2135 else if( lsmash_check_codec_type_identical( audio_type, ISOM_CODEC_TYPE_SAMR_AUDIO ) )
2136 err = isom_set_isom_amr_audio_description( audio, 0 );
2137 else if( lsmash_check_codec_type_identical( audio_type, ISOM_CODEC_TYPE_SAWB_AUDIO ) )
2138 err = isom_set_isom_amr_audio_description( audio, 1 );
2139 else
2140 err = isom_set_isom_template_audio_description( audio, summary );
2141 if( err < 0 )
2142 goto fail;
2143 err = LSMASH_ERR_NAMELESS;
2144 /* Don't use audio_type since audio->type might have changed. */
2145 for( lsmash_entry_t *entry = summary->opaque->list.head; entry; entry = entry->next )
2147 lsmash_codec_specific_t *specific = (lsmash_codec_specific_t *)entry->data;
2148 if( !specific )
2149 goto fail;
2150 if( specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN
2151 && specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
2152 continue; /* LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN + LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED is not supported. */
2153 switch( specific->type )
2155 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_COMMON :
2157 if( specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED )
2158 continue; /* Ignore since not fatal. */
2159 lsmash_qt_audio_common_t *data = (lsmash_qt_audio_common_t *)specific->data.structured;
2160 audio->revision_level = data->revision_level;
2161 audio->vendor = data->vendor;
2162 if( audio->version == 1
2163 && !isom_is_lpcm_audio( audio )
2164 && data->compression_ID != QT_AUDIO_COMPRESSION_ID_NOT_COMPRESSED )
2166 /* Compressed audio must not be set to QT_AUDIO_COMPRESSION_ID_NOT_COMPRESSED. */
2167 audio->compression_ID = data->compression_ID;
2168 if( audio->compression_ID == QT_AUDIO_COMPRESSION_ID_VARIABLE_COMPRESSION )
2170 /* For variable compression, bytesPerPacket and bytesPerFrame are reserved and should be set to 0. */
2171 audio->bytesPerPacket = 0;
2172 audio->bytesPerFrame = 0;
2175 break;
2177 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT :
2179 if( !file->qt_compatible
2180 && !lsmash_check_codec_type_identical( audio->type, ISOM_CODEC_TYPE_ALAC_AUDIO )
2181 && !lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ALAC_AUDIO ) )
2182 continue;
2183 if( (err = isom_append_channel_layout_extension( specific, audio, summary->channels )) < 0 )
2184 goto fail;
2185 break;
2187 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER :
2189 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2190 if( !cs )
2191 goto fail;
2192 lsmash_codec_global_header_t *data = (lsmash_codec_global_header_t *)cs->data.structured;
2193 isom_glbl_t *glbl = isom_add_glbl( audio );
2194 if( LSMASH_IS_NON_EXISTING_BOX( glbl ) )
2196 lsmash_destroy_codec_specific_data( cs );
2197 goto fail;
2199 glbl->header_size = data->header_size;
2200 glbl->header_data = lsmash_memdup( data->header_data, data->header_size );
2201 lsmash_destroy_codec_specific_data( cs );
2202 if( !glbl->header_data )
2204 isom_remove_box_by_itself( glbl );
2205 err = LSMASH_ERR_MEMORY_ALLOC;
2206 goto fail;
2208 break;
2210 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS :
2211 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_DECOMPRESSION_PARAMETERS :
2212 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG :
2213 break; /* shall be set up already */
2214 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_ALAC :
2215 if( file->qt_compatible )
2216 continue; /* shall be set up already */
2217 default :
2219 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
2220 if( !cs )
2221 goto fail;
2222 if( cs->size < ISOM_BASEBOX_COMMON_SIZE )
2224 lsmash_destroy_codec_specific_data( cs );
2225 continue;
2227 uint8_t *box_data = cs->data.unstructured;
2228 lsmash_compact_box_type_t fourcc = LSMASH_4CC( box_data[4], box_data[5], box_data[6], box_data[7] );
2229 lsmash_box_type_t box_type = isom_guess_audio_codec_specific_box_type( audio->type, fourcc );
2230 if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_WAVE ) )
2232 /* CODEC specific info shall be already inside 'wave' extension. */
2233 lsmash_destroy_codec_specific_data( cs );
2234 continue;
2236 /* Append the extension. */
2237 err = isom_add_extension_binary( audio, box_type, LSMASH_BOX_PRECEDENCE_HM, cs->data.unstructured, cs->size );
2238 cs->data.unstructured = NULL; /* Avoid freeing the binary data of the extension. */
2239 lsmash_destroy_codec_specific_data( cs );
2240 if( err < 0 )
2241 goto fail;
2242 break;
2246 if( audio->version == 0 )
2247 audio->compression_ID = QT_AUDIO_COMPRESSION_ID_NOT_COMPRESSED;
2248 else if( audio->version == 2 )
2249 audio->compression_ID = QT_AUDIO_COMPRESSION_ID_VARIABLE_COMPRESSION;
2250 return 0;
2251 fail:
2252 isom_remove_box_by_itself( audio );
2253 return err;
2256 static int isom_setup_tx3g_description( isom_stsd_t *stsd, lsmash_summary_t *summary )
2258 isom_tx3g_entry_t *tx3g = isom_add_tx3g_description( stsd );
2259 if( LSMASH_IS_NON_EXISTING_BOX( tx3g ) )
2260 return LSMASH_ERR_NAMELESS;
2261 /* We create a dummy font record to make valid font_ID in the sample description.
2262 * The specification (3GPP TS 26.245) does not forbid the value 0 for the identifier,
2263 * but we set 1 to it as track_ID begins from 1. */
2264 tx3g->data_reference_index = summary->data_ref_index;
2265 tx3g->font_ID = 1; /* ID of the default font record */
2266 int err = LSMASH_ERR_MEMORY_ALLOC;
2267 isom_ftab_t *ftab = isom_add_ftab( tx3g );
2268 if( LSMASH_IS_NON_EXISTING_BOX( ftab ) )
2270 err = LSMASH_ERR_NAMELESS;
2271 goto fail;
2273 isom_font_record_t *font = lsmash_malloc( sizeof(isom_font_record_t) );
2274 if( !font )
2275 goto fail;
2276 if( lsmash_list_add_entry( ftab->list, font ) < 0 )
2278 lsmash_free( font );
2279 goto fail;
2281 const char font_names[] = "Serif,Sans-serif,Monospace";
2282 font->font_ID = 1;
2283 font->font_name_length = sizeof(font_names);
2284 font->font_name = lsmash_memdup( font_names, sizeof(font_names) );
2285 if( !font->font_name )
2286 goto fail;
2287 return 0;
2288 fail:
2289 isom_remove_box_by_itself( tx3g );
2290 return err;
2293 static int isom_setup_qt_text_description( isom_stsd_t *stsd, lsmash_summary_t *summary )
2295 isom_qt_text_entry_t *text = isom_add_qt_text_description( stsd );
2296 if( LSMASH_IS_NON_EXISTING_BOX( text ) )
2297 return LSMASH_ERR_NAMELESS;
2298 text->data_reference_index = summary->data_ref_index;
2299 return 0;
2302 static int isom_setup_text_description( isom_stsd_t *stsd, lsmash_summary_t *summary )
2304 lsmash_codec_type_t sample_type = summary->sample_type;
2305 if( lsmash_check_box_type_identical( sample_type, ISOM_CODEC_TYPE_TX3G_TEXT ) )
2306 return isom_setup_tx3g_description( stsd, summary );
2307 else if( lsmash_check_box_type_identical( sample_type, QT_CODEC_TYPE_TEXT_TEXT ) )
2308 return isom_setup_qt_text_description( stsd, summary );
2309 else
2310 return LSMASH_ERR_NAMELESS;
2313 int isom_setup_hint_description( isom_stsd_t *stsd, lsmash_hint_summary_t *summary )
2315 lsmash_codec_type_t sample_type = summary->sample_type;
2316 if( LSMASH_IS_NON_EXISTING_BOX( stsd->file ) || !summary )
2317 return LSMASH_ERR_NAMELESS;
2318 int err = isom_check_valid_summary( (lsmash_summary_t *)summary );
2319 if( err < 0 )
2320 goto fail;
2321 isom_hint_entry_t *hint = isom_add_hint_description( stsd, sample_type );
2322 if( LSMASH_IS_NON_EXISTING_BOX( hint ) )
2323 return LSMASH_ERR_NAMELESS;
2324 hint->data_reference_index = summary->data_ref_index;
2325 /* configure the sample description */
2326 lsmash_codec_type_t hint_type = hint->type;
2327 if( lsmash_check_codec_type_identical(hint_type, ISOM_CODEC_TYPE_RRTP_HINT ) )
2329 /* go through list of codec specific datas associated with this summary */
2330 for( lsmash_entry_t *entry = summary->opaque->list.head; entry; entry = entry->next )
2332 lsmash_codec_specific_t *specific = (lsmash_codec_specific_t *)entry->data;
2333 if( !specific )
2335 err = LSMASH_ERR_NAMELESS;
2336 goto fail;
2338 if( specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_RTP_HINT_COMMON )
2340 lsmash_isom_rtp_reception_hint_t* rtp_param;
2341 rtp_param = (lsmash_isom_rtp_reception_hint_t *)specific->data.structured;
2342 if( rtp_param->timescale == 0 )
2343 return LSMASH_ERR_INVALID_DATA;
2344 err = isom_set_hint_summary( hint, summary );
2345 if( err < 0 )
2346 goto fail;
2347 isom_tims_t *tims = isom_add_tims( hint );
2348 isom_tsro_t *tsro = isom_add_tsro( hint );
2349 isom_tssy_t *tssy = isom_add_tssy( hint );
2350 if( LSMASH_IS_NON_EXISTING_BOX( tims )
2351 || LSMASH_IS_NON_EXISTING_BOX( tsro )
2352 || LSMASH_IS_NON_EXISTING_BOX( tssy ) )
2353 return LSMASH_ERR_NAMELESS;
2354 tims->timescale = rtp_param->timescale;
2355 tsro->offset = rtp_param->time_offset;
2356 tssy->reserved = rtp_param->reserved_timestamp_sync >> 2;
2357 tssy->timestamp_sync = rtp_param->reserved_timestamp_sync & 0x03;
2361 else
2362 return LSMASH_ERR_PATCH_WELCOME;
2363 return 0;
2364 fail:
2365 return err;
2368 int isom_setup_sample_description( isom_stsd_t *stsd, lsmash_media_type media_type, lsmash_summary_t *summary )
2370 if( media_type == ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK )
2371 return isom_setup_visual_description( stsd, (lsmash_video_summary_t *)summary );
2372 else if( media_type == ISOM_MEDIA_HANDLER_TYPE_AUDIO_TRACK )
2373 return isom_setup_audio_description( stsd, (lsmash_audio_summary_t *)summary );
2374 else if( media_type == ISOM_MEDIA_HANDLER_TYPE_TEXT_TRACK )
2375 return isom_setup_text_description( stsd, (lsmash_summary_t *)summary );
2376 else if( media_type == ISOM_MEDIA_HANDLER_TYPE_HINT_TRACK )
2377 return isom_setup_hint_description( stsd, (lsmash_hint_summary_t *)summary );
2378 else
2379 return LSMASH_ERR_NAMELESS;
2382 static lsmash_codec_specific_data_type isom_get_codec_specific_data_type( lsmash_compact_box_type_t extension_fourcc )
2384 static struct codec_specific_data_type_table_tag
2386 lsmash_compact_box_type_t extension_fourcc;
2387 lsmash_codec_specific_data_type data_type;
2388 } codec_specific_data_type_table[32] = { { 0, LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN } };
2389 if( codec_specific_data_type_table[0].data_type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN )
2391 int i = 0;
2392 #define ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( extension_type, data_type ) \
2393 codec_specific_data_type_table[i++] = (struct codec_specific_data_type_table_tag){ extension_type.fourcc, data_type }
2394 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_AVCC, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264 );
2395 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_HVCC, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_HEVC );
2396 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_DVC1, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_VC_1 );
2397 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_DAC3, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_AC_3 );
2398 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_DEC3, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_EC_3 );
2399 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_DDTS, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS );
2400 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_ALAC, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_ALAC );
2401 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_ESDS, LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG );
2402 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_STSL, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_SAMPLE_SCALE );
2403 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_BTRT, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264_BITRATE );
2404 //ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_ALAC, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_ALAC );
2405 //ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_ESDS, LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG );
2406 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_FIEL, LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_FIELD_INFO );
2407 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_CSPC, LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_PIXEL_FORMAT );
2408 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_SGBT, LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_SIGNIFICANT_BITS );
2409 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_GAMA, LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_GAMMA_LEVEL );
2410 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_CLLI, LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_CONTENT_LIGHT_LEVEL_INFO );
2411 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_MDCV, LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_MASTERING_DISPLAY_COLOR_VOLUME );
2412 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_CHAN, LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT );
2413 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_GLBL, LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER );
2414 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( LSMASH_BOX_TYPE_UNSPECIFIED, LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN );
2415 #undef ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT
2417 lsmash_codec_specific_data_type data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN;
2418 for( int i = 0; codec_specific_data_type_table[i].data_type != LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN; i++ )
2419 if( extension_fourcc == codec_specific_data_type_table[i].extension_fourcc )
2421 data_type = codec_specific_data_type_table[i].data_type;
2422 break;
2424 return data_type;
2427 lsmash_summary_t *isom_create_video_summary_from_description( isom_sample_entry_t *sample_entry )
2429 if( LSMASH_IS_NON_EXISTING_BOX( sample_entry ) )
2430 return NULL;
2431 isom_visual_entry_t *visual = (isom_visual_entry_t *)sample_entry;
2432 lsmash_video_summary_t *summary = (lsmash_video_summary_t *)lsmash_create_summary( LSMASH_SUMMARY_TYPE_VIDEO );
2433 if( !summary )
2434 return NULL;
2435 summary->sample_type = visual->type;
2436 summary->data_ref_index = visual->data_reference_index;
2437 summary->width = visual->width;
2438 summary->height = visual->height;
2439 summary->depth = visual->depth;
2440 memcpy( summary->compressorname, visual->compressorname, 32 );
2441 summary->compressorname[32] = '\0';
2442 if( isom_is_qt_video( summary->sample_type ) )
2444 lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_COMMON,
2445 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2446 if( !specific )
2447 goto fail;
2448 lsmash_qt_video_common_t *data = (lsmash_qt_video_common_t *)specific->data.structured;
2449 data->revision_level = visual->revision_level;
2450 data->vendor = visual->vendor;
2451 data->temporalQuality = visual->temporalQuality;
2452 data->spatialQuality = visual->spatialQuality;
2453 data->horizontal_resolution = visual->horizresolution;
2454 data->vertical_resolution = visual->vertresolution;
2455 data->dataSize = visual->dataSize;
2456 data->frame_count = visual->frame_count;
2457 data->color_table_ID = visual->color_table_ID;
2458 if( visual->color_table_ID == 0 )
2460 isom_qt_color_table_t *src_ct = &visual->color_table;
2461 if( !src_ct->array )
2463 lsmash_destroy_codec_specific_data( specific );
2464 goto fail;
2466 uint16_t element_count = LSMASH_MIN( src_ct->size + 1, 256 );
2467 lsmash_qt_color_table_t *dst_ct = &data->color_table;
2468 dst_ct->seed = src_ct->seed;
2469 dst_ct->flags = src_ct->flags;
2470 dst_ct->size = src_ct->size;
2471 for( uint16_t i = 0; i < element_count; i++ )
2473 dst_ct->array[i].unused = src_ct->array[i].value;
2474 dst_ct->array[i].r = src_ct->array[i].r;
2475 dst_ct->array[i].g = src_ct->array[i].g;
2476 dst_ct->array[i].b = src_ct->array[i].b;
2479 if( lsmash_list_add_entry( &summary->opaque->list, specific ) < 0 )
2481 lsmash_destroy_codec_specific_data( specific );
2482 goto fail;
2485 for( lsmash_entry_t *entry = visual->extensions.head; entry; entry = entry->next )
2487 isom_box_t *box = (isom_box_t *)entry->data;
2488 if( LSMASH_IS_NON_EXISTING_BOX( box ) )
2489 continue;
2490 if( !(box->manager & LSMASH_BINARY_CODED_BOX) )
2492 lsmash_codec_specific_t *specific = NULL;
2493 if( lsmash_check_box_type_identical( box->type, ISOM_BOX_TYPE_CLAP ) )
2495 isom_clap_t *clap = (isom_clap_t *)box;
2496 summary->clap.width.n = clap->cleanApertureWidthN;
2497 summary->clap.width.d = clap->cleanApertureWidthD;
2498 summary->clap.height.n = clap->cleanApertureHeightN;
2499 summary->clap.height.d = clap->cleanApertureHeightD;
2500 summary->clap.horizontal_offset.n = clap->horizOffN;
2501 summary->clap.horizontal_offset.d = clap->horizOffD;
2502 summary->clap.vertical_offset.n = clap->vertOffN;
2503 summary->clap.vertical_offset.d = clap->vertOffD;
2504 continue;
2506 else if( lsmash_check_box_type_identical( box->type, ISOM_BOX_TYPE_PASP ) )
2508 isom_pasp_t *pasp = (isom_pasp_t *)box;
2509 summary->par_h = pasp->hSpacing;
2510 summary->par_v = pasp->vSpacing;
2511 continue;
2513 else if( lsmash_check_box_type_identical( box->type, ISOM_BOX_TYPE_COLR )
2514 || lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_COLR ) )
2516 isom_colr_t *colr = (isom_colr_t *)box;
2517 summary->color.primaries_index = colr->primaries_index;
2518 summary->color.transfer_index = colr->transfer_function_index;
2519 summary->color.matrix_index = colr->matrix_index;
2520 summary->color.full_range = colr->full_range_flag;
2521 continue;
2523 else if( lsmash_check_box_type_identical( box->type, ISOM_BOX_TYPE_STSL ) )
2525 specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_SAMPLE_SCALE,
2526 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2527 if( !specific )
2528 goto fail;
2529 isom_stsl_t *stsl = (isom_stsl_t *)box;
2530 lsmash_isom_sample_scale_t *data = (lsmash_isom_sample_scale_t *)specific->data.structured;
2531 data->constraint_flag = stsl->constraint_flag;
2532 data->scale_method = stsl->scale_method;
2533 data->display_center_x = stsl->display_center_x;
2534 data->display_center_y = stsl->display_center_y;
2536 else if( lsmash_check_box_type_identical( box->type, ISOM_BOX_TYPE_BTRT ) )
2538 specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264_BITRATE,
2539 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2540 if( !specific )
2541 goto fail;
2542 isom_btrt_t *btrt = (isom_btrt_t *)box;
2543 lsmash_h264_bitrate_t *data = (lsmash_h264_bitrate_t *)specific->data.structured;
2544 data->bufferSizeDB = btrt->bufferSizeDB;
2545 data->maxBitrate = btrt->maxBitrate;
2546 data->avgBitrate = btrt->avgBitrate;
2548 else if( lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_FIEL ) )
2550 specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_FIELD_INFO,
2551 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2552 if( !specific )
2553 goto fail;
2554 isom_fiel_t *fiel = (isom_fiel_t *)box;
2555 lsmash_qt_field_info_t *data = (lsmash_qt_field_info_t *)specific->data.structured;
2556 data->fields = fiel->fields;
2557 data->detail = fiel->detail;
2559 else if( lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_CSPC ) )
2561 specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_PIXEL_FORMAT,
2562 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2563 if( !specific )
2564 goto fail;
2565 isom_cspc_t *cspc = (isom_cspc_t *)box;
2566 lsmash_qt_pixel_format_t *data = (lsmash_qt_pixel_format_t *)specific->data.structured;
2567 data->pixel_format = cspc->pixel_format;
2569 else if( lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_SGBT ) )
2571 specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_SIGNIFICANT_BITS,
2572 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2573 if( !specific )
2574 goto fail;
2575 isom_sgbt_t *sgbt = (isom_sgbt_t *)box;
2576 lsmash_qt_significant_bits_t *data = (lsmash_qt_significant_bits_t *)specific->data.structured;
2577 data->significantBits = sgbt->significantBits;
2579 else if( lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_GLBL ) )
2581 specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER,
2582 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2583 if( !specific )
2584 goto fail;
2585 isom_glbl_t *glbl = (isom_glbl_t *)box;
2586 lsmash_codec_global_header_t *data = (lsmash_codec_global_header_t *)specific->data.structured;
2587 data->header_size = glbl->header_size;
2588 data->header_data = lsmash_memdup( glbl->header_data, glbl->header_size );
2589 if( !data->header_data )
2591 lsmash_destroy_codec_specific_data( specific );
2592 goto fail;
2595 else if( lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_CLLI ) )
2597 specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_CONTENT_LIGHT_LEVEL_INFO,
2598 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2599 if( !specific )
2600 goto fail;
2601 isom_clli_t *clli = (isom_clli_t *)box;
2602 lsmash_qt_content_light_level_info_t *data = (lsmash_qt_content_light_level_info_t *)specific->data.structured;
2603 data->max_content_light_level = clli->max_content_light_level;
2604 data->max_pic_average_light_level = clli->max_pic_average_light_level;
2606 else if( lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_MDCV ) )
2608 specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_MASTERING_DISPLAY_COLOR_VOLUME,
2609 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2610 if( !specific )
2611 goto fail;
2612 isom_mdcv_t *mdcv = (isom_mdcv_t *)box;
2613 lsmash_qt_mastering_display_color_volume_t *data = (lsmash_qt_mastering_display_color_volume_t *)specific->data.structured;
2614 data->display_primaries_g_x = mdcv->display_primaries_g_x;
2615 data->display_primaries_g_y = mdcv->display_primaries_g_y;
2616 data->display_primaries_b_x = mdcv->display_primaries_b_x;
2617 data->display_primaries_b_y = mdcv->display_primaries_b_y;
2618 data->display_primaries_r_x = mdcv->display_primaries_r_x;
2619 data->display_primaries_r_y = mdcv->display_primaries_r_y;
2620 data->white_point_x = mdcv->white_point_x;
2621 data->white_point_y = mdcv->white_point_y;
2622 data->max_display_mastering_luminance = mdcv->max_display_mastering_luminance;
2623 data->min_display_mastering_luminance = mdcv->min_display_mastering_luminance;
2625 else
2626 continue;
2627 if( lsmash_list_add_entry( &summary->opaque->list, specific ) < 0 )
2629 lsmash_destroy_codec_specific_data( specific );
2630 goto fail;
2633 else
2635 if( box->size < ISOM_BASEBOX_COMMON_SIZE )
2636 continue;
2637 uint8_t *data = box->binary;
2638 lsmash_compact_box_type_t fourcc = LSMASH_4CC( data[4], data[5], data[6], data[7] );
2639 lsmash_codec_specific_data_type type = isom_get_codec_specific_data_type( fourcc );
2640 lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( type, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
2641 if( !specific )
2642 goto fail;
2643 specific->size = box->size;
2644 specific->data.unstructured = lsmash_memdup( box->binary, box->size );
2645 if( !specific->data.unstructured
2646 || lsmash_list_add_entry( &summary->opaque->list, specific ) < 0 )
2648 lsmash_destroy_codec_specific_data( specific );
2649 goto fail;
2653 return (lsmash_summary_t *)summary;
2654 fail:
2655 lsmash_cleanup_summary( (lsmash_summary_t *)summary );
2656 return NULL;
2659 static int isom_append_structured_mp4sys_decoder_config( lsmash_codec_specific_list_t *opaque, isom_esds_t *esds )
2661 lsmash_bs_t *bs = lsmash_bs_create();
2662 if( !bs )
2663 return LSMASH_ERR_MEMORY_ALLOC;
2664 /* Put box size, type, version and flags fields. */
2665 lsmash_bs_put_be32( bs, 0 );
2666 lsmash_bs_put_be32( bs, ISOM_BOX_TYPE_ESDS.fourcc );
2667 lsmash_bs_put_be32( bs, 0 );
2668 /* Put ES Descriptor. */
2669 mp4sys_update_descriptor_size( esds->ES );
2670 mp4sys_write_descriptor( bs, esds->ES );
2671 /* Export ES Descriptor Box as binary string. */
2672 uint32_t esds_size;
2673 uint8_t *esds_data = lsmash_bs_export_data( bs, &esds_size );
2674 lsmash_bs_cleanup( bs );
2675 if( !esds_data )
2676 return LSMASH_ERR_NAMELESS;
2677 /* Update box size. */
2678 LSMASH_SET_BE32( esds_data, esds_size );
2679 lsmash_codec_specific_data_type type = isom_get_codec_specific_data_type( ISOM_BOX_TYPE_ESDS.fourcc );
2680 lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( type, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
2681 if( !specific )
2683 lsmash_free( esds_data );
2684 return LSMASH_ERR_NAMELESS;
2686 specific->data.unstructured = esds_data;
2687 specific->size = esds_size;
2688 /* Convert unstructured CODEC specific data format into structured, and append it to the opaque list. */
2689 lsmash_codec_specific_t *conv = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2690 lsmash_destroy_codec_specific_data( specific );
2691 if( !conv )
2692 return LSMASH_ERR_NAMELESS;
2693 if( lsmash_list_add_entry( &opaque->list, conv ) < 0 )
2695 lsmash_destroy_codec_specific_data( conv );
2696 return LSMASH_ERR_MEMORY_ALLOC;
2698 return 0;
2701 lsmash_summary_t *isom_create_audio_summary_from_description( isom_sample_entry_t *sample_entry )
2703 if( LSMASH_IS_NON_EXISTING_BOX( sample_entry->file )
2704 || LSMASH_IS_NON_EXISTING_BOX( sample_entry->parent ) )
2705 return NULL;
2706 isom_audio_entry_t *audio = (isom_audio_entry_t *)sample_entry;
2707 lsmash_audio_summary_t *summary = (lsmash_audio_summary_t *)lsmash_create_summary( LSMASH_SUMMARY_TYPE_AUDIO );
2708 if( !summary )
2709 return NULL;
2710 summary->sample_type = audio->type;
2711 summary->data_ref_index = audio->data_reference_index;
2712 summary->sample_size = audio->samplesize;
2713 summary->channels = audio->channelcount;
2714 summary->frequency = audio->samplerate >> 16;
2715 if( ((isom_stsd_t *)audio->parent)->version == 0
2716 && audio->file->qt_compatible
2717 && isom_is_qt_audio( audio->type ) )
2719 if( audio->version == 0 )
2720 isom_get_implicit_qt_fixed_comp_audio_sample_quants( audio, &summary->samples_in_frame, &summary->bytes_per_frame, &summary->sample_size );
2721 else if( audio->version == 1 )
2723 summary->channels = audio->bytesPerPacket ? audio->bytesPerFrame / audio->bytesPerPacket : audio->channelcount;
2724 summary->sample_size = audio->bytesPerPacket * 8;
2725 summary->samples_in_frame = audio->samplesPerPacket;
2726 summary->bytes_per_frame = audio->bytesPerFrame;
2728 else if( audio->version == 2 )
2730 summary->frequency = (union {uint64_t i; double d;}){audio->audioSampleRate}.d;
2731 summary->channels = audio->numAudioChannels;
2732 summary->sample_size = audio->constBitsPerChannel;
2733 summary->samples_in_frame = audio->constLPCMFramesPerAudioPacket;
2734 summary->bytes_per_frame = audio->constBytesPerAudioPacket;
2736 lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_COMMON,
2737 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2738 if( !specific )
2739 goto fail;
2740 lsmash_qt_audio_common_t *common = (lsmash_qt_audio_common_t *)specific->data.structured;
2741 common->revision_level = audio->revision_level;
2742 common->vendor = audio->vendor;
2743 common->compression_ID = audio->compression_ID;
2744 if( lsmash_list_add_entry( &summary->opaque->list, specific ) < 0 )
2746 lsmash_destroy_codec_specific_data( specific );
2747 goto fail;
2749 if( isom_is_lpcm_audio( audio ) )
2751 specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS,
2752 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2753 if( !specific )
2754 goto fail;
2755 lsmash_qt_audio_format_specific_flags_t *data = (lsmash_qt_audio_format_specific_flags_t *)specific->data.structured;
2756 if( audio->version == 2 )
2757 data->format_flags = audio->formatSpecificFlags;
2758 else
2760 data->format_flags = QT_LPCM_FORMAT_FLAG_BIG_ENDIAN | QT_LPCM_FORMAT_FLAG_SIGNED_INTEGER;
2761 /* Here, don't override samplesize.
2762 * We should trust samplesize field in the description for misused CODEC indentifier. */
2763 lsmash_codec_type_t audio_type = audio->type;
2764 if( lsmash_check_codec_type_identical( audio_type, QT_CODEC_TYPE_TWOS_AUDIO )
2765 || lsmash_check_codec_type_identical( audio_type, QT_CODEC_TYPE_NONE_AUDIO )
2766 || lsmash_check_codec_type_identical( audio_type, QT_CODEC_TYPE_NOT_SPECIFIED ) )
2768 if( summary->sample_size <= 8 )
2769 data->format_flags &= ~(QT_LPCM_FORMAT_FLAG_BIG_ENDIAN | QT_LPCM_FORMAT_FLAG_SIGNED_INTEGER);
2771 else
2773 if( lsmash_check_codec_type_identical( audio_type, QT_CODEC_TYPE_FL32_AUDIO )
2774 || lsmash_check_codec_type_identical( audio_type, QT_CODEC_TYPE_FL64_AUDIO ) )
2776 data->format_flags &= ~QT_LPCM_FORMAT_FLAG_SIGNED_INTEGER;
2777 data->format_flags |= QT_LPCM_FORMAT_FLAG_FLOAT;
2779 else if( lsmash_check_codec_type_identical( audio_type, QT_CODEC_TYPE_23NI_AUDIO )
2780 || lsmash_check_codec_type_identical( audio_type, QT_CODEC_TYPE_SOWT_AUDIO ) )
2781 data->format_flags &= ~QT_LPCM_FORMAT_FLAG_BIG_ENDIAN;
2784 isom_wave_t *wave = (isom_wave_t *)isom_get_extension_box_format( &audio->extensions, QT_BOX_TYPE_WAVE );
2785 if( LSMASH_IS_EXISTING_BOX( wave->enda ) )
2787 if( wave->enda->littleEndian )
2788 data->format_flags &= ~QT_LPCM_FORMAT_FLAG_BIG_ENDIAN;
2789 else
2790 data->format_flags |= QT_LPCM_FORMAT_FLAG_BIG_ENDIAN;
2792 if( lsmash_list_add_entry( &summary->opaque->list, specific ) < 0 )
2794 lsmash_destroy_codec_specific_data( specific );
2795 goto fail;
2798 else if( audio->version == 2
2799 && (lsmash_check_codec_type_identical( audio->type, ISOM_CODEC_TYPE_ALAC_AUDIO )
2800 || lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ALAC_AUDIO )) )
2801 switch( audio->formatSpecificFlags )
2803 case QT_ALAC_FORMAT_FLAG_16BIT_SOURCE_DATA :
2804 summary->sample_size = 16;
2805 break;
2806 case QT_ALAC_FORMAT_FLAG_20BIT_SOURCE_DATA :
2807 summary->sample_size = 20;
2808 break;
2809 case QT_ALAC_FORMAT_FLAG_24BIT_SOURCE_DATA :
2810 summary->sample_size = 24;
2811 break;
2812 case QT_ALAC_FORMAT_FLAG_32BIT_SOURCE_DATA :
2813 summary->sample_size = 32;
2814 break;
2815 default :
2816 break;
2819 else if( lsmash_check_codec_type_identical( audio->type, ISOM_CODEC_TYPE_SAMR_AUDIO ) )
2821 summary->channels = 1;
2822 summary->frequency = 8000;
2824 else if( lsmash_check_codec_type_identical( audio->type, ISOM_CODEC_TYPE_SAWB_AUDIO ) )
2826 summary->channels = 1;
2827 summary->frequency = 16000;
2829 uint32_t actual_sampling_rate = 0;
2830 for( lsmash_entry_t *entry = audio->extensions.head; entry; entry = entry->next )
2832 isom_box_t *box = (isom_box_t *)entry->data;
2833 if( LSMASH_IS_NON_EXISTING_BOX( box ) )
2834 continue;
2835 if( !(box->manager & LSMASH_BINARY_CODED_BOX) )
2837 if( lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_CHAN ) )
2839 lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT,
2840 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2841 if( !specific )
2842 goto fail;
2843 isom_chan_t *chan = (isom_chan_t *)box;
2844 lsmash_qt_audio_channel_layout_t *data = (lsmash_qt_audio_channel_layout_t *)specific->data.structured;
2845 data->channelLayoutTag = chan->channelLayoutTag;
2846 data->channelBitmap = chan->channelBitmap;
2847 if( lsmash_list_add_entry( &summary->opaque->list, specific ) < 0 )
2849 lsmash_destroy_codec_specific_data( specific );
2850 goto fail;
2853 else if( lsmash_check_box_type_identical( box->type, ISOM_BOX_TYPE_ESDS )
2854 || lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_ESDS ) )
2856 isom_esds_t *esds = (isom_esds_t *)box;
2857 if( mp4sys_setup_summary_from_DecoderSpecificInfo( summary, esds->ES ) < 0
2858 || isom_append_structured_mp4sys_decoder_config( summary->opaque, esds ) < 0 )
2859 goto fail;
2861 else if( lsmash_check_box_type_identical( box->type, ISOM_BOX_TYPE_SRAT ) )
2863 isom_srat_t *srat = (isom_srat_t *)box;
2864 actual_sampling_rate = srat->sampling_rate;
2866 else if( lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_WAVE ) )
2868 /* Don't append 'wave' extension itself to the opaque CODEC specific info list. */
2869 isom_wave_t *wave = (isom_wave_t *)box;
2870 lsmash_bs_t *bs = lsmash_bs_create();
2871 if( !bs )
2872 goto fail;
2873 for( lsmash_entry_t *wave_entry = wave->extensions.head; wave_entry; wave_entry = wave_entry->next )
2875 isom_box_t *wave_ext = (isom_box_t *)wave_entry->data;
2876 if( LSMASH_IS_NON_EXISTING_BOX( wave_ext ) )
2877 continue;
2878 lsmash_box_type_t box_type = LSMASH_BOX_TYPE_INITIALIZER;
2879 if( !(wave_ext->manager & LSMASH_BINARY_CODED_BOX) )
2881 box_type = wave_ext->type;
2882 if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_ENDA ) )
2884 isom_enda_t *enda = (isom_enda_t *)wave_ext;
2885 isom_bs_put_box_common( bs, enda );
2886 lsmash_bs_put_be16( bs, enda->littleEndian );
2888 else if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_MP4A ) )
2890 isom_mp4a_t *mp4a = (isom_mp4a_t *)wave_ext;
2891 isom_bs_put_box_common( bs, mp4a );
2892 lsmash_bs_put_be32( bs, mp4a->unknown );
2894 else if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_CHAN ) )
2896 isom_chan_t *chan = (isom_chan_t *)wave_ext;
2897 isom_bs_put_box_common( bs, chan );
2898 lsmash_bs_put_be32( bs, chan->channelLayoutTag );
2899 lsmash_bs_put_be32( bs, chan->channelBitmap );
2900 lsmash_bs_put_be32( bs, chan->numberChannelDescriptions );
2901 if( chan->channelDescriptions )
2902 for( uint32_t i = 0; i < chan->numberChannelDescriptions; i++ )
2904 isom_channel_description_t *channelDescriptions = (isom_channel_description_t *)(&chan->channelDescriptions[i]);
2905 lsmash_bs_put_be32( bs, channelDescriptions->channelLabel );
2906 lsmash_bs_put_be32( bs, channelDescriptions->channelFlags );
2907 lsmash_bs_put_be32( bs, channelDescriptions->coordinates[0] );
2908 lsmash_bs_put_be32( bs, channelDescriptions->coordinates[1] );
2909 lsmash_bs_put_be32( bs, channelDescriptions->coordinates[2] );
2912 else if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_ESDS ) )
2914 isom_esds_t *esds = (isom_esds_t *)wave_ext;
2915 if( LSMASH_IS_NON_EXISTING_BOX( esds )
2916 || mp4sys_setup_summary_from_DecoderSpecificInfo( summary, esds->ES ) < 0
2917 || isom_append_structured_mp4sys_decoder_config( summary->opaque, esds ) < 0 )
2919 lsmash_bs_cleanup( bs );
2920 goto fail;
2922 continue;
2924 else
2925 /* Skip Format Box and Terminator Box since they are mandatory and fixed structure. */
2926 continue;
2928 else
2930 if( wave_ext->size < ISOM_BASEBOX_COMMON_SIZE )
2931 continue;
2932 uint8_t *data = wave_ext->binary;
2933 box_type.fourcc = LSMASH_4CC( data[4], data[5], data[6], data[7] );
2934 lsmash_bs_put_bytes( bs, wave_ext->size, wave_ext->binary );
2936 /* Export as binary string. */
2937 uint32_t box_size;
2938 uint8_t *box_data = lsmash_bs_export_data( bs, &box_size );
2939 lsmash_bs_empty( bs );
2940 if( !box_data )
2942 lsmash_bs_cleanup( bs );
2943 goto fail;
2945 /* Append as an unstructured CODEC specific info. */
2946 lsmash_codec_specific_data_type type;
2947 if( box_type.fourcc == QT_BOX_TYPE_CHAN.fourcc )
2948 /* Complete audio channel layout is stored as binary string.
2949 * We distinguish it from one of the outside of 'wave' extension here. */
2950 type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_DECOMPRESSION_PARAMETERS;
2951 else
2953 type = isom_get_codec_specific_data_type( box_type.fourcc );
2954 if( type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN )
2955 type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_DECOMPRESSION_PARAMETERS;
2957 lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( type, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
2958 if( !specific )
2960 lsmash_free( box_data );
2961 lsmash_bs_cleanup( bs );
2962 goto fail;
2964 specific->data.unstructured = box_data;
2965 specific->size = box_size;
2966 if( lsmash_list_add_entry( &summary->opaque->list, specific ) < 0 )
2968 lsmash_destroy_codec_specific_data( specific );
2969 lsmash_bs_cleanup( bs );
2970 goto fail;
2973 lsmash_bs_cleanup( bs );
2976 else
2978 if( box->size < ISOM_BASEBOX_COMMON_SIZE )
2979 continue;
2980 uint8_t *data = box->binary;
2981 lsmash_compact_box_type_t fourcc = LSMASH_4CC( data[4], data[5], data[6], data[7] );
2982 lsmash_codec_specific_data_type type = isom_get_codec_specific_data_type( fourcc );
2983 lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( type, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
2984 if( !specific )
2985 goto fail;
2986 specific->size = box->size;
2987 specific->data.unstructured = lsmash_memdup( box->binary, box->size );
2988 if( !specific->data.unstructured
2989 || lsmash_list_add_entry( &summary->opaque->list, specific ) < 0 )
2991 lsmash_destroy_codec_specific_data( specific );
2992 goto fail;
2994 if( specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS
2995 || specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_AC_3
2996 || specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_EC_3 )
2998 specific = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2999 if( !specific )
3000 goto fail;
3001 switch( specific->type )
3003 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS :
3005 lsmash_dts_specific_parameters_t *param = (lsmash_dts_specific_parameters_t *)specific->data.structured;
3006 summary->sample_size = param->pcmSampleDepth;
3007 summary->samples_in_frame = (summary->frequency * (512 << param->FrameDuration)) / param->DTSSamplingFrequency;
3008 break;
3010 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_AC_3 :
3012 lsmash_ac3_specific_parameters_t *param = (lsmash_ac3_specific_parameters_t *)specific->data.structured;
3013 summary->frequency = ac3_get_sample_rate( param );
3014 summary->channels = ac3_get_channel_count( param );
3015 summary->samples_in_frame = 1536;
3016 break;
3018 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_EC_3 :
3020 lsmash_eac3_specific_parameters_t *param = (lsmash_eac3_specific_parameters_t *)specific->data.structured;
3021 eac3_update_sample_rate( &summary->frequency, param, NULL );
3022 eac3_update_channel_count( &summary->channels, param );
3023 summary->samples_in_frame = 1536;
3024 break;
3026 default :
3027 break;
3029 lsmash_destroy_codec_specific_data( specific );
3033 /* Set the actual sampling rate. */
3034 if( actual_sampling_rate )
3035 summary->frequency = actual_sampling_rate;
3036 return (lsmash_summary_t *)summary;
3037 fail:
3038 lsmash_cleanup_summary( (lsmash_summary_t *)summary );
3039 return NULL;
3042 lsmash_codec_specific_t *lsmash_get_codec_specific_data( lsmash_summary_t *summary, uint32_t extension_number )
3044 if( !summary || !summary->opaque )
3045 return NULL;
3046 uint32_t i = 0;
3047 for( lsmash_entry_t *entry = summary->opaque->list.head; entry; entry = entry->next )
3048 if( ++i == extension_number )
3049 return (lsmash_codec_specific_t *)entry->data;
3050 return NULL;
3053 uint32_t lsmash_count_codec_specific_data( lsmash_summary_t *summary )
3055 if( !summary || !summary->opaque )
3056 return 0;
3057 return summary->opaque->list.entry_count;
3060 int isom_compare_opaque_extensions( lsmash_summary_t *a, lsmash_summary_t *b )
3062 assert( a && b );
3063 uint32_t in_number_of_extensions = lsmash_count_codec_specific_data( a );
3064 uint32_t out_number_of_extensions = lsmash_count_codec_specific_data( b );
3065 if( out_number_of_extensions != in_number_of_extensions )
3066 return 1;
3067 uint32_t active_number_of_extensions = in_number_of_extensions;
3068 uint32_t identical_count = 0;
3069 for( uint32_t j = 1; j <= in_number_of_extensions; j++ )
3071 lsmash_codec_specific_t *in_cs_orig = lsmash_get_codec_specific_data( a, j );
3072 lsmash_codec_specific_t *in_cs;
3073 lsmash_codec_specific_format compare_format = LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED;
3074 if( in_cs_orig->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
3076 if( in_cs_orig->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_COMMON
3077 || in_cs_orig->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_COMMON
3078 || in_cs_orig->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS )
3080 compare_format = LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED;
3081 in_cs = in_cs_orig;
3083 else
3085 in_cs = lsmash_convert_codec_specific_format( in_cs_orig, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
3086 if( !in_cs )
3088 /* We don't support the format converter of this data type. */
3089 --active_number_of_extensions;
3090 continue;
3094 else
3095 in_cs = in_cs_orig;
3096 for( uint32_t k = 1; k <= out_number_of_extensions; k++ )
3098 lsmash_codec_specific_t *out_cs_orig = lsmash_get_codec_specific_data( b, k );
3099 if( out_cs_orig->type != in_cs_orig->type )
3100 continue;
3101 lsmash_codec_specific_t *out_cs;
3102 if( out_cs_orig->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
3104 if( compare_format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
3105 out_cs = out_cs_orig;
3106 else
3108 out_cs = lsmash_convert_codec_specific_format( out_cs_orig, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
3109 if( !out_cs )
3110 continue;
3113 else
3114 out_cs = out_cs_orig;
3115 int identical;
3116 if( compare_format == LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED )
3117 identical = out_cs->size == in_cs->size && !memcmp( out_cs->data.unstructured, in_cs->data.unstructured, in_cs->size );
3118 else
3120 if( in_cs->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_COMMON )
3122 lsmash_qt_video_common_t *in_data = (lsmash_qt_video_common_t *)in_cs->data.structured;
3123 lsmash_qt_video_common_t *out_data = (lsmash_qt_video_common_t *)out_cs->data.structured;
3124 identical = in_data->revision_level == out_data->revision_level
3125 && in_data->vendor == out_data->vendor
3126 && in_data->temporalQuality == out_data->temporalQuality
3127 && in_data->spatialQuality == out_data->spatialQuality
3128 && in_data->horizontal_resolution == out_data->horizontal_resolution
3129 && in_data->vertical_resolution == out_data->vertical_resolution
3130 && in_data->dataSize == out_data->dataSize
3131 && in_data->frame_count == out_data->frame_count
3132 && in_data->color_table_ID == out_data->color_table_ID;
3134 else if( in_cs->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_COMMON )
3136 lsmash_qt_audio_common_t *in_data = (lsmash_qt_audio_common_t *)in_cs->data.structured;
3137 lsmash_qt_audio_common_t *out_data = (lsmash_qt_audio_common_t *)out_cs->data.structured;
3138 identical = in_data->revision_level == out_data->revision_level
3139 && in_data->vendor == out_data->vendor
3140 && in_data->compression_ID == out_data->compression_ID;
3142 else
3144 lsmash_qt_audio_format_specific_flags_t *in_data = (lsmash_qt_audio_format_specific_flags_t *)in_cs->data.structured;
3145 lsmash_qt_audio_format_specific_flags_t *out_data = (lsmash_qt_audio_format_specific_flags_t *)out_cs->data.structured;
3146 identical = (in_data->format_flags == out_data->format_flags);
3149 if( out_cs != out_cs_orig )
3150 lsmash_destroy_codec_specific_data( out_cs );
3151 if( identical )
3153 ++identical_count;
3154 break;
3157 if( in_cs != in_cs_orig )
3158 lsmash_destroy_codec_specific_data( in_cs );
3160 return (identical_count != active_number_of_extensions);
3163 int isom_get_implicit_qt_fixed_comp_audio_sample_quants
3165 isom_audio_entry_t *audio,
3166 uint32_t *samples_per_packet,
3167 uint32_t *constant_bytes_per_frame,
3168 uint32_t *sample_size
3171 if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_MAC3_AUDIO ) )
3173 *samples_per_packet = 6;
3174 *constant_bytes_per_frame = 2 * audio->channelcount;
3175 *sample_size = 8;
3177 else if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_MAC6_AUDIO ) )
3179 *samples_per_packet = 6;
3180 *constant_bytes_per_frame = audio->channelcount;
3181 *sample_size = 8;
3183 else if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ADPCM17_AUDIO ) )
3185 *samples_per_packet = 64;
3186 *constant_bytes_per_frame = 34 * audio->channelcount;
3187 *sample_size = 16;
3189 else if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_AGSM_AUDIO ) )
3191 *samples_per_packet = 160;
3192 *constant_bytes_per_frame = 33;
3193 *sample_size = 16;
3195 else if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ALAW_AUDIO )
3196 || lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ULAW_AUDIO ) )
3198 *samples_per_packet = 1;
3199 *constant_bytes_per_frame = audio->channelcount;
3200 *sample_size = 16;
3202 else
3203 return 0;
3204 return 1;
3207 int hint_update_bitrate( isom_stbl_t *stbl, isom_mdhd_t *mdhd, uint32_t sample_description_index )
3209 uint32_t bufferSizeDB;
3210 uint32_t maxBitrate = 0;
3211 uint32_t avgBitrate = 0;
3212 int err = isom_calculate_bitrate_description( stbl, mdhd, &bufferSizeDB, &maxBitrate, &avgBitrate, sample_description_index );
3213 isom_hmhd_t *hmhd = ((isom_mdia_t*)(mdhd->parent))->minf->hmhd;
3214 hmhd->maxbitrate = maxBitrate;
3215 hmhd->avgbitrate = avgBitrate;
3216 hmhd->avgPDUsize = hmhd->PDUcount > 0 ? (hmhd->combinedPDUsize / hmhd->PDUcount) : 0;
3217 return err;
3220 isom_bitrate_updater_t isom_get_bitrate_updater
3222 isom_sample_entry_t *sample_entry
3225 #define RETURN_BITRATE_UPDATER( func_name ) \
3227 extern int func_name( isom_stbl_t *, isom_mdhd_t *, uint32_t sample_description_index ); \
3228 return func_name; \
3230 lsmash_codec_type_t sample_type = sample_entry->type;
3231 if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_AVC1_VIDEO )
3232 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_AVC2_VIDEO )
3233 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_AVC3_VIDEO )
3234 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_AVC4_VIDEO )
3235 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_HVC1_VIDEO )
3236 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_HEV1_VIDEO ) )
3237 RETURN_BITRATE_UPDATER( nalu_update_bitrate )
3238 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_MP4V_VIDEO ) )
3239 RETURN_BITRATE_UPDATER( mp4v_update_bitrate )
3240 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_MP4A_AUDIO )
3241 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_MP4A_AUDIO ) )
3242 RETURN_BITRATE_UPDATER( mp4a_update_bitrate )
3243 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_ALAC_AUDIO )
3244 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_ALAC_AUDIO ) )
3245 RETURN_BITRATE_UPDATER( alac_update_bitrate )
3246 else if( isom_is_dts_audio( sample_type ) )
3247 RETURN_BITRATE_UPDATER( dts_update_bitrate )
3248 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_EC_3_AUDIO ) )
3249 RETURN_BITRATE_UPDATER( eac3_update_bitrate )
3250 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_RRTP_HINT ) )
3251 RETURN_BITRATE_UPDATER( hint_update_bitrate )
3252 else if( isom_is_waveform_audio( sample_type ) )
3253 RETURN_BITRATE_UPDATER( waveform_audio_update_bitrate )
3254 else
3255 return NULL;
3256 #undef RETURN_BITRATE_UPDATER