hevc: Fix an AU delimit finder by TileId and CtbAddrRsToTs.
[L-SMASH.git] / codecs / description.c
blobdac6f0bbbb267084a0b62a8b3aa7aa561cb4e8c5
1 /*****************************************************************************
2 * description.c:
3 *****************************************************************************
4 * Copyright (C) 2012-2015 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 int lsmash_convert_crop_into_clap( lsmash_crop_t crop, uint32_t width, uint32_t height, lsmash_clap_t *clap )
125 if( !clap || crop.top.d == 0 || crop.bottom.d == 0 || crop.left.d == 0 || crop.right.d == 0 )
126 return LSMASH_ERR_FUNCTION_PARAM;
127 uint64_t vertical_crop_lcm = lsmash_get_lcm( crop.top.d, crop.bottom.d );
128 uint64_t horizontal_crop_lcm = lsmash_get_lcm( crop.left.d, crop.right.d );
129 lsmash_rational_u64_t clap_height;
130 lsmash_rational_u64_t clap_width;
131 lsmash_rational_s64_t clap_horizontal_offset;
132 lsmash_rational_s64_t clap_vertical_offset;
133 clap_height.d = vertical_crop_lcm;
134 clap_width.d = horizontal_crop_lcm;
135 clap_horizontal_offset.d = 2 * vertical_crop_lcm;
136 clap_vertical_offset.d = 2 * horizontal_crop_lcm;
137 clap_height.n = height * vertical_crop_lcm
138 - (crop.top.n * (vertical_crop_lcm / crop.top.d) + crop.bottom.n * (vertical_crop_lcm / crop.bottom.d));
139 clap_width.n = width * horizontal_crop_lcm
140 - (crop.left.n * (horizontal_crop_lcm / crop.left.d) + crop.right.n * (horizontal_crop_lcm / crop.right.d));
141 clap_horizontal_offset.n = (int64_t)(crop.left.n * (horizontal_crop_lcm / crop.left.d))
142 - crop.right.n * (horizontal_crop_lcm / crop.right.d);
143 clap_vertical_offset.n = (int64_t)(crop.top.n * (vertical_crop_lcm / crop.top.d))
144 - crop.bottom.n * (vertical_crop_lcm / crop.bottom.d);
145 lsmash_reduce_fraction( &clap_height.n, &clap_height.d );
146 lsmash_reduce_fraction( &clap_width.n, &clap_width.d );
147 lsmash_reduce_fraction_su( &clap_vertical_offset.n, &clap_vertical_offset.d );
148 lsmash_reduce_fraction_su( &clap_horizontal_offset.n, &clap_horizontal_offset.d );
149 clap->height = (lsmash_rational_u32_t){ clap_height.n, clap_height.d };
150 clap->width = (lsmash_rational_u32_t){ clap_width.n, clap_width.d };
151 clap->vertical_offset = (lsmash_rational_s32_t){ clap_vertical_offset.n, clap_vertical_offset.d };
152 clap->horizontal_offset = (lsmash_rational_s32_t){ clap_horizontal_offset.n, clap_horizontal_offset.d };
153 return 0;
156 int lsmash_convert_clap_into_crop( lsmash_clap_t clap, uint32_t width, uint32_t height, lsmash_crop_t *crop )
158 if( !crop || clap.height.d == 0 || clap.vertical_offset.d == 0 || clap.width.d == 0 || clap.horizontal_offset.d == 0 )
159 return LSMASH_ERR_FUNCTION_PARAM;
160 uint64_t clap_vertical_lcm = lsmash_get_lcm( clap.height.d, clap.vertical_offset.d );
161 uint64_t clap_horizontal_lcm = lsmash_get_lcm( clap.width.d, clap.horizontal_offset.d );
162 lsmash_rational_u64_t crop_top;
163 lsmash_rational_u64_t crop_bottom;
164 lsmash_rational_u64_t crop_left;
165 lsmash_rational_u64_t crop_right;
166 crop_top.d = 2 * clap_vertical_lcm;
167 crop_bottom.d = 2 * clap_vertical_lcm;
168 crop_left.d = 2 * clap_horizontal_lcm;
169 crop_right.d = 2 * clap_horizontal_lcm;
170 crop_top.n = (height * crop_top.d - clap.height.n * (crop_top.d / clap.height.d)) / 2
171 + clap.vertical_offset.n * (crop_top.d / clap.vertical_offset.d);
172 crop_bottom.n = (height * crop_bottom.d - clap.height.n * (crop_bottom.d / clap.height.d)) / 2
173 - clap.vertical_offset.n * (crop_bottom.d / clap.vertical_offset.d);
174 crop_left.n = (width * crop_left.d - clap.width.n * (crop_left.d / clap.width.d)) / 2
175 + clap.horizontal_offset.n * (crop_left.d / clap.horizontal_offset.d);
176 crop_right.n = (width * crop_right.d - clap.width.n * (crop_right.d / clap.width.d)) / 2
177 - clap.horizontal_offset.n * (crop_right.d / clap.horizontal_offset.d);
178 lsmash_reduce_fraction( &crop_top.n, &crop_top.d );
179 lsmash_reduce_fraction( &crop_bottom.n, &crop_bottom.d );
180 lsmash_reduce_fraction( &crop_left.n, &crop_left.d );
181 lsmash_reduce_fraction( &crop_right.n, &crop_right.d );
182 crop->top = (lsmash_rational_u32_t){ crop_top.n, crop_top.d };
183 crop->bottom = (lsmash_rational_u32_t){ crop_bottom.n, crop_bottom.d };
184 crop->left = (lsmash_rational_u32_t){ crop_left.n, crop_left.d };
185 crop->right = (lsmash_rational_u32_t){ crop_right.n, crop_right.d };
186 return 0;
189 static void isom_destruct_nothing( void *data )
191 /* Do nothing. */;
194 static int isom_initialize_structured_codec_specific_data( lsmash_codec_specific_t *specific )
196 extern void mp4sys_destruct_decoder_config( void * );
197 extern void h264_destruct_specific_data( void * );
198 extern void hevc_destruct_specific_data( void * );
199 extern void vc1_destruct_specific_data( void * );
200 extern void dts_destruct_specific_data( void * );
201 switch( specific->type )
203 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG :
204 specific->size = sizeof(lsmash_mp4sys_decoder_parameters_t);
205 specific->destruct = mp4sys_destruct_decoder_config;
206 break;
207 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264 :
208 specific->size = sizeof(lsmash_h264_specific_parameters_t);
209 specific->destruct = h264_destruct_specific_data;
210 break;
211 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_HEVC :
212 specific->size = sizeof(lsmash_hevc_specific_parameters_t);
213 specific->destruct = hevc_destruct_specific_data;
214 break;
215 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_VC_1 :
216 specific->size = sizeof(lsmash_vc1_specific_parameters_t);
217 specific->destruct = vc1_destruct_specific_data;
218 break;
219 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_AC_3 :
220 specific->size = sizeof(lsmash_ac3_specific_parameters_t);
221 specific->destruct = lsmash_free;
222 break;
223 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_EC_3 :
224 specific->size = sizeof(lsmash_eac3_specific_parameters_t);
225 specific->destruct = lsmash_free;
226 break;
227 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS :
228 specific->size = sizeof(lsmash_dts_specific_parameters_t);
229 specific->destruct = dts_destruct_specific_data;
230 break;
231 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_ALAC :
232 specific->size = sizeof(lsmash_alac_specific_parameters_t);
233 specific->destruct = lsmash_free;
234 break;
235 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_SAMPLE_SCALE :
236 specific->size = sizeof(lsmash_isom_sample_scale_t);
237 specific->destruct = lsmash_free;
238 break;
239 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264_BITRATE :
240 specific->size = sizeof(lsmash_h264_bitrate_t);
241 specific->destruct = lsmash_free;
242 break;
243 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_COMMON :
244 specific->size = sizeof(lsmash_qt_video_common_t);
245 specific->destruct = lsmash_free;
246 break;
247 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_COMMON :
248 specific->size = sizeof(lsmash_qt_audio_common_t);
249 specific->destruct = lsmash_free;
250 break;
251 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS :
252 specific->size = sizeof(lsmash_qt_audio_format_specific_flags_t);
253 specific->destruct = lsmash_free;
254 break;
255 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER :
256 specific->size = sizeof(lsmash_codec_global_header_t);
257 specific->destruct = global_destruct_specific_data;
258 break;
259 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_FIELD_INFO :
260 specific->size = sizeof(lsmash_qt_field_info_t);
261 specific->destruct = lsmash_free;
262 break;
263 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_PIXEL_FORMAT :
264 specific->size = sizeof(lsmash_qt_pixel_format_t);
265 specific->destruct = lsmash_free;
266 break;
267 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_SIGNIFICANT_BITS :
268 specific->size = sizeof(lsmash_qt_significant_bits_t);
269 specific->destruct = lsmash_free;
270 break;
271 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT :
272 specific->size = sizeof(lsmash_qt_audio_channel_layout_t);
273 specific->destruct = lsmash_free;
274 break;
275 default :
276 specific->size = 0;
277 specific->destruct = isom_destruct_nothing;
278 return 0;
280 specific->data.structured = lsmash_malloc_zero( specific->size );
281 if( !specific->data.structured )
283 specific->size = 0;
284 specific->destruct = NULL;
285 return LSMASH_ERR_MEMORY_ALLOC;
287 return 0;
290 static inline int isom_initialize_codec_specific_data( lsmash_codec_specific_t *specific,
291 lsmash_codec_specific_data_type type,
292 lsmash_codec_specific_format format )
294 specific->type = type;
295 specific->format = format;
296 if( format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
298 int err = isom_initialize_structured_codec_specific_data( specific );
299 if( err < 0 )
300 return err;
302 else
304 specific->data.unstructured = NULL;
305 specific->size = 0;
306 specific->destruct = (lsmash_codec_specific_destructor_t)lsmash_free;
308 return 0;
311 void lsmash_destroy_codec_specific_data( lsmash_codec_specific_t *specific )
313 if( !specific )
314 return;
315 if( specific->destruct )
317 if( specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
319 if( specific->data.structured )
320 specific->destruct( specific->data.structured );
322 else
324 if( specific->data.unstructured )
325 specific->destruct( specific->data.unstructured );
328 lsmash_free( specific );
331 lsmash_codec_specific_t *lsmash_create_codec_specific_data( lsmash_codec_specific_data_type type, lsmash_codec_specific_format format )
333 lsmash_codec_specific_t *specific = lsmash_malloc( sizeof(lsmash_codec_specific_t) );
334 if( !specific )
335 return NULL;
336 if( isom_initialize_codec_specific_data( specific, type, format ) < 0 )
338 lsmash_destroy_codec_specific_data( specific );
339 return NULL;
341 return specific;
344 static int isom_duplicate_structured_specific_data( lsmash_codec_specific_t *dst, lsmash_codec_specific_t *src )
346 extern int mp4sys_copy_decoder_config( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
347 extern int h264_copy_codec_specific( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
348 extern int hevc_copy_codec_specific( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
349 extern int vc1_copy_codec_specific( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
350 extern int dts_copy_codec_specific( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
351 void *src_data = src->data.structured;
352 void *dst_data = dst->data.structured;
353 switch( src->type )
355 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG :
356 return mp4sys_copy_decoder_config( dst, src );
357 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264 :
358 return h264_copy_codec_specific( dst, src );
359 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_HEVC :
360 return hevc_copy_codec_specific( dst, src );
361 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_VC_1 :
362 return vc1_copy_codec_specific( dst, src );
363 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_AC_3 :
364 *(lsmash_ac3_specific_parameters_t *)dst_data = *(lsmash_ac3_specific_parameters_t *)src_data;
365 return 0;
366 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_EC_3 :
367 *(lsmash_eac3_specific_parameters_t *)dst_data = *(lsmash_eac3_specific_parameters_t *)src_data;
368 return 0;
369 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS :
370 return dts_copy_codec_specific( dst, src );
371 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_ALAC :
372 *(lsmash_alac_specific_parameters_t *)dst_data = *(lsmash_alac_specific_parameters_t *)src_data;
373 return 0;
374 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_SAMPLE_SCALE :
375 *(lsmash_isom_sample_scale_t *)dst_data = *(lsmash_isom_sample_scale_t *)src_data;
376 return 0;
377 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264_BITRATE :
378 *(lsmash_h264_bitrate_t *)dst_data = *(lsmash_h264_bitrate_t *)src_data;
379 return 0;
380 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_COMMON :
381 *(lsmash_qt_video_common_t *)dst_data = *(lsmash_qt_video_common_t *)src_data;
382 return 0;
383 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_COMMON :
384 *(lsmash_qt_audio_common_t *)dst_data = *(lsmash_qt_audio_common_t *)src_data;
385 return 0;
386 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS :
387 *(lsmash_qt_audio_format_specific_flags_t *)dst_data = *(lsmash_qt_audio_format_specific_flags_t *)src_data;
388 return 0;
389 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER :
391 lsmash_codec_global_header_t *src_global = (lsmash_codec_global_header_t *)src_data;
392 if( src_global->header_data && src_global->header_size )
394 lsmash_codec_global_header_t *dst_global = (lsmash_codec_global_header_t *)dst_data;
395 dst_global->header_data = lsmash_memdup( src_global->header_data, src_global->header_size );
396 if( !dst_global->header_data )
397 return LSMASH_ERR_MEMORY_ALLOC;
398 dst_global->header_size = src_global->header_size;
400 return 0;
402 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_FIELD_INFO :
403 *(lsmash_qt_field_info_t *)dst_data = *(lsmash_qt_field_info_t *)src_data;
404 return 0;
405 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_PIXEL_FORMAT :
406 *(lsmash_qt_pixel_format_t *)dst_data = *(lsmash_qt_pixel_format_t *)src_data;
407 return 0;
408 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_SIGNIFICANT_BITS :
409 *(lsmash_qt_significant_bits_t *)dst_data = *(lsmash_qt_significant_bits_t *)src_data;
410 return 0;
411 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_GAMMA_LEVEL :
412 *(lsmash_qt_gamma_t *)dst_data = *(lsmash_qt_gamma_t *)src_data;
413 return 0;
414 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT :
415 *(lsmash_qt_audio_channel_layout_t *)dst_data = *(lsmash_qt_audio_channel_layout_t *)src_data;
416 return 0;
417 default :
418 return LSMASH_ERR_NAMELESS;
422 lsmash_codec_specific_t *isom_duplicate_codec_specific_data( lsmash_codec_specific_t *specific )
424 if( !specific )
425 return NULL;
426 lsmash_codec_specific_t *dup = lsmash_create_codec_specific_data( specific->type, specific->format );
427 if( !dup )
428 return NULL;
429 if( specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
431 if( isom_duplicate_structured_specific_data( dup, specific ) < 0 )
433 lsmash_destroy_codec_specific_data( dup );
434 return NULL;
437 else
439 dup->data.unstructured = lsmash_memdup( specific->data.unstructured, specific->size );
440 if( !dup->data.unstructured )
442 lsmash_destroy_codec_specific_data( dup );
443 return NULL;
446 dup->size = specific->size;
447 return dup;
450 static size_t isom_description_read_box_common( uint8_t **p_data, uint64_t *size, lsmash_box_type_t *type )
452 uint8_t *orig = *p_data;
453 uint8_t *data = *p_data;
454 *size = LSMASH_GET_BE32( &data[0] );
455 type->fourcc = LSMASH_GET_BE32( &data[4] );
456 data += ISOM_BASEBOX_COMMON_SIZE;
457 if( *size == 1 )
459 *size = LSMASH_GET_BE64( data );
460 data += 8;
462 *p_data = data;
463 if( type->fourcc == ISOM_BOX_TYPE_UUID.fourcc )
465 type->user.fourcc = LSMASH_GET_BE32( &data[0] );
466 memcpy( type->user.id, &data[4], 12 );
468 return data - orig;
471 uint8_t *isom_get_child_box_position( uint8_t *parent_data, uint32_t parent_size, lsmash_box_type_t child_type, uint32_t *child_size )
473 if( !parent_data || !child_size || parent_size < ISOM_BASEBOX_COMMON_SIZE )
474 return NULL;
475 uint8_t *data = parent_data;
476 uint64_t size;
477 lsmash_box_type_t type;
478 uint32_t offset = isom_description_read_box_common( &data, &size, &type );
479 if( size != parent_size )
480 return NULL;
481 uint8_t *end = parent_data + parent_size;
482 for( uint8_t *pos = data; pos + ISOM_BASEBOX_COMMON_SIZE <= end; )
484 offset = isom_description_read_box_common( &pos, &size, &type );
485 if( lsmash_check_box_type_identical( type, child_type ) )
487 *child_size = size;
488 return pos - offset;
490 pos += size - offset; /* Move to the next box. */
492 return NULL;
495 static int isom_construct_global_specific_header( lsmash_codec_specific_t *dst, lsmash_codec_specific_t *src )
497 if( src->size < ISOM_BASEBOX_COMMON_SIZE )
498 return LSMASH_ERR_INVALID_DATA;
499 lsmash_codec_global_header_t *global = (lsmash_codec_global_header_t *)dst->data.structured;
500 uint8_t *data = src->data.unstructured;
501 uint64_t size = LSMASH_GET_BE32( data );
502 data += ISOM_BASEBOX_COMMON_SIZE;
503 if( size == 1 )
505 size = LSMASH_GET_BE64( data );
506 data += 8;
508 if( size != src->size )
509 return LSMASH_ERR_INVALID_DATA;
510 global->header_size = size - ISOM_BASEBOX_COMMON_SIZE;
511 if( data != src->data.unstructured + ISOM_BASEBOX_COMMON_SIZE )
512 global->header_size -= 8; /* largesize */
513 if( global->header_size )
515 global->header_data = lsmash_memdup( data, global->header_size );
516 if( !global->header_data )
517 return LSMASH_ERR_MEMORY_ALLOC;
519 return 0;
522 static int isom_construct_audio_channel_layout( lsmash_codec_specific_t *dst, lsmash_codec_specific_t *src )
524 if( src->size < ISOM_FULLBOX_COMMON_SIZE + 12 )
525 return LSMASH_ERR_INVALID_DATA;
526 lsmash_qt_audio_channel_layout_t *layout = (lsmash_qt_audio_channel_layout_t *)dst->data.structured;
527 uint8_t *data = src->data.unstructured;
528 uint64_t size = LSMASH_GET_BE32( data );
529 data += ISOM_FULLBOX_COMMON_SIZE;
530 if( size == 1 )
532 size = LSMASH_GET_BE64( data );
533 data += 8;
535 if( size != src->size )
536 return LSMASH_ERR_INVALID_DATA;
537 layout->channelLayoutTag = LSMASH_GET_BE32( &data[0] );
538 layout->channelBitmap = LSMASH_GET_BE32( &data[4] );
539 return 0;
542 #if 0
543 static int codec_construct_qt_audio_decompression_info( lsmash_codec_specific_t *dst, lsmash_codec_specific_t *src )
545 if( src->size < ISOM_BASEBOX_COMMON_SIZE )
546 return LSMASH_ERR_INVALID_DATA;
547 uint8_t *data = src->data.unstructured;
548 uint64_t size;
549 uint32_t type;
550 uint32_t offset = isom_description_read_box_common( &data, &size, &type );
551 if( size != src->size )
552 return LSMASH_ERR_INVALID_DATA;
553 uint8_t *end = src->data.unstructured + src->size;
554 isom_wave_t *wave = lsmash_malloc_zero( sizeof(isom_wave_t) );
555 if( !wave )
556 return LSMASH_ERR_MEMORY_ALLOC;
557 wave->type = QT_BOX_TYPE_WAVE;
558 for( uint8_t *pos = data; pos + ISOM_BASEBOX_COMMON_SIZE <= end; )
560 offset = isom_description_read_box_common( &pos, &size, &type );
561 switch( type )
563 case QT_BOX_TYPE_FRMA :
565 if( pos + 4 > end )
566 return LSMASH_ERR_INVALID_DATA;
567 isom_frma_t *frma = isom_add_frma( wave );
568 if( !frma )
569 return LSMASH_ERR_NAMELESS;
570 frma->data_format = LSMASH_GET_BE32( pos );
571 pos += 4;
572 break;
574 case QT_BOX_TYPE_ENDA :
576 if( pos + 2 > end )
577 return LSMASH_ERR_INVALID_DATA;
578 isom_enda_t *enda = isom_add_enda( wave );
579 if( !enda )
580 return LSMASH_ERR_NAMELESS;
581 enda->littleEndian = LSMASH_GET_BE16( pos );
582 break;
584 case QT_BOX_TYPE_MP4A :
586 if( pos + 4 > end )
587 return LSMASH_ERR_INVALID_DATA;
588 isom_mp4a_t *mp4a = isom_add_mp4a( wave );
589 if( !mp4a )
590 return LSMASH_ERR_NAMELESS;
591 mp4a->unknown = LSMASH_GET_BE32( pos );
592 pos += 4;
593 break;
595 case QT_BOX_TYPE_TERMINATOR :
597 if( !isom_add_terminator( wave ) )
598 return LSMASH_ERR_NAMELESS;
599 break;
601 default :
603 isom_unknown_box_t *box = lsmash_malloc_zero( sizeof(isom_unknown_box_t) );
604 if( !box )
605 return LSMASH_ERR_MEMORY_ALLOC;
606 isom_init_box_common( box, wave, type, isom_remove_unknown_box );
607 box->unknown_size = size - offset;
608 box->unknown_field = lsmash_memdup( pos, box->unknown_size );
609 if( !box->unknown_field )
611 lsmash_free( box );
612 return LSMASH_ERR_MEMORY_ALLOC;
614 if( lsmash_add_entry( &wave->extensions, box ) < 0 )
616 isom_remove_unknown_box( box );
617 return LSMASH_ERR_MEMORY_ALLOC;
619 pos += box->unknown_size;
620 break;
624 return 0;
626 #endif
628 /* structured <-> unstructured conversion might be irreversible by CODEC
629 * since structured formats we defined don't always have all contents included in unstructured data. */
630 lsmash_codec_specific_t *lsmash_convert_codec_specific_format( lsmash_codec_specific_t *specific, lsmash_codec_specific_format format )
632 if( !specific || format == LSMASH_CODEC_SPECIFIC_FORMAT_UNSPECIFIED )
633 return NULL;
634 if( format == specific->format )
635 return isom_duplicate_codec_specific_data( specific );
636 lsmash_codec_specific_t *dst = lsmash_create_codec_specific_data( specific->type, format );
637 if( !dst )
638 return NULL;
639 if( format == LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED )
640 /* structured -> unstructured */
641 switch( specific->type )
643 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG :
644 dst->data.unstructured = lsmash_create_mp4sys_decoder_config( (lsmash_mp4sys_decoder_parameters_t *)specific->data.structured, &dst->size );
645 if( !dst->data.unstructured )
646 goto fail;
647 return dst;
648 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264 :
649 dst->data.unstructured = lsmash_create_h264_specific_info( (lsmash_h264_specific_parameters_t *)specific->data.structured, &dst->size );
650 if( !dst->data.unstructured )
651 goto fail;
652 return dst;
653 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_HEVC :
654 dst->data.unstructured = lsmash_create_hevc_specific_info( (lsmash_hevc_specific_parameters_t *)specific->data.structured, &dst->size );
655 if( !dst->data.unstructured )
656 goto fail;
657 return dst;
658 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_VC_1 :
659 dst->data.unstructured = lsmash_create_vc1_specific_info( (lsmash_vc1_specific_parameters_t *)specific->data.structured, &dst->size );
660 if( !dst->data.unstructured )
661 goto fail;
662 return dst;
663 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_AC_3 :
664 dst->data.unstructured = lsmash_create_ac3_specific_info( (lsmash_ac3_specific_parameters_t *)specific->data.structured, &dst->size );
665 if( !dst->data.unstructured )
666 goto fail;
667 return dst;
668 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_EC_3 :
669 dst->data.unstructured = lsmash_create_eac3_specific_info( (lsmash_eac3_specific_parameters_t *)specific->data.structured, &dst->size );
670 if( !dst->data.unstructured )
671 goto fail;
672 return dst;
673 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS :
674 dst->data.unstructured = lsmash_create_dts_specific_info( (lsmash_dts_specific_parameters_t *)specific->data.structured, &dst->size );
675 if( !dst->data.unstructured )
676 goto fail;
677 return dst;
678 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_ALAC :
679 dst->data.unstructured = lsmash_create_alac_specific_info( (lsmash_alac_specific_parameters_t *)specific->data.structured, &dst->size );
680 if( !dst->data.unstructured )
681 goto fail;
682 return dst;
683 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER :
685 lsmash_bs_t *bs = lsmash_bs_create();
686 if( !bs )
687 goto fail;
688 lsmash_codec_global_header_t *global = specific->data.structured;
689 lsmash_bs_put_be32( bs, ISOM_BASEBOX_COMMON_SIZE + global->header_size );
690 lsmash_bs_put_be32( bs, QT_BOX_TYPE_GLBL.fourcc );
691 lsmash_bs_put_bytes( bs, global->header_size, global->header_data );
692 dst->data.unstructured = lsmash_bs_export_data( bs, &dst->size );
693 lsmash_bs_cleanup( bs );
694 if( !dst->data.unstructured || dst->size != (ISOM_BASEBOX_COMMON_SIZE + global->header_size) )
695 goto fail;
696 return dst;
698 default :
699 break;
701 else if( format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
703 /* unstructured -> structured */
704 extern int mp4sys_construct_decoder_config( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
705 extern int h264_construct_specific_parameters( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
706 extern int hevc_construct_specific_parameters( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
707 extern int vc1_construct_specific_parameters( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
708 extern int ac3_construct_specific_parameters( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
709 extern int eac3_construct_specific_parameters( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
710 extern int dts_construct_specific_parameters( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
711 extern int alac_construct_specific_parameters( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
712 static const struct
714 lsmash_codec_specific_data_type data_type;
715 int (*constructor)( lsmash_codec_specific_t *, lsmash_codec_specific_t * );
716 } codec_specific_format_constructor_table[] =
718 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG, mp4sys_construct_decoder_config },
719 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264, h264_construct_specific_parameters },
720 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_HEVC, hevc_construct_specific_parameters },
721 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_VC_1, vc1_construct_specific_parameters },
722 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_AC_3, ac3_construct_specific_parameters },
723 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_EC_3, eac3_construct_specific_parameters },
724 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS, dts_construct_specific_parameters },
725 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_ALAC, alac_construct_specific_parameters },
726 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER, isom_construct_global_specific_header },
727 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT, isom_construct_audio_channel_layout },
728 { LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN, NULL }
730 int (*constructor)( lsmash_codec_specific_t *, lsmash_codec_specific_t * ) = NULL;
731 for( int i = 0; codec_specific_format_constructor_table[i].constructor; i++ )
732 if( specific->type == codec_specific_format_constructor_table[i].data_type )
734 constructor = codec_specific_format_constructor_table[i].constructor;
735 break;
737 if( constructor && !constructor( dst, specific ) )
738 return dst;
740 fail:
741 lsmash_destroy_codec_specific_data( dst );
742 return NULL;
745 static inline void isom_set_default_compressorname( char *compressorname, lsmash_codec_type_t sample_type )
747 static struct compressorname_table_tag
749 lsmash_codec_type_t type;
750 char name[33];
751 } compressorname_table[33] = { { LSMASH_CODEC_TYPE_INITIALIZER, { '\0' } } };
752 if( compressorname_table[0].name[0] == '\0' )
754 int i = 0;
755 #define ADD_COMPRESSORNAME_TABLE( type, name ) compressorname_table[i++] = (struct compressorname_table_tag){ type, name }
756 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_AVC1_VIDEO, "\012AVC Coding" );
757 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_AVC2_VIDEO, "\012AVC Coding" );
758 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_AVC3_VIDEO, "\012AVC Coding" );
759 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_AVC4_VIDEO, "\012AVC Coding" );
760 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_AVCP_VIDEO, "\016AVC Parameters" );
761 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_HVC1_VIDEO, "\013HEVC Coding" );
762 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_HEV1_VIDEO, "\013HEVC Coding" );
763 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_SVC1_VIDEO, "\012SVC Coding" );
764 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_MVC1_VIDEO, "\012MVC Coding" );
765 ADD_COMPRESSORNAME_TABLE( ISOM_CODEC_TYPE_MVC2_VIDEO, "\012MVC Coding" );
766 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_APCH_VIDEO, "\023Apple ProRes 422 (HQ)" );
767 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_APCN_VIDEO, "\023Apple ProRes 422 (SD)" );
768 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_APCS_VIDEO, "\023Apple ProRes 422 (LT)" );
769 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_APCO_VIDEO, "\026Apple ProRes 422 (Proxy)" );
770 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_AP4H_VIDEO, "\019Apple ProRes 4444" );
771 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_AP4X_VIDEO, "\022Apple ProRes 4444 XQ" );
772 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DVPP_VIDEO, "\014DVCPRO - PAL" );
773 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DV5N_VIDEO, "\017DVCPRO50 - NTSC" );
774 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DV5P_VIDEO, "\016DVCPRO50 - PAL" );
775 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DVH2_VIDEO, "\019DVCPRO HD 1080p25" );
776 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DVH3_VIDEO, "\019DVCPRO HD 1080p30" );
777 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DVH5_VIDEO, "\019DVCPRO HD 1080i50" );
778 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DVH6_VIDEO, "\019DVCPRO HD 1080i60" );
779 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DVHP_VIDEO, "\018DVCPRO HD 720p60" );
780 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_DVHQ_VIDEO, "\018DVCPRO HD 720p50" );
781 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_ULRA_VIDEO, "\017Ut Video (ULRA)" );
782 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_ULRG_VIDEO, "\017Ut Video (ULRG)" );
783 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_ULY0_VIDEO, "\017Ut Video (ULY0)" );
784 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_ULY2_VIDEO, "\017Ut Video (ULY2)" );
785 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_ULH0_VIDEO, "\017Ut Video (ULH0)" );
786 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_ULH2_VIDEO, "\017Ut Video (ULH2)" );
787 ADD_COMPRESSORNAME_TABLE( QT_CODEC_TYPE_UQY2_VIDEO, "\021Ut Video Pro (UQY2)" );
788 ADD_COMPRESSORNAME_TABLE( LSMASH_CODEC_TYPE_UNSPECIFIED, { '\0' } );
789 #undef ADD_COMPRESSORNAME_TABLE
791 for( int i = 0; compressorname_table[i].name[0] != '\0'; i++ )
792 if( lsmash_check_codec_type_identical( sample_type, compressorname_table[i].type ) )
794 strcpy( compressorname, compressorname_table[i].name );
795 return;
799 lsmash_codec_specific_t *isom_get_codec_specific( lsmash_codec_specific_list_t *opaque, lsmash_codec_specific_data_type type )
801 for( lsmash_entry_t *entry = opaque->list.head; entry; entry = entry->next )
803 lsmash_codec_specific_t *specific = (lsmash_codec_specific_t *)entry->data;
804 if( !specific || specific->type != type )
805 continue;
806 return specific;
808 return NULL;
811 static int isom_check_valid_summary( lsmash_summary_t *summary )
813 if( !summary )
814 return LSMASH_ERR_NAMELESS;
815 isom_box_t temp_box;
816 temp_box.type = summary->sample_type;
817 temp_box.manager = summary->summary_type == LSMASH_SUMMARY_TYPE_AUDIO ? LSMASH_AUDIO_DESCRIPTION: 0;
818 if( isom_is_lpcm_audio( &temp_box ) )
820 if( isom_get_codec_specific( summary->opaque, LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS ) )
821 return 0;
822 return LSMASH_ERR_INVALID_DATA;
824 if( isom_is_uncompressed_ycbcr( summary->sample_type ) )
826 if( isom_get_codec_specific( summary->opaque, LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_FIELD_INFO ) )
828 if( !lsmash_check_codec_type_identical( summary->sample_type, QT_CODEC_TYPE_V216_VIDEO ) )
829 return 0;
831 else
832 return LSMASH_ERR_INVALID_DATA;
834 lsmash_codec_type_t sample_type = summary->sample_type;
835 lsmash_codec_specific_data_type required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNSPECIFIED;
836 if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_AVC1_VIDEO )
837 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_AVC2_VIDEO )
838 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_AVC3_VIDEO )
839 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_AVC4_VIDEO ) )
840 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264;
841 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_HVC1_VIDEO )
842 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_HEV1_VIDEO ) )
843 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_HEVC;
844 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_VC_1_VIDEO ) )
845 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_VC_1 ;
846 else if( lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_ULRA_VIDEO )
847 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_ULRG_VIDEO )
848 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_ULY0_VIDEO )
849 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_ULY2_VIDEO )
850 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_ULH0_VIDEO )
851 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_ULH2_VIDEO )
852 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_UQY2_VIDEO ) )
853 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER;
854 else if( lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_V216_VIDEO ) )
855 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_SIGNIFICANT_BITS;
856 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_MP4V_VIDEO )
857 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_MP4A_AUDIO )
858 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_MP4A_AUDIO ) )
859 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG;
860 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_AC_3_AUDIO ) )
861 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_AC_3;
862 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_EC_3_AUDIO ) )
863 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_EC_3;
864 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_DTSC_AUDIO )
865 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_DTSE_AUDIO )
866 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_DTSH_AUDIO )
867 || lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_DTSL_AUDIO ) )
868 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS;
869 else if( lsmash_check_codec_type_identical( sample_type, ISOM_CODEC_TYPE_ALAC_AUDIO )
870 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_ALAC_AUDIO ) )
871 required_data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_ALAC;
872 if( required_data_type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNSPECIFIED )
873 return 0;
874 return isom_get_codec_specific( summary->opaque, required_data_type ) ? 0 : LSMASH_ERR_INVALID_DATA;
877 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 )
879 lsmash_box_type_t box_type = LSMASH_BOX_TYPE_INITIALIZER;
880 box_type.fourcc = fourcc;
881 #define GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( codec_type, predefined_box_type ) \
882 else if( (codec_type.user.fourcc == 0 \
883 || lsmash_check_codec_type_identical( active_codec_type, codec_type )) \
884 && box_type.fourcc == predefined_box_type.fourcc ) \
885 box_type = predefined_box_type
886 if( 0 );
887 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_AVC1_VIDEO, ISOM_BOX_TYPE_AVCC );
888 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_AVC2_VIDEO, ISOM_BOX_TYPE_AVCC );
889 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_AVC3_VIDEO, ISOM_BOX_TYPE_AVCC );
890 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_AVC4_VIDEO, ISOM_BOX_TYPE_AVCC );
891 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_AVCP_VIDEO, ISOM_BOX_TYPE_AVCC );
892 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_HVC1_VIDEO, ISOM_BOX_TYPE_HVCC );
893 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_HEV1_VIDEO, ISOM_BOX_TYPE_HVCC );
894 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_VC_1_VIDEO, ISOM_BOX_TYPE_DVC1 );
895 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_MP4V_VIDEO, ISOM_BOX_TYPE_ESDS );
896 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, ISOM_BOX_TYPE_BTRT );
897 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, QT_BOX_TYPE_FIEL );
898 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, QT_BOX_TYPE_CSPC );
899 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, QT_BOX_TYPE_SGBT );
900 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, QT_BOX_TYPE_GAMA );
901 GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, QT_BOX_TYPE_GLBL );
902 #undef GUESS_VIDEO_CODEC_SPECIFIC_BOX_TYPE
903 return box_type;
906 int isom_setup_visual_description( isom_stsd_t *stsd, lsmash_codec_type_t sample_type, lsmash_video_summary_t *summary )
908 if( !summary
909 || !stsd
910 || !stsd->parent
911 || !stsd->parent->parent
912 || !stsd->parent->parent->parent
913 || !stsd->parent->parent->parent->parent )
914 return LSMASH_ERR_NAMELESS;
915 int err = isom_check_valid_summary( (lsmash_summary_t *)summary );
916 if( err < 0 )
917 return err;
918 isom_visual_entry_t *visual = isom_add_visual_description( stsd, sample_type );
919 if( !visual )
920 return LSMASH_ERR_NAMELESS;
921 visual->data_reference_index = summary->data_ref_index;
922 visual->version = 0;
923 visual->revision_level = 0;
924 visual->vendor = 0;
925 visual->temporalQuality = 0;
926 visual->spatialQuality = 0;
927 visual->width = (uint16_t)summary->width;
928 visual->height = (uint16_t)summary->height;
929 visual->horizresolution = 0x00480000;
930 visual->vertresolution = 0x00480000;
931 visual->dataSize = 0;
932 visual->frame_count = 1;
933 visual->depth = isom_is_qt_video( summary->sample_type ) || isom_is_nalff( summary->sample_type )
934 ? summary->depth : 0x0018;
935 visual->color_table_ID = -1;
936 if( summary->compressorname[0] == '\0' )
937 isom_set_default_compressorname( visual->compressorname, sample_type );
938 else
940 memcpy( visual->compressorname, summary->compressorname, 32 );
941 visual->compressorname[32] = '\0';
943 err = LSMASH_ERR_NAMELESS;
944 for( lsmash_entry_t *entry = summary->opaque->list.head; entry; entry = entry->next )
946 lsmash_codec_specific_t *specific = (lsmash_codec_specific_t *)entry->data;
947 if( !specific )
948 goto fail;
949 if( specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN
950 && specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
951 continue; /* LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN + LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED is not supported. */
952 switch( specific->type )
954 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_COMMON :
956 if( specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED )
957 continue;
958 lsmash_qt_video_common_t *data = (lsmash_qt_video_common_t *)specific->data.structured;
959 visual->revision_level = data->revision_level;
960 visual->vendor = data->vendor;
961 visual->temporalQuality = data->temporalQuality;
962 visual->spatialQuality = data->spatialQuality;
963 visual->horizresolution = data->horizontal_resolution;
964 visual->vertresolution = data->vertical_resolution;
965 visual->dataSize = data->dataSize;
966 visual->frame_count = data->frame_count;
967 visual->color_table_ID = data->color_table_ID;
968 if( data->color_table_ID == 0 )
970 lsmash_qt_color_table_t *src_ct = &data->color_table;
971 uint16_t element_count = LSMASH_MIN( src_ct->size + 1, 256 );
972 isom_qt_color_array_t *dst_array = lsmash_malloc_zero( element_count * sizeof(isom_qt_color_array_t) );
973 if( !dst_array )
975 err = LSMASH_ERR_MEMORY_ALLOC;
976 goto fail;
978 isom_qt_color_table_t *dst_ct = &visual->color_table;
979 dst_ct->array = dst_array;
980 dst_ct->seed = src_ct->seed;
981 dst_ct->flags = src_ct->flags;
982 dst_ct->size = src_ct->size;
983 for( uint16_t i = 0; i < element_count; i++ )
985 dst_array[i].value = src_ct->array[i].unused;
986 dst_array[i].r = src_ct->array[i].r;
987 dst_array[i].g = src_ct->array[i].g;
988 dst_array[i].b = src_ct->array[i].b;
991 break;
993 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_SAMPLE_SCALE :
995 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
996 if( !cs )
997 goto fail;
998 lsmash_isom_sample_scale_t *data = (lsmash_isom_sample_scale_t *)cs->data.structured;
999 isom_stsl_t *stsl = isom_add_stsl( visual );
1000 if( !stsl )
1002 lsmash_destroy_codec_specific_data( cs );
1003 goto fail;
1005 stsl->constraint_flag = data->constraint_flag;
1006 stsl->scale_method = data->scale_method;
1007 stsl->display_center_x = data->display_center_x;
1008 stsl->display_center_y = data->display_center_y;
1009 lsmash_destroy_codec_specific_data( cs );
1010 break;
1012 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264_BITRATE :
1014 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
1015 if( !cs )
1016 goto fail;
1017 lsmash_h264_bitrate_t *data = (lsmash_h264_bitrate_t *)cs->data.structured;
1018 isom_btrt_t *btrt = isom_add_btrt( visual );
1019 if( !btrt )
1021 lsmash_destroy_codec_specific_data( cs );
1022 goto fail;
1024 btrt->bufferSizeDB = data->bufferSizeDB;
1025 btrt->maxBitrate = data->maxBitrate;
1026 btrt->avgBitrate = data->avgBitrate;
1027 lsmash_destroy_codec_specific_data( cs );
1028 break;
1030 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_FIELD_INFO :
1032 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
1033 if( !cs )
1034 goto fail;
1035 lsmash_qt_field_info_t *data = (lsmash_qt_field_info_t *)cs->data.structured;
1036 isom_fiel_t *fiel = isom_add_fiel( visual );
1037 if( !fiel )
1039 lsmash_destroy_codec_specific_data( cs );
1040 goto fail;
1042 fiel->fields = data->fields;
1043 fiel->detail = data->detail;
1044 lsmash_destroy_codec_specific_data( cs );
1045 break;
1047 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_PIXEL_FORMAT :
1049 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
1050 if( !cs )
1051 goto fail;
1052 lsmash_qt_pixel_format_t *data = (lsmash_qt_pixel_format_t *)cs->data.structured;
1053 isom_cspc_t *cspc = isom_add_cspc( visual );
1054 if( !cspc )
1056 lsmash_destroy_codec_specific_data( cs );
1057 goto fail;
1059 cspc->pixel_format = data->pixel_format;
1060 lsmash_destroy_codec_specific_data( cs );
1061 break;
1063 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_SIGNIFICANT_BITS :
1065 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
1066 if( !cs )
1067 goto fail;
1068 lsmash_qt_significant_bits_t *data = (lsmash_qt_significant_bits_t *)cs->data.structured;
1069 isom_sgbt_t *sgbt = isom_add_sgbt( visual );
1070 if( !sgbt )
1072 lsmash_destroy_codec_specific_data( cs );
1073 goto fail;
1075 sgbt->significantBits = data->significantBits;
1076 lsmash_destroy_codec_specific_data( cs );
1077 break;
1079 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_GAMMA_LEVEL :
1081 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
1082 if( !cs )
1083 goto fail;
1084 lsmash_qt_gamma_t *data = (lsmash_qt_gamma_t *)cs->data.structured;
1085 isom_gama_t *gama = isom_add_gama( visual );
1086 if( !gama )
1088 lsmash_destroy_codec_specific_data( cs );
1089 goto fail;
1091 gama->level = data->level;
1092 lsmash_destroy_codec_specific_data( cs );
1093 break;
1095 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER :
1097 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
1098 if( !cs )
1099 goto fail;
1100 lsmash_codec_global_header_t *data = (lsmash_codec_global_header_t *)cs->data.structured;
1101 isom_glbl_t *glbl = isom_add_glbl( visual );
1102 if( !glbl )
1104 lsmash_destroy_codec_specific_data( cs );
1105 goto fail;
1107 glbl->header_size = data->header_size;
1108 glbl->header_data = lsmash_memdup( data->header_data, data->header_size );
1109 lsmash_destroy_codec_specific_data( cs );
1110 if( !glbl->header_data )
1112 isom_remove_box_by_itself( glbl );
1113 err = LSMASH_ERR_MEMORY_ALLOC;
1114 goto fail;
1116 break;
1118 default :
1120 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
1121 if( !cs )
1122 goto fail;
1123 if( cs->size < ISOM_BASEBOX_COMMON_SIZE )
1125 lsmash_destroy_codec_specific_data( cs );
1126 err = LSMASH_ERR_INVALID_DATA;
1127 goto fail;
1129 uint8_t *data = cs->data.unstructured;
1130 lsmash_compact_box_type_t fourcc = LSMASH_4CC( data[4], data[5], data[6], data[7] );
1131 lsmash_box_type_t box_type = isom_guess_video_codec_specific_box_type( visual->type, fourcc );
1132 /* Append the extension. */
1133 err = isom_add_extension_binary( visual, box_type, LSMASH_BOX_PRECEDENCE_HM, cs->data.unstructured, cs->size );
1134 cs->data.unstructured = NULL; /* Avoid freeing the binary data of the extension. */
1135 lsmash_destroy_codec_specific_data( cs );
1136 if( err < 0 )
1137 goto fail;
1138 break;
1142 isom_trak_t *trak = (isom_trak_t *)visual->parent->parent->parent->parent->parent;
1143 int qt_compatible = trak->file->qt_compatible;
1144 isom_tapt_t *tapt = trak->tapt;
1145 isom_stsl_t *stsl = (isom_stsl_t *)isom_get_extension_box_format( &visual->extensions, ISOM_BOX_TYPE_STSL );
1146 int set_aperture_modes = qt_compatible /* Track Aperture Modes is only available under QuickTime file format. */
1147 && (!stsl || stsl->scale_method == 0) /* Sample scaling method might conflict with this feature. */
1148 && tapt && tapt->clef && tapt->prof && tapt->enof /* Check if required boxes exist. */
1149 && ((isom_stsd_t *)visual->parent)->list.entry_count == 1; /* Multiple sample description might conflict with this, so in that case, disable this feature. */
1150 if( !set_aperture_modes )
1151 isom_remove_box_by_itself( trak->tapt );
1152 int uncompressed_ycbcr = qt_compatible && isom_is_uncompressed_ycbcr( visual->type );
1153 /* Set up Clean Aperture. */
1154 if( set_aperture_modes || uncompressed_ycbcr
1155 || (summary->clap.width.d && summary->clap.height.d && summary->clap.horizontal_offset.d && summary->clap.vertical_offset.d) )
1157 isom_clap_t *clap = isom_add_clap( visual );
1158 if( !clap )
1159 goto fail;
1160 if( summary->clap.width.d && summary->clap.height.d && summary->clap.horizontal_offset.d && summary->clap.vertical_offset.d )
1162 clap->cleanApertureWidthN = summary->clap.width.n;
1163 clap->cleanApertureWidthD = summary->clap.width.d;
1164 clap->cleanApertureHeightN = summary->clap.height.n;
1165 clap->cleanApertureHeightD = summary->clap.height.d;
1166 clap->horizOffN = summary->clap.horizontal_offset.n;
1167 clap->horizOffD = summary->clap.horizontal_offset.d;
1168 clap->vertOffN = summary->clap.vertical_offset.n;
1169 clap->vertOffD = summary->clap.vertical_offset.d;
1171 else
1173 clap->cleanApertureWidthN = summary->width;
1174 clap->cleanApertureWidthD = 1;
1175 clap->cleanApertureHeightN = summary->height;
1176 clap->cleanApertureHeightD = 1;
1177 clap->horizOffN = 0;
1178 clap->horizOffD = 1;
1179 clap->vertOffN = 0;
1180 clap->vertOffD = 1;
1183 /* Set up Pixel Aspect Ratio. */
1184 if( set_aperture_modes || (summary->par_h && summary->par_v) )
1186 isom_pasp_t *pasp = isom_add_pasp( visual );
1187 if( !pasp )
1188 goto fail;
1189 pasp->hSpacing = LSMASH_MAX( summary->par_h, 1 );
1190 pasp->vSpacing = LSMASH_MAX( summary->par_v, 1 );
1192 /* Set up Color Parameter. */
1193 if( uncompressed_ycbcr
1194 || summary->color.primaries_index
1195 || summary->color.transfer_index
1196 || summary->color.matrix_index
1197 || (trak->file->isom_compatible && summary->color.full_range) )
1199 isom_colr_t *colr = isom_add_colr( visual );
1200 if( !colr )
1201 goto fail;
1202 /* Set 'nclc' to parameter type, we don't support 'prof'. */
1203 uint16_t primaries = summary->color.primaries_index;
1204 uint16_t transfer = summary->color.transfer_index;
1205 uint16_t matrix = summary->color.matrix_index;
1206 if( qt_compatible && !trak->file->isom_compatible )
1208 colr->manager |= LSMASH_QTFF_BASE;
1209 colr->type = QT_BOX_TYPE_COLR;
1210 colr->color_parameter_type = QT_COLOR_PARAMETER_TYPE_NCLC;
1211 colr->primaries_index = (primaries == 1 || primaries == 5 || primaries == 6)
1212 ? primaries : QT_PRIMARIES_INDEX_UNSPECIFIED;
1213 colr->transfer_function_index = (transfer == 1 || transfer == 7)
1214 ? transfer : QT_TRANSFER_INDEX_UNSPECIFIED;
1215 colr->matrix_index = (matrix == 1 || matrix == 6 || matrix == 7)
1216 ? matrix : QT_MATRIX_INDEX_UNSPECIFIED;
1218 else
1220 colr->type = ISOM_BOX_TYPE_COLR;
1221 colr->color_parameter_type = ISOM_COLOR_PARAMETER_TYPE_NCLX;
1222 colr->primaries_index = (primaries == 1 || (primaries >= 4 && primaries <= 7))
1223 ? primaries : ISOM_PRIMARIES_INDEX_UNSPECIFIED;
1224 colr->transfer_function_index = (transfer == 1 || (transfer >= 4 && transfer <= 8) || (transfer >= 11 && transfer <= 13))
1225 ? transfer : ISOM_TRANSFER_INDEX_UNSPECIFIED;
1226 colr->matrix_index = (matrix == 1 || (matrix >= 4 && matrix <= 8))
1227 ? matrix : ISOM_MATRIX_INDEX_UNSPECIFIED;
1228 colr->full_range_flag = summary->color.full_range;
1231 /* Set up Track Apeture Modes. */
1232 if( set_aperture_modes )
1234 uint32_t width = visual->width << 16;
1235 uint32_t height = visual->height << 16;
1236 isom_clap_t *clap = (isom_clap_t *)isom_get_extension_box_format( &visual->extensions, ISOM_BOX_TYPE_CLAP );
1237 isom_pasp_t *pasp = (isom_pasp_t *)isom_get_extension_box_format( &visual->extensions, ISOM_BOX_TYPE_PASP );
1238 double clap_width = ((double)clap->cleanApertureWidthN / clap->cleanApertureWidthD) * (1<<16);
1239 double clap_height = ((double)clap->cleanApertureHeightN / clap->cleanApertureHeightD) * (1<<16);
1240 double par = (double)pasp->hSpacing / pasp->vSpacing;
1241 if( par >= 1.0 )
1243 tapt->clef->width = clap_width * par;
1244 tapt->clef->height = clap_height;
1245 tapt->prof->width = width * par;
1246 tapt->prof->height = height;
1248 else
1250 tapt->clef->width = clap_width;
1251 tapt->clef->height = clap_height / par;
1252 tapt->prof->width = width;
1253 tapt->prof->height = height / par;
1255 tapt->enof->width = width;
1256 tapt->enof->height = height;
1258 return 0;
1259 fail:
1260 isom_remove_box_by_itself( visual );
1261 return err;
1264 static int isom_append_audio_es_descriptor_extension( isom_box_t *box, lsmash_audio_summary_t *summary )
1266 uint32_t esds_size = 0;
1267 uint8_t *esds_data = NULL;
1268 lsmash_codec_specific_t *specific = isom_get_codec_specific( summary->opaque, LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG );
1269 if( !specific )
1270 return LSMASH_ERR_NAMELESS;
1271 if( specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED )
1273 esds_size = specific->size;
1274 esds_data = lsmash_memdup( specific->data.unstructured, specific->size );
1275 if( !esds_data )
1276 return LSMASH_ERR_MEMORY_ALLOC;
1278 else
1280 esds_data = lsmash_create_mp4sys_decoder_config( (lsmash_mp4sys_decoder_parameters_t *)specific->data.structured, &esds_size );
1281 if( !esds_data )
1282 return LSMASH_ERR_NAMELESS;
1284 isom_esds_t *esds = isom_add_esds( box );
1285 if( !esds )
1287 lsmash_free( esds_data );
1288 return LSMASH_ERR_NAMELESS;
1290 lsmash_bs_t bs = { 0 };
1291 bs.buffer.data = esds_data + ISOM_FULLBOX_COMMON_SIZE;
1292 bs.buffer.alloc = esds_size - ISOM_FULLBOX_COMMON_SIZE;
1293 bs.buffer.store = bs.buffer.alloc;
1294 esds->ES = mp4sys_get_descriptor( &bs, NULL );
1295 lsmash_free( esds_data );
1296 if( !esds->ES )
1298 isom_remove_box_by_itself( esds );
1299 return LSMASH_ERR_NAMELESS;
1301 return 0;
1304 static int isom_append_channel_layout_extension( lsmash_codec_specific_t *specific, void *parent, uint32_t channels )
1306 assert( parent );
1307 if( isom_get_extension_box( &((isom_box_t *)parent)->extensions, QT_BOX_TYPE_CHAN ) )
1308 return 0; /* Audio Channel Layout Box is already present. */
1309 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
1310 if( !cs )
1311 return LSMASH_ERR_NAMELESS;
1312 lsmash_qt_audio_channel_layout_t *data = (lsmash_qt_audio_channel_layout_t *)cs->data.structured;
1313 lsmash_channel_layout_tag channelLayoutTag = data->channelLayoutTag;
1314 lsmash_channel_bitmap channelBitmap = data->channelBitmap;
1315 if( channelLayoutTag == QT_CHANNEL_LAYOUT_USE_CHANNEL_DESCRIPTIONS /* We don't support the feature of Channel Descriptions. */
1316 || (channelLayoutTag == QT_CHANNEL_LAYOUT_USE_CHANNEL_BITMAP && (!channelBitmap || channelBitmap > QT_CHANNEL_BIT_FULL)) )
1318 channelLayoutTag = QT_CHANNEL_LAYOUT_UNKNOWN | channels;
1319 channelBitmap = 0;
1321 lsmash_destroy_codec_specific_data( cs );
1322 /* Don't create Audio Channel Layout Box if the channel layout is unknown. */
1323 if( (channelLayoutTag ^ QT_CHANNEL_LAYOUT_UNKNOWN) >> 16 )
1325 isom_chan_t *chan = isom_add_chan( parent );
1326 if( !chan )
1327 return LSMASH_ERR_NAMELESS;
1328 chan->channelLayoutTag = channelLayoutTag;
1329 chan->channelBitmap = channelBitmap;
1330 chan->numberChannelDescriptions = 0;
1331 chan->channelDescriptions = NULL;
1333 return 0;
1336 static int isom_set_qtff_mp4a_description( isom_audio_entry_t *audio, lsmash_audio_summary_t *summary )
1338 isom_wave_t *wave = isom_add_wave( audio );
1339 isom_frma_t *frma;
1340 if( !(frma = isom_add_frma( wave ))
1341 || !isom_add_mp4a( wave )
1342 || !isom_add_terminator( wave ) )
1344 lsmash_remove_entry_tail( &audio->extensions, wave->destruct );
1345 return LSMASH_ERR_NAMELESS;
1347 frma->data_format = audio->type.fourcc;
1348 /* Add ES Descriptor Box. */
1349 int err = isom_append_audio_es_descriptor_extension( (isom_box_t *)wave, summary );
1350 if( err < 0 )
1351 return err;
1352 /* */
1353 audio->type = QT_CODEC_TYPE_MP4A_AUDIO;
1354 audio->version = (summary->channels > 2 || summary->frequency > UINT16_MAX) ? 2 : 1;
1355 audio->channelcount = audio->version == 2 ? 3 : LSMASH_MIN( summary->channels, 2 );
1356 audio->samplesize = 16;
1357 audio->compression_ID = QT_AUDIO_COMPRESSION_ID_VARIABLE_COMPRESSION;
1358 audio->packet_size = 0;
1359 if( audio->version == 1 )
1361 audio->samplerate = summary->frequency << 16;
1362 audio->samplesPerPacket = summary->samples_in_frame;
1363 audio->bytesPerPacket = 1; /* Apparently, this field is set to 1. */
1364 audio->bytesPerFrame = audio->bytesPerPacket * summary->channels;
1365 audio->bytesPerSample = 2;
1367 else /* audio->version == 2 */
1369 audio->samplerate = 0x00010000;
1370 audio->sizeOfStructOnly = 72;
1371 audio->audioSampleRate = (union {double d; uint64_t i;}){summary->frequency}.i;
1372 audio->numAudioChannels = summary->channels;
1373 audio->always7F000000 = 0x7F000000;
1374 audio->constBitsPerChannel = 0; /* compressed audio */
1375 audio->formatSpecificFlags = 0;
1376 audio->constBytesPerAudioPacket = 0; /* variable */
1377 audio->constLPCMFramesPerAudioPacket = summary->samples_in_frame;
1379 return 0;
1382 static int isom_set_isom_mp4a_description( isom_audio_entry_t *audio, lsmash_audio_summary_t *summary )
1384 if( summary->summary_type != LSMASH_SUMMARY_TYPE_AUDIO )
1385 return LSMASH_ERR_NAMELESS;
1386 /* Check objectTypeIndication. */
1387 lsmash_mp4sys_object_type_indication objectTypeIndication = lsmash_mp4sys_get_object_type_indication( (lsmash_summary_t *)summary );
1388 switch( objectTypeIndication )
1390 case MP4SYS_OBJECT_TYPE_Audio_ISO_14496_3:
1391 case MP4SYS_OBJECT_TYPE_Audio_ISO_13818_7_Main_Profile:
1392 case MP4SYS_OBJECT_TYPE_Audio_ISO_13818_7_LC_Profile:
1393 case MP4SYS_OBJECT_TYPE_Audio_ISO_13818_7_SSR_Profile:
1394 case MP4SYS_OBJECT_TYPE_Audio_ISO_13818_3: /* Legacy Interface */
1395 case MP4SYS_OBJECT_TYPE_Audio_ISO_11172_3: /* Legacy Interface */
1396 break;
1397 default:
1398 return LSMASH_ERR_NAMELESS;
1400 /* Add ES Descriptor Box. */
1401 int err = isom_append_audio_es_descriptor_extension( (isom_box_t *)audio, summary );
1402 if( err < 0 )
1403 return err;
1404 /* In pure mp4 file, these "template" fields shall be default values according to the spec.
1405 But not pure - hybrid with other spec - mp4 file can take other values.
1406 Which is to say, these template values shall be ignored in terms of mp4, except some object_type_indications.
1407 see 14496-14, "Template fields used". */
1408 audio->type = ISOM_CODEC_TYPE_MP4A_AUDIO;
1409 audio->version = 0;
1410 audio->revision_level = 0;
1411 audio->vendor = 0;
1412 audio->channelcount = 2;
1413 audio->samplesize = 16;
1414 audio->compression_ID = 0;
1415 audio->packet_size = 0;
1416 /* WARNING: This field cannot retain frequency above 65535Hz.
1417 This is not "FIXME", I just honestly implemented what the spec says.
1418 BTW, who ever expects sampling frequency takes fixed-point decimal??? */
1419 audio->samplerate = summary->frequency <= UINT16_MAX ? summary->frequency << 16 : 0;
1420 return 0;
1423 static int isom_set_qtff_lpcm_description( isom_audio_entry_t *audio, lsmash_audio_summary_t *summary )
1425 lsmash_qt_audio_format_specific_flags_t *lpcm = NULL;
1426 for( lsmash_entry_t *entry = summary->opaque->list.head; entry; entry = entry->next )
1428 lsmash_codec_specific_t *specific = (lsmash_codec_specific_t *)entry->data;
1429 if( !specific )
1430 continue;
1431 if( specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS
1432 && specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
1434 lpcm = (lsmash_qt_audio_format_specific_flags_t *)specific->data.structured;
1435 break;
1438 if( !lpcm )
1439 return LSMASH_ERR_NAMELESS;
1440 audio->manager |= LSMASH_QTFF_BASE;
1441 lsmash_codec_type_t sample_type = audio->type;
1442 /* Convert the sample type into 'lpcm' if the description doesn't match the format or version = 2 fields are needed. */
1443 if( (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_RAW_AUDIO )
1444 && (summary->sample_size != 8 || (lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT)))
1445 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_FL32_AUDIO )
1446 && (summary->sample_size != 32 || !(lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT)))
1447 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_FL64_AUDIO )
1448 && (summary->sample_size != 64 || !(lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT)))
1449 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_IN24_AUDIO )
1450 && (summary->sample_size != 24 || (lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT)))
1451 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_IN32_AUDIO )
1452 && (summary->sample_size != 32 || (lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT)))
1453 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_23NI_AUDIO )
1454 && (summary->sample_size != 32 || (lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT) || (lpcm->format_flags & QT_LPCM_FORMAT_FLAG_BIG_ENDIAN)))
1455 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_SOWT_AUDIO )
1456 && (summary->sample_size != 16 || (lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT) || (lpcm->format_flags & QT_LPCM_FORMAT_FLAG_BIG_ENDIAN)))
1457 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_TWOS_AUDIO )
1458 && ((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)))
1459 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_NONE_AUDIO )
1460 && ((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)))
1461 || (lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_NOT_SPECIFIED )
1462 && ((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)))
1463 || (summary->channels > 2 || summary->frequency > UINT16_MAX || summary->sample_size % 8) )
1465 audio->type = QT_CODEC_TYPE_LPCM_AUDIO;
1466 audio->version = 2;
1468 else if( lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_LPCM_AUDIO ) )
1469 audio->version = 2;
1470 else if( summary->sample_size > 16
1471 || (!lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_RAW_AUDIO )
1472 && !lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_TWOS_AUDIO )
1473 && !lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_NONE_AUDIO )
1474 && !lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_NOT_SPECIFIED )) )
1475 audio->version = 1;
1476 /* Set up constBytesPerAudioPacket field.
1477 * We use constBytesPerAudioPacket as the actual size of LPCM audio frame even when version is not 2. */
1478 audio->constBytesPerAudioPacket = (summary->sample_size * summary->channels) / 8;
1479 /* Set up other fields in this description by its version. */
1480 if( audio->version == 2 )
1482 audio->channelcount = 3;
1483 audio->samplesize = 16;
1484 audio->compression_ID = -2;
1485 audio->samplerate = 0x00010000;
1486 audio->sizeOfStructOnly = 72;
1487 audio->audioSampleRate = (union {double d; uint64_t i;}){summary->frequency}.i;
1488 audio->numAudioChannels = summary->channels;
1489 audio->always7F000000 = 0x7F000000;
1490 audio->constBitsPerChannel = summary->sample_size;
1491 audio->constLPCMFramesPerAudioPacket = 1;
1492 audio->formatSpecificFlags = lpcm->format_flags;
1493 if( lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_TWOS_AUDIO ) && summary->sample_size != 8 )
1494 audio->formatSpecificFlags |= QT_LPCM_FORMAT_FLAG_BIG_ENDIAN;
1495 if( lpcm->format_flags & QT_LPCM_FORMAT_FLAG_FLOAT )
1496 audio->formatSpecificFlags &= ~QT_LPCM_FORMAT_FLAG_SIGNED_INTEGER;
1497 if( lpcm->format_flags & QT_LPCM_FORMAT_FLAG_PACKED )
1498 audio->formatSpecificFlags &= ~QT_LPCM_FORMAT_FLAG_ALIGNED_HIGH;
1500 else if( audio->version == 1 )
1502 audio->channelcount = summary->channels;
1503 audio->samplesize = 16;
1504 /* Audio formats other than 'raw ' and 'twos' are treated as compressed audio. */
1505 if( lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_RAW_AUDIO )
1506 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_TWOS_AUDIO ) )
1507 audio->compression_ID = QT_AUDIO_COMPRESSION_ID_NOT_COMPRESSED;
1508 else
1509 audio->compression_ID = QT_AUDIO_COMPRESSION_ID_FIXED_COMPRESSION;
1510 audio->samplerate = summary->frequency << 16;
1511 audio->samplesPerPacket = 1;
1512 audio->bytesPerPacket = summary->sample_size / 8;
1513 audio->bytesPerFrame = audio->bytesPerPacket * summary->channels; /* sample_size field in stsz box is NOT used. */
1514 audio->bytesPerSample = 1 + (summary->sample_size != 8);
1515 if( lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_FL32_AUDIO )
1516 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_FL64_AUDIO )
1517 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_IN24_AUDIO )
1518 || lsmash_check_codec_type_identical( sample_type, QT_CODEC_TYPE_IN32_AUDIO ) )
1520 isom_wave_t *wave = isom_add_wave( audio );
1521 isom_frma_t *frma;
1522 isom_enda_t *enda;
1523 if( !(frma = isom_add_frma( wave ))
1524 || !(enda = isom_add_enda( wave ))
1525 || !isom_add_terminator( wave ) )
1527 lsmash_remove_entry_tail( &audio->extensions, wave->destruct );
1528 return LSMASH_ERR_NAMELESS;
1530 frma->data_format = sample_type.fourcc;
1531 enda->littleEndian = !(lpcm->format_flags & QT_LPCM_FORMAT_FLAG_BIG_ENDIAN);
1534 else /* audio->version == 0 */
1536 audio->channelcount = summary->channels;
1537 audio->samplesize = summary->sample_size;
1538 audio->compression_ID = QT_AUDIO_COMPRESSION_ID_NOT_COMPRESSED;
1539 audio->samplerate = summary->frequency << 16;
1541 return 0;
1544 static int isom_set_isom_dts_description( isom_audio_entry_t *audio, lsmash_audio_summary_t *summary )
1546 audio->version = 0;
1547 audio->revision_level = 0;
1548 audio->vendor = 0;
1549 audio->channelcount = summary->channels;
1550 audio->samplesize = 16;
1551 audio->compression_ID = 0;
1552 audio->packet_size = 0;
1553 switch( summary->frequency )
1555 case 12000 : /* Invalid? (No reference in the spec) */
1556 case 24000 :
1557 case 48000 :
1558 case 96000 :
1559 case 192000 :
1560 case 384000 : /* Invalid? (No reference in the spec) */
1561 audio->samplerate = 48000 << 16;
1562 break;
1563 case 22050 :
1564 case 44100 :
1565 case 88200 :
1566 case 176400 :
1567 case 352800 : /* Invalid? (No reference in the spec) */
1568 audio->samplerate = 44100 << 16;
1569 break;
1570 case 8000 : /* Invalid? (No reference in the spec) */
1571 case 16000 :
1572 case 32000 :
1573 case 64000 :
1574 case 128000 :
1575 audio->samplerate = 32000 << 16;
1576 break;
1577 default :
1578 audio->samplerate = 0;
1579 break;
1581 return 0;
1584 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 )
1586 lsmash_box_type_t box_type = LSMASH_BOX_TYPE_INITIALIZER;
1587 box_type.fourcc = fourcc;
1588 #define GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( codec_type, predefined_box_type ) \
1589 else if( (codec_type.user.fourcc == 0 \
1590 || lsmash_check_codec_type_identical( active_codec_type, codec_type )) \
1591 && box_type.fourcc == predefined_box_type.fourcc ) \
1592 box_type = predefined_box_type
1593 if( 0 );
1594 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_AC_3_AUDIO, ISOM_BOX_TYPE_DAC3 );
1595 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_EC_3_AUDIO, ISOM_BOX_TYPE_DEC3 );
1596 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_DTSC_AUDIO, ISOM_BOX_TYPE_DDTS );
1597 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_DTSE_AUDIO, ISOM_BOX_TYPE_DDTS );
1598 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_DTSH_AUDIO, ISOM_BOX_TYPE_DDTS );
1599 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_DTSL_AUDIO, ISOM_BOX_TYPE_DDTS );
1600 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_ALAC_AUDIO, ISOM_BOX_TYPE_ALAC );
1601 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( ISOM_CODEC_TYPE_MP4A_AUDIO, ISOM_BOX_TYPE_ESDS );
1602 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( QT_CODEC_TYPE_ALAC_AUDIO, QT_BOX_TYPE_ALAC );
1603 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( QT_CODEC_TYPE_MP4A_AUDIO, QT_BOX_TYPE_ESDS );
1604 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( QT_CODEC_TYPE_FULLMP3_AUDIO, QT_CODEC_TYPE_MP3_AUDIO );
1605 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( QT_CODEC_TYPE_ADPCM2_AUDIO, QT_CODEC_TYPE_ADPCM2_AUDIO );
1606 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( QT_CODEC_TYPE_ADPCM17_AUDIO, QT_CODEC_TYPE_ADPCM17_AUDIO );
1607 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( QT_CODEC_TYPE_GSM49_AUDIO, QT_CODEC_TYPE_GSM49_AUDIO );
1608 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, QT_BOX_TYPE_CHAN );
1609 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, QT_BOX_TYPE_GLBL );
1610 GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE( LSMASH_CODEC_TYPE_UNSPECIFIED, QT_BOX_TYPE_WAVE );
1611 #undef GUESS_AUDIO_CODEC_SPECIFIC_BOX_TYPE
1612 return box_type;
1615 typedef struct
1617 uint16_t wFormatTag;
1618 uint16_t nChannels;
1619 uint32_t nSamplesPerSec;
1620 uint32_t nAvgBytesPerSec;
1621 uint16_t nBlockAlign;
1622 uint16_t wBitsPerSample;
1623 uint16_t cbSize;
1624 } wave_format_ex_t;
1626 static lsmash_bs_t *isom_create_waveform_audio_info
1628 wave_format_ex_t *wfx,
1629 lsmash_box_type_t type
1632 lsmash_bs_t *bs = lsmash_bs_create();
1633 if( !bs )
1634 return NULL;
1635 lsmash_bs_put_be32( bs, ISOM_BASEBOX_COMMON_SIZE + 18 + wfx->cbSize );
1636 lsmash_bs_put_be32( bs, type.fourcc );
1637 lsmash_bs_put_le16( bs, wfx->wFormatTag );
1638 lsmash_bs_put_le16( bs, wfx->nChannels );
1639 lsmash_bs_put_le32( bs, wfx->nSamplesPerSec );
1640 lsmash_bs_put_le32( bs, wfx->nAvgBytesPerSec );
1641 lsmash_bs_put_le16( bs, wfx->nBlockAlign );
1642 lsmash_bs_put_le16( bs, wfx->wBitsPerSample );
1643 lsmash_bs_put_le16( bs, wfx->cbSize );
1644 return bs;
1647 static int isom_setup_waveform_audio_info
1649 isom_wave_t *wave,
1650 isom_audio_entry_t *audio,
1651 lsmash_audio_summary_t *summary,
1652 uint32_t samples_per_packet,
1653 uint32_t bytes_per_frame,
1654 uint32_t sample_size
1657 wave_format_ex_t wfx;
1658 wfx.wFormatTag = 0x0000; /* WAVE_FORMAT_UNKNOWN */
1659 wfx.nChannels = summary->channels;
1660 wfx.nSamplesPerSec = summary->frequency;
1661 wfx.nAvgBytesPerSec = 0;
1662 wfx.nBlockAlign = bytes_per_frame;
1663 wfx.wBitsPerSample = sample_size;
1664 wfx.cbSize = 0;
1665 lsmash_bs_t *bs = NULL;
1666 if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ADPCM2_AUDIO ) )
1668 /* ADPCMWAVEFORMAT */
1669 wfx.wFormatTag = 0x0002; /* WAVE_FORMAT_ADPCM */
1670 wfx.cbSize = 32;
1671 bs = isom_create_waveform_audio_info( &wfx, audio->type );
1672 if( !bs )
1673 return LSMASH_ERR_MEMORY_ALLOC;
1674 uint16_t wSamplesPerBlock = samples_per_packet; /* nBlockAlign * 2 / nChannels - 12 */
1675 uint16_t wNumCoef = 7; /* Microsoft ADPCM uses just 7 coefficients. */
1676 static const struct
1678 int16_t iCoef1;
1679 int16_t iCoef2;
1680 } aCoef[7] = { { 256, 0 }, { 512, -256 }, { 0,0 }, { 192,64 }, { 240,0 }, { 460, -208 }, { 392,-232 } };
1681 lsmash_bs_put_le16( bs, wSamplesPerBlock );
1682 lsmash_bs_put_le16( bs, wNumCoef );
1683 for( int i = 0; i < 7; i++ )
1685 lsmash_bs_put_le16( bs, aCoef[i].iCoef1 );
1686 lsmash_bs_put_le16( bs, aCoef[i].iCoef2 );
1689 else if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ADPCM17_AUDIO ) )
1691 /* IMAADPCMWAVEFORMAT */
1692 wfx.wFormatTag = 0x0011; /* WAVE_FORMAT_DVI_ADPCM / WAVE_FORMAT_IMA_ADPCM */
1693 wfx.cbSize = 2;
1694 bs = isom_create_waveform_audio_info( &wfx, audio->type );
1695 if( !bs )
1696 return LSMASH_ERR_MEMORY_ALLOC;
1697 uint16_t wSamplesPerBlock = samples_per_packet;
1698 lsmash_bs_put_le16( bs, wSamplesPerBlock );
1700 else if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_GSM49_AUDIO ) )
1702 /* GSM610WAVEFORMAT */
1703 wfx.wFormatTag = 0x0031; /* WAVE_FORMAT_GSM610 */
1704 wfx.cbSize = 2;
1705 bs = isom_create_waveform_audio_info( &wfx, audio->type );
1706 if( !bs )
1707 return LSMASH_ERR_MEMORY_ALLOC;
1708 uint16_t wSamplesPerBlock = samples_per_packet;
1709 lsmash_bs_put_le16( bs, wSamplesPerBlock );
1711 else if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_FULLMP3_AUDIO )
1712 || lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_MP3_AUDIO ) )
1714 /* MPEGLAYER3WAVEFORMAT */
1715 wfx.wFormatTag = 0x0055; /* WAVE_FORMAT_MPEGLAYER3 */
1716 wfx.nBlockAlign = 1; /* ? */
1717 wfx.wBitsPerSample = 0; /* undefined */
1718 wfx.cbSize = 12;
1719 bs = isom_create_waveform_audio_info( &wfx, audio->type );
1720 if( !bs )
1721 return LSMASH_ERR_MEMORY_ALLOC;
1722 uint16_t wID = 1; /* MPEGLAYER3_ID_MPEG */
1723 uint32_t fdwFlags = 0; /* We don't know whether the stream is padded or not here. */
1724 uint16_t nBlockSize = 0; /* (144 * (bitrate / nSamplesPerSec) + padding) * nFramesPerBlock */
1725 uint16_t nFramesPerBlock = 1; /* the number of audio frames per block */
1726 uint16_t nCodecDelay = 0; /* Encoder delay in samples is unknown. */
1727 lsmash_bs_put_le16( bs, wID );
1728 lsmash_bs_put_le32( bs, fdwFlags );
1729 lsmash_bs_put_le16( bs, nBlockSize );
1730 lsmash_bs_put_le16( bs, nFramesPerBlock );
1731 lsmash_bs_put_le16( bs, nCodecDelay );
1733 if( !bs )
1735 assert( 0 );
1736 return LSMASH_ERR_NAMELESS;
1738 uint32_t wfx_size;
1739 uint8_t *wfx_data = lsmash_bs_export_data( bs, &wfx_size );
1740 lsmash_bs_cleanup( bs );
1741 if( !wfx_data )
1742 return LSMASH_ERR_NAMELESS;
1743 if( wfx_size != ISOM_BASEBOX_COMMON_SIZE + 18 + wfx.cbSize )
1745 lsmash_free( wfx_data );
1746 return LSMASH_ERR_NAMELESS;
1748 int err = isom_add_extension_binary( wave, audio->type, LSMASH_BOX_PRECEDENCE_HM, wfx_data, wfx_size );
1749 if( err < 0 )
1751 lsmash_free( wfx_data );
1752 return err;
1754 return 0;
1757 static int isom_set_qtff_sound_decompression_parameters
1759 isom_audio_entry_t *audio,
1760 lsmash_audio_summary_t *summary,
1761 lsmash_qt_audio_format_specific_flag *format_flags,
1762 uint32_t samples_per_packet,
1763 uint32_t bytes_per_frame,
1764 uint32_t sample_size
1767 /* A 'wave' extension itself shall be absent in the opaque CODEC specific info list.
1768 * So, create a 'wave' extension here and append it as an extension to the audio sample description. */
1769 isom_wave_t *wave = isom_add_wave( audio );
1770 if( !isom_add_frma ( wave )
1771 || !isom_add_terminator( wave ) )
1773 lsmash_remove_entry_tail( &audio->extensions, wave->destruct );
1774 return LSMASH_ERR_NAMELESS;
1776 wave->frma->data_format = audio->type.fourcc;
1777 /* Append extensions from the opaque CODEC specific info list to 'wave' extension. */
1778 int err;
1779 int waveform_audio_info_present = 0;
1780 int requires_waveform_audio_info = isom_is_waveform_audio( audio->type );
1781 for( lsmash_entry_t *entry = summary->opaque->list.head; entry; entry = entry->next )
1783 lsmash_codec_specific_t *specific = (lsmash_codec_specific_t *)entry->data;
1784 if( !specific )
1785 return LSMASH_ERR_NAMELESS;
1786 if( specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN
1787 && specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
1788 continue; /* LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN + LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED is not supported. */
1789 switch( specific->type )
1791 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_COMMON :
1792 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER :
1793 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS :
1794 continue; /* These cannot be an extension for 'wave' extension. */
1795 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT :
1796 /* (Legacy?) ALAC might have an Audio Channel Layout Box inside 'wave' extension. */
1797 #if 1
1798 continue;
1799 #else
1800 if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ALAC_AUDIO ) )
1801 continue;
1802 if( (err = isom_append_channel_layout_extension( specific, wave, summary->channels )) < 0 )
1803 return err;
1804 break;
1805 #endif
1806 default :
1808 assert( specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED
1809 || specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_DECOMPRESSION_PARAMETERS );
1810 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
1811 if( !cs )
1812 return LSMASH_ERR_NAMELESS;
1813 if( cs->size < ISOM_BASEBOX_COMMON_SIZE )
1815 lsmash_destroy_codec_specific_data( cs );
1816 continue;
1818 uint8_t *box_data = cs->data.unstructured;
1819 uint64_t box_size = cs->size;
1820 lsmash_compact_box_type_t fourcc = LSMASH_4CC( box_data[4], box_data[5], box_data[6], box_data[7] );
1821 if( audio->version == 2 && fourcc == QT_BOX_TYPE_ENDA.fourcc )
1823 /* Don't append a 'enda' extension if version == 2.
1824 * Endianness is indicated in QuickTime audio format specific flags. */
1825 if( box_size >= ISOM_BASEBOX_COMMON_SIZE + 2 )
1827 /* Override endianness indicated in format specific flags. */
1828 if( box_data[9] == 1 )
1829 *format_flags &= ~QT_AUDIO_FORMAT_FLAG_BIG_ENDIAN;
1830 else
1831 *format_flags |= QT_AUDIO_FORMAT_FLAG_BIG_ENDIAN;
1833 lsmash_destroy_codec_specific_data( cs );
1834 continue;
1836 lsmash_box_type_t box_type = isom_guess_audio_codec_specific_box_type( audio->type, fourcc );
1837 if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_WAVE ) )
1839 /* It is insane to appened a 'wave' extension to a 'wave' extension. */
1840 lsmash_destroy_codec_specific_data( cs );
1841 continue;
1843 box_type = lsmash_form_qtff_box_type( box_type.fourcc );
1844 /* Determine 'precedence'. */
1845 uint64_t precedence;
1846 if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_FRMA ) )
1847 precedence = LSMASH_BOX_PRECEDENCE_QTFF_FRMA;
1848 else if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_ESDS ) )
1849 precedence = LSMASH_BOX_PRECEDENCE_QTFF_ESDS;
1850 else if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_ENDA ) )
1851 precedence = LSMASH_BOX_PRECEDENCE_QTFF_ENDA;
1852 else if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_MP4A ) )
1853 precedence = LSMASH_BOX_PRECEDENCE_QTFF_MP4A;
1854 else if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_TERMINATOR ) )
1855 precedence = LSMASH_BOX_PRECEDENCE_QTFF_TERMINATOR;
1856 else
1857 precedence = LSMASH_BOX_PRECEDENCE_HM;
1858 /* Append the extension. */
1859 err = isom_add_extension_binary( wave, box_type, precedence, cs->data.unstructured, cs->size );
1860 cs->data.unstructured = NULL; /* Avoid freeing the binary data of the extension. */
1861 lsmash_destroy_codec_specific_data( cs );
1862 if( err < 0 )
1863 return err;
1864 if( isom_is_waveform_audio( box_type ) )
1865 waveform_audio_info_present = 1;
1866 break;
1870 if( requires_waveform_audio_info && !waveform_audio_info_present
1871 && (err = isom_setup_waveform_audio_info( wave, audio, summary, samples_per_packet, bytes_per_frame, sample_size )) < 0 )
1872 return err;
1873 return 0;
1876 static int isom_set_qtff_template_audio_description( isom_audio_entry_t *audio, lsmash_audio_summary_t *summary )
1878 audio->manager |= LSMASH_QTFF_BASE;
1879 audio->type = lsmash_form_qtff_box_type( audio->type.fourcc );
1880 audio->version = (summary->channels > 2 || summary->frequency > UINT16_MAX) ? 2 : 1;
1881 /* Try to get QuickTime audio format specific flags. */
1882 lsmash_qt_audio_format_specific_flag format_flags = QT_AUDIO_FORMAT_FLAG_BIG_ENDIAN;
1883 for( lsmash_entry_t *entry = summary->opaque->list.head; entry; entry = entry->next )
1885 lsmash_codec_specific_t *specific = (lsmash_codec_specific_t *)entry->data;
1886 if( !specific
1887 || !specific->data.structured )
1888 continue;
1889 if( specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS
1890 && specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
1892 /* A format specific flags is found.
1893 * Force audio sample description version == 2. */
1894 format_flags = ((lsmash_qt_audio_format_specific_flags_t *)specific->data.structured)->format_flags;
1895 audio->version = 2;
1896 break;
1899 uint32_t samples_per_packet;
1900 uint32_t bytes_per_frame;
1901 uint32_t sample_size;
1902 if( !((summary->samples_in_frame == 0 || summary->bytes_per_frame == 0 || summary->sample_size == 0)
1903 && isom_get_implicit_qt_fixed_comp_audio_sample_quants( audio, &samples_per_packet, &bytes_per_frame, &sample_size )) )
1905 samples_per_packet = summary->samples_in_frame;
1906 bytes_per_frame = summary->bytes_per_frame;
1907 sample_size = summary->sample_size;
1909 if( !lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_MAC3_AUDIO )
1910 && !lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_MAC6_AUDIO )
1911 && !lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_AGSM_AUDIO )
1912 && !lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ALAW_AUDIO )
1913 && !lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ULAW_AUDIO ) )
1915 int err = isom_set_qtff_sound_decompression_parameters( audio, summary, &format_flags,
1916 samples_per_packet, bytes_per_frame, sample_size );
1917 if( err < 0 )
1918 return err;
1920 /* Set up common audio description fields. */
1921 audio->samplesize = 16;
1922 audio->packet_size = 0;
1923 if( audio->version == 2 )
1925 audio->channelcount = 3;
1926 audio->compression_ID = QT_AUDIO_COMPRESSION_ID_VARIABLE_COMPRESSION;
1927 audio->samplerate = 0x00010000;
1928 audio->sizeOfStructOnly = 72;
1929 audio->audioSampleRate = (union {double d; uint64_t i;}){summary->frequency}.i;
1930 audio->numAudioChannels = summary->channels;
1931 audio->always7F000000 = 0x7F000000;
1932 audio->constBitsPerChannel = 0;
1933 audio->constBytesPerAudioPacket = bytes_per_frame;
1934 audio->constLPCMFramesPerAudioPacket = samples_per_packet;
1935 if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ALAC_AUDIO ) )
1937 switch( sample_size )
1939 case 16 :
1940 audio->formatSpecificFlags = QT_ALAC_FORMAT_FLAG_16BIT_SOURCE_DATA;
1941 break;
1942 case 20 :
1943 audio->formatSpecificFlags = QT_ALAC_FORMAT_FLAG_20BIT_SOURCE_DATA;
1944 break;
1945 case 24 :
1946 audio->formatSpecificFlags = QT_ALAC_FORMAT_FLAG_24BIT_SOURCE_DATA;
1947 break;
1948 case 32 :
1949 audio->formatSpecificFlags = QT_ALAC_FORMAT_FLAG_32BIT_SOURCE_DATA;
1950 break;
1951 default :
1952 break;
1955 else
1957 if( format_flags & QT_AUDIO_FORMAT_FLAG_FLOAT )
1958 format_flags &= ~QT_AUDIO_FORMAT_FLAG_SIGNED_INTEGER;
1959 if( format_flags & QT_AUDIO_FORMAT_FLAG_PACKED )
1960 format_flags &= ~QT_AUDIO_FORMAT_FLAG_ALIGNED_HIGH;
1961 audio->formatSpecificFlags = format_flags;
1964 else /* if( audio->version == 1 ) */
1966 audio->channelcount = LSMASH_MIN( summary->channels, 2 );
1967 audio->compression_ID = QT_AUDIO_COMPRESSION_ID_FIXED_COMPRESSION;
1968 audio->samplerate = summary->frequency << 16;
1969 audio->samplesPerPacket = samples_per_packet;
1970 audio->bytesPerPacket = bytes_per_frame / summary->channels;
1971 audio->bytesPerFrame = bytes_per_frame; /* sample_size field in stsz box is NOT used. */
1972 audio->bytesPerSample = 1 + (sample_size != 8);
1974 return 0;
1977 static void isom_set_samplerate_division_of_media_timescale( isom_audio_entry_t *audio, int strict )
1979 if( audio->parent /* stsd */
1980 && audio->parent->parent /* stbl */
1981 && audio->parent->parent->parent /* minf */
1982 && audio->parent->parent->parent->parent /* mdia */
1983 && lsmash_check_box_type_identical( audio->parent->parent->parent->parent->type, ISOM_BOX_TYPE_MDIA )
1984 && ((isom_mdia_t *)audio->parent->parent->parent->parent)->mdhd )
1986 /* Make an effort to match the timescale with samplerate, or be an integer multiple of it. */
1987 uint32_t orig_timescale = ((isom_mdia_t *)audio->parent->parent->parent->parent)->mdhd->timescale;
1988 uint32_t timescale = orig_timescale;
1989 uint32_t i = 2;
1990 while( timescale > UINT16_MAX && timescale > 1 )
1992 if( timescale % i == 0 )
1993 timescale /= i;
1994 else
1995 i += i > 2 ? 2 : 1;
1997 if( timescale != orig_timescale && strict )
1998 lsmash_log( NULL, LSMASH_LOG_WARNING, "samplerate does not match the media timescale.\n" );
1999 if( timescale <= UINT16_MAX && timescale > 1 )
2001 audio->samplerate = timescale << 16;
2002 return;
2005 audio->samplerate = 0;
2008 static int isom_set_isom_template_audio_description( isom_audio_entry_t *audio, lsmash_audio_summary_t *summary )
2010 audio->version = 0; /* reserved */
2011 audio->revision_level = 0; /* reserved */
2012 audio->vendor = 0; /* reserved */
2013 audio->channelcount = 2; /* template */
2014 audio->samplesize = 16; /* template */
2015 audio->compression_ID = 0; /* pre_defined */
2016 audio->packet_size = 0; /* reserved */
2017 /* template : default output audio sampling rate at playback */
2018 if( summary->frequency <= UINT16_MAX )
2019 audio->samplerate = summary->frequency << 16;
2020 else
2021 isom_set_samplerate_division_of_media_timescale( audio, 0 );
2022 return 0;
2025 static int isom_set_isom_amr_audio_description( isom_audio_entry_t *audio, int wb )
2027 /* For AMR-NB and AMR-WB stream, these fields are not meaningful. */
2028 audio->version = 0; /* always 0 */
2029 audio->revision_level = 0; /* always 0 */
2030 audio->vendor = 0; /* always 0 */
2031 audio->channelcount = 2; /* always 2 although the actual number of channels is always 1 */
2032 audio->samplesize = 16; /* always 16 */
2033 audio->compression_ID = 0; /* always 0 */
2034 audio->packet_size = 0; /* always 0 */
2035 /* Set samplerate by trying to copy from Media Header Box of this media though the
2036 * actual samplerate is 8000 Hz for AMR-NB and 16000 Hz for AMR-WB.
2037 * 3GPP and 3GPP2 has no restriction for media timescale. Therefore, users should
2038 * set suitable media timescale by themselves within the bounds of common sense. */
2039 isom_set_samplerate_division_of_media_timescale( audio, 1 );
2040 if( audio->samplerate == 0 )
2041 /* Set hard-coded but correct samplerate in the CODEC level. */
2042 audio->samplerate = wb ? 8000 : 16000;
2043 return 0;
2046 int isom_setup_audio_description( isom_stsd_t *stsd, lsmash_codec_type_t sample_type, lsmash_audio_summary_t *summary )
2048 if( !stsd || !stsd->file || !summary )
2049 return LSMASH_ERR_NAMELESS;
2050 int err = isom_check_valid_summary( (lsmash_summary_t *)summary );
2051 if( err < 0 )
2052 return err;
2053 isom_audio_entry_t *audio = isom_add_audio_description( stsd, sample_type );
2054 if( !audio )
2055 return LSMASH_ERR_NAMELESS;
2056 audio->data_reference_index = summary->data_ref_index;
2057 lsmash_file_t *file = stsd->file;
2058 lsmash_codec_type_t audio_type = audio->type;
2059 if( lsmash_check_codec_type_identical( audio_type, ISOM_CODEC_TYPE_MP4A_AUDIO )
2060 || lsmash_check_codec_type_identical( audio_type, QT_CODEC_TYPE_MP4A_AUDIO ) )
2062 if( (file->ftyp && file->ftyp->major_brand == ISOM_BRAND_TYPE_QT)
2063 || (!file->ftyp && (file->qt_compatible || (file->moov && !file->moov->iods))) )
2064 err = isom_set_qtff_mp4a_description( audio, summary );
2065 else
2066 err = isom_set_isom_mp4a_description( audio, summary );
2068 else if( isom_is_lpcm_audio( audio ) )
2069 err = isom_set_qtff_lpcm_description( audio, summary );
2070 else if( lsmash_check_codec_type_identical( audio_type, ISOM_CODEC_TYPE_DTSC_AUDIO )
2071 || lsmash_check_codec_type_identical( audio_type, ISOM_CODEC_TYPE_DTSE_AUDIO )
2072 || lsmash_check_codec_type_identical( audio_type, ISOM_CODEC_TYPE_DTSH_AUDIO )
2073 || lsmash_check_codec_type_identical( audio_type, ISOM_CODEC_TYPE_DTSL_AUDIO ) )
2074 err = isom_set_isom_dts_description( audio, summary );
2075 else if( file->qt_compatible )
2076 err = isom_set_qtff_template_audio_description( audio, summary );
2077 else if( lsmash_check_codec_type_identical( audio_type, ISOM_CODEC_TYPE_SAMR_AUDIO ) )
2078 err = isom_set_isom_amr_audio_description( audio, 0 );
2079 else if( lsmash_check_codec_type_identical( audio_type, ISOM_CODEC_TYPE_SAWB_AUDIO ) )
2080 err = isom_set_isom_amr_audio_description( audio, 1 );
2081 else
2082 err = isom_set_isom_template_audio_description( audio, summary );
2083 if( err < 0 )
2084 goto fail;
2085 err = LSMASH_ERR_NAMELESS;
2086 /* Don't use audio_type since audio->type might have changed. */
2087 for( lsmash_entry_t *entry = summary->opaque->list.head; entry; entry = entry->next )
2089 lsmash_codec_specific_t *specific = (lsmash_codec_specific_t *)entry->data;
2090 if( !specific )
2091 goto fail;
2092 if( specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN
2093 && specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
2094 continue; /* LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN + LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED is not supported. */
2095 switch( specific->type )
2097 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_COMMON :
2099 if( specific->format == LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED )
2100 continue; /* Ignore since not fatal. */
2101 lsmash_qt_audio_common_t *data = (lsmash_qt_audio_common_t *)specific->data.structured;
2102 audio->revision_level = data->revision_level;
2103 audio->vendor = data->vendor;
2104 if( audio->version == 1
2105 && !isom_is_lpcm_audio( audio )
2106 && data->compression_ID != QT_AUDIO_COMPRESSION_ID_NOT_COMPRESSED )
2108 /* Compressed audio must not be set to QT_AUDIO_COMPRESSION_ID_NOT_COMPRESSED. */
2109 audio->compression_ID = data->compression_ID;
2110 if( audio->compression_ID == QT_AUDIO_COMPRESSION_ID_VARIABLE_COMPRESSION )
2112 /* For variable compression, bytesPerPacket and bytesPerFrame are reserved and should be set to 0. */
2113 audio->bytesPerPacket = 0;
2114 audio->bytesPerFrame = 0;
2117 break;
2119 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT :
2121 if( !file->qt_compatible
2122 && !lsmash_check_codec_type_identical( audio->type, ISOM_CODEC_TYPE_ALAC_AUDIO )
2123 && !lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ALAC_AUDIO ) )
2124 continue;
2125 if( (err = isom_append_channel_layout_extension( specific, audio, summary->channels )) < 0 )
2126 goto fail;
2127 break;
2129 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER :
2131 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2132 if( !cs )
2133 goto fail;
2134 lsmash_codec_global_header_t *data = (lsmash_codec_global_header_t *)cs->data.structured;
2135 isom_glbl_t *glbl = isom_add_glbl( audio );
2136 if( !glbl )
2138 lsmash_destroy_codec_specific_data( cs );
2139 goto fail;
2141 glbl->header_size = data->header_size;
2142 glbl->header_data = lsmash_memdup( data->header_data, data->header_size );
2143 lsmash_destroy_codec_specific_data( cs );
2144 if( !glbl->header_data )
2146 isom_remove_box_by_itself( glbl );
2147 err = LSMASH_ERR_MEMORY_ALLOC;
2148 goto fail;
2150 break;
2152 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS :
2153 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_DECOMPRESSION_PARAMETERS :
2154 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG :
2155 break; /* shall be set up already */
2156 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_ALAC :
2157 if( file->qt_compatible )
2158 continue; /* shall be set up already */
2159 default :
2161 lsmash_codec_specific_t *cs = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
2162 if( !cs )
2163 goto fail;
2164 if( cs->size < ISOM_BASEBOX_COMMON_SIZE )
2166 lsmash_destroy_codec_specific_data( cs );
2167 continue;
2169 uint8_t *box_data = cs->data.unstructured;
2170 lsmash_compact_box_type_t fourcc = LSMASH_4CC( box_data[4], box_data[5], box_data[6], box_data[7] );
2171 lsmash_box_type_t box_type = isom_guess_audio_codec_specific_box_type( audio->type, fourcc );
2172 if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_WAVE ) )
2174 /* CODEC specific info shall be already inside 'wave' extension. */
2175 lsmash_destroy_codec_specific_data( cs );
2176 continue;
2178 /* Append the extension. */
2179 err = isom_add_extension_binary( audio, box_type, LSMASH_BOX_PRECEDENCE_HM, cs->data.unstructured, cs->size );
2180 cs->data.unstructured = NULL; /* Avoid freeing the binary data of the extension. */
2181 lsmash_destroy_codec_specific_data( cs );
2182 if( err < 0 )
2183 goto fail;
2184 break;
2188 if( audio->version == 0 )
2189 audio->compression_ID = QT_AUDIO_COMPRESSION_ID_NOT_COMPRESSED;
2190 else if( audio->version == 2 )
2191 audio->compression_ID = QT_AUDIO_COMPRESSION_ID_VARIABLE_COMPRESSION;
2192 return 0;
2193 fail:
2194 isom_remove_box_by_itself( audio );
2195 return err;
2198 int isom_setup_tx3g_description( isom_stsd_t *stsd, lsmash_summary_t *summary )
2200 isom_tx3g_entry_t *tx3g = isom_add_tx3g_description( stsd );
2201 if( !tx3g )
2202 return LSMASH_ERR_NAMELESS;
2203 /* We create a dummy font record to make valid font_ID in the sample description.
2204 * The specification (3GPP TS 26.245) does not forbid the value 0 for the identifier,
2205 * but we set 1 to it as track_ID begins from 1. */
2206 tx3g->data_reference_index = summary->data_ref_index;
2207 tx3g->font_ID = 1; /* ID of the default font record */
2208 int err = LSMASH_ERR_MEMORY_ALLOC;
2209 isom_ftab_t *ftab = isom_add_ftab( tx3g );
2210 if( !ftab )
2212 err = LSMASH_ERR_NAMELESS;
2213 goto fail;
2215 isom_font_record_t *font = lsmash_malloc( sizeof(isom_font_record_t) );
2216 if( !font )
2217 goto fail;
2218 if( lsmash_add_entry( ftab->list, font ) < 0 )
2220 lsmash_free( font );
2221 goto fail;
2223 const char font_names[] = "Serif,Sans-serif,Monospace";
2224 font->font_ID = 1;
2225 font->font_name_length = sizeof(font_names);
2226 font->font_name = lsmash_memdup( font_names, sizeof(font_names) );
2227 if( !font->font_name )
2228 goto fail;
2229 return 0;
2230 fail:
2231 isom_remove_box_by_itself( tx3g );
2232 return err;
2235 static lsmash_codec_specific_data_type isom_get_codec_specific_data_type( lsmash_compact_box_type_t extension_fourcc )
2237 static struct codec_specific_data_type_table_tag
2239 lsmash_compact_box_type_t extension_fourcc;
2240 lsmash_codec_specific_data_type data_type;
2241 } codec_specific_data_type_table[32] = { { 0, LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN } };
2242 if( codec_specific_data_type_table[0].data_type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN )
2244 int i = 0;
2245 #define ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( extension_type, data_type ) \
2246 codec_specific_data_type_table[i++] = (struct codec_specific_data_type_table_tag){ extension_type.fourcc, data_type }
2247 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_AVCC, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264 );
2248 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_HVCC, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_HEVC );
2249 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_DVC1, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_VC_1 );
2250 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_DAC3, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_AC_3 );
2251 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_DEC3, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_EC_3 );
2252 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_DDTS, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS );
2253 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_ALAC, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_ALAC );
2254 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_ESDS, LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG );
2255 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_STSL, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_SAMPLE_SCALE );
2256 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( ISOM_BOX_TYPE_BTRT, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264_BITRATE );
2257 //ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_ALAC, LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_ALAC );
2258 //ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_ESDS, LSMASH_CODEC_SPECIFIC_DATA_TYPE_MP4SYS_DECODER_CONFIG );
2259 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_FIEL, LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_FIELD_INFO );
2260 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_CSPC, LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_PIXEL_FORMAT );
2261 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_SGBT, LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_SIGNIFICANT_BITS );
2262 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_GAMA, LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_GAMMA_LEVEL );
2263 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_CHAN, LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT );
2264 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( QT_BOX_TYPE_GLBL, LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER );
2265 ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT( LSMASH_BOX_TYPE_UNSPECIFIED, LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN );
2266 #undef ADD_CODEC_SPECIFIC_DATA_TYPE_TABLE_ELEMENT
2268 lsmash_codec_specific_data_type data_type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN;
2269 for( int i = 0; codec_specific_data_type_table[i].data_type != LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN; i++ )
2270 if( extension_fourcc == codec_specific_data_type_table[i].extension_fourcc )
2272 data_type = codec_specific_data_type_table[i].data_type;
2273 break;
2275 return data_type;
2278 lsmash_summary_t *isom_create_video_summary_from_description( isom_sample_entry_t *sample_entry )
2280 if( !sample_entry )
2281 return NULL;
2282 isom_visual_entry_t *visual = (isom_visual_entry_t *)sample_entry;
2283 lsmash_video_summary_t *summary = (lsmash_video_summary_t *)lsmash_create_summary( LSMASH_SUMMARY_TYPE_VIDEO );
2284 if( !summary )
2285 return NULL;
2286 summary->sample_type = visual->type;
2287 summary->data_ref_index = visual->data_reference_index;
2288 summary->width = visual->width;
2289 summary->height = visual->height;
2290 summary->depth = visual->depth;
2291 memcpy( summary->compressorname, visual->compressorname, 32 );
2292 summary->compressorname[32] = '\0';
2293 if( isom_is_qt_video( summary->sample_type ) )
2295 lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_COMMON,
2296 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2297 if( !specific )
2298 goto fail;
2299 lsmash_qt_video_common_t *data = (lsmash_qt_video_common_t *)specific->data.structured;
2300 data->revision_level = visual->revision_level;
2301 data->vendor = visual->vendor;
2302 data->temporalQuality = visual->temporalQuality;
2303 data->spatialQuality = visual->spatialQuality;
2304 data->horizontal_resolution = visual->horizresolution;
2305 data->vertical_resolution = visual->vertresolution;
2306 data->dataSize = visual->dataSize;
2307 data->frame_count = visual->frame_count;
2308 data->color_table_ID = visual->color_table_ID;
2309 if( visual->color_table_ID == 0 )
2311 isom_qt_color_table_t *src_ct = &visual->color_table;
2312 if( !src_ct->array )
2314 lsmash_destroy_codec_specific_data( specific );
2315 goto fail;
2317 uint16_t element_count = LSMASH_MIN( src_ct->size + 1, 256 );
2318 lsmash_qt_color_table_t *dst_ct = &data->color_table;
2319 dst_ct->seed = src_ct->seed;
2320 dst_ct->flags = src_ct->flags;
2321 dst_ct->size = src_ct->size;
2322 for( uint16_t i = 0; i < element_count; i++ )
2324 dst_ct->array[i].unused = src_ct->array[i].value;
2325 dst_ct->array[i].r = src_ct->array[i].r;
2326 dst_ct->array[i].g = src_ct->array[i].g;
2327 dst_ct->array[i].b = src_ct->array[i].b;
2330 if( lsmash_add_entry( &summary->opaque->list, specific ) < 0 )
2332 lsmash_destroy_codec_specific_data( specific );
2333 goto fail;
2336 for( lsmash_entry_t *entry = visual->extensions.head; entry; entry = entry->next )
2338 isom_box_t *box = (isom_box_t *)entry->data;
2339 if( !box )
2340 continue;
2341 if( !(box->manager & LSMASH_BINARY_CODED_BOX) )
2343 lsmash_codec_specific_t *specific = NULL;
2344 if( lsmash_check_box_type_identical( box->type, ISOM_BOX_TYPE_CLAP ) )
2346 isom_clap_t *clap = (isom_clap_t *)box;
2347 summary->clap.width.n = clap->cleanApertureWidthN;
2348 summary->clap.width.d = clap->cleanApertureWidthD;
2349 summary->clap.height.n = clap->cleanApertureHeightN;
2350 summary->clap.height.d = clap->cleanApertureHeightD;
2351 summary->clap.horizontal_offset.n = clap->horizOffN;
2352 summary->clap.horizontal_offset.d = clap->horizOffD;
2353 summary->clap.vertical_offset.n = clap->vertOffN;
2354 summary->clap.vertical_offset.d = clap->vertOffD;
2355 continue;
2357 else if( lsmash_check_box_type_identical( box->type, ISOM_BOX_TYPE_PASP ) )
2359 isom_pasp_t *pasp = (isom_pasp_t *)box;
2360 summary->par_h = pasp->hSpacing;
2361 summary->par_v = pasp->vSpacing;
2362 continue;
2364 else if( lsmash_check_box_type_identical( box->type, ISOM_BOX_TYPE_COLR )
2365 || lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_COLR ) )
2367 isom_colr_t *colr = (isom_colr_t *)box;
2368 summary->color.primaries_index = colr->primaries_index;
2369 summary->color.transfer_index = colr->transfer_function_index;
2370 summary->color.matrix_index = colr->matrix_index;
2371 summary->color.full_range = colr->full_range_flag;
2372 continue;
2374 else if( lsmash_check_box_type_identical( box->type, ISOM_BOX_TYPE_STSL ) )
2376 specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_SAMPLE_SCALE,
2377 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2378 if( !specific )
2379 goto fail;
2380 isom_stsl_t *stsl = (isom_stsl_t *)box;
2381 lsmash_isom_sample_scale_t *data = (lsmash_isom_sample_scale_t *)specific->data.structured;
2382 data->constraint_flag = stsl->constraint_flag;
2383 data->scale_method = stsl->scale_method;
2384 data->display_center_x = stsl->display_center_x;
2385 data->display_center_y = stsl->display_center_y;
2387 else if( lsmash_check_box_type_identical( box->type, ISOM_BOX_TYPE_BTRT ) )
2389 specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264_BITRATE,
2390 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2391 if( !specific )
2392 goto fail;
2393 isom_btrt_t *btrt = (isom_btrt_t *)box;
2394 lsmash_h264_bitrate_t *data = (lsmash_h264_bitrate_t *)specific->data.structured;
2395 data->bufferSizeDB = btrt->bufferSizeDB;
2396 data->maxBitrate = btrt->maxBitrate;
2397 data->avgBitrate = btrt->avgBitrate;
2399 else if( lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_FIEL ) )
2401 specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_FIELD_INFO,
2402 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2403 if( !specific )
2404 goto fail;
2405 isom_fiel_t *fiel = (isom_fiel_t *)box;
2406 lsmash_qt_field_info_t *data = (lsmash_qt_field_info_t *)specific->data.structured;
2407 data->fields = fiel->fields;
2408 data->detail = fiel->detail;
2410 else if( lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_CSPC ) )
2412 specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_PIXEL_FORMAT,
2413 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2414 if( !specific )
2415 goto fail;
2416 isom_cspc_t *cspc = (isom_cspc_t *)box;
2417 lsmash_qt_pixel_format_t *data = (lsmash_qt_pixel_format_t *)specific->data.structured;
2418 data->pixel_format = cspc->pixel_format;
2420 else if( lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_SGBT ) )
2422 specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_SIGNIFICANT_BITS,
2423 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2424 if( !specific )
2425 goto fail;
2426 isom_sgbt_t *sgbt = (isom_sgbt_t *)box;
2427 lsmash_qt_significant_bits_t *data = (lsmash_qt_significant_bits_t *)specific->data.structured;
2428 data->significantBits = sgbt->significantBits;
2430 else if( lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_GLBL ) )
2432 specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_CODEC_GLOBAL_HEADER,
2433 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2434 if( !specific )
2435 goto fail;
2436 isom_glbl_t *glbl = (isom_glbl_t *)box;
2437 lsmash_codec_global_header_t *data = (lsmash_codec_global_header_t *)specific->data.structured;
2438 data->header_size = glbl->header_size;
2439 data->header_data = lsmash_memdup( glbl->header_data, glbl->header_size );
2440 if( !data->header_data )
2442 lsmash_destroy_codec_specific_data( specific );
2443 goto fail;
2446 else
2447 continue;
2448 if( lsmash_add_entry( &summary->opaque->list, specific ) < 0 )
2450 lsmash_destroy_codec_specific_data( specific );
2451 goto fail;
2454 else
2456 if( box->size < ISOM_BASEBOX_COMMON_SIZE )
2457 continue;
2458 uint8_t *data = box->binary;
2459 lsmash_compact_box_type_t fourcc = LSMASH_4CC( data[4], data[5], data[6], data[7] );
2460 lsmash_codec_specific_data_type type = isom_get_codec_specific_data_type( fourcc );
2461 lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( type, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
2462 if( !specific )
2463 goto fail;
2464 specific->size = box->size;
2465 specific->data.unstructured = lsmash_memdup( box->binary, box->size );
2466 if( !specific->data.unstructured
2467 || lsmash_add_entry( &summary->opaque->list, specific ) < 0 )
2469 lsmash_destroy_codec_specific_data( specific );
2470 goto fail;
2474 return (lsmash_summary_t *)summary;
2475 fail:
2476 lsmash_cleanup_summary( (lsmash_summary_t *)summary );
2477 return NULL;
2480 static int isom_append_structured_mp4sys_decoder_config( lsmash_codec_specific_list_t *opaque, isom_esds_t *esds )
2482 lsmash_bs_t *bs = lsmash_bs_create();
2483 if( !bs )
2484 return LSMASH_ERR_MEMORY_ALLOC;
2485 /* Put box size, type, version and flags fields. */
2486 lsmash_bs_put_be32( bs, 0 );
2487 lsmash_bs_put_be32( bs, ISOM_BOX_TYPE_ESDS.fourcc );
2488 lsmash_bs_put_be32( bs, 0 );
2489 /* Put ES Descriptor. */
2490 mp4sys_update_descriptor_size( esds->ES );
2491 mp4sys_write_descriptor( bs, esds->ES );
2492 /* Export ES Descriptor Box as binary string. */
2493 uint32_t esds_size;
2494 uint8_t *esds_data = lsmash_bs_export_data( bs, &esds_size );
2495 lsmash_bs_cleanup( bs );
2496 if( !esds_data )
2497 return LSMASH_ERR_NAMELESS;
2498 /* Update box size. */
2499 LSMASH_SET_BE32( esds_data, esds_size );
2500 lsmash_codec_specific_data_type type = isom_get_codec_specific_data_type( ISOM_BOX_TYPE_ESDS.fourcc );
2501 lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( type, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
2502 if( !specific )
2504 lsmash_free( esds_data );
2505 return LSMASH_ERR_NAMELESS;
2507 specific->data.unstructured = esds_data;
2508 specific->size = esds_size;
2509 /* Convert unstructured CODEC specific data format into structured, and append it to the opaque list. */
2510 lsmash_codec_specific_t *conv = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2511 lsmash_destroy_codec_specific_data( specific );
2512 if( !conv )
2513 return LSMASH_ERR_NAMELESS;
2514 if( lsmash_add_entry( &opaque->list, conv ) < 0 )
2516 lsmash_destroy_codec_specific_data( conv );
2517 return LSMASH_ERR_MEMORY_ALLOC;
2519 return 0;
2522 lsmash_summary_t *isom_create_audio_summary_from_description( isom_sample_entry_t *sample_entry )
2524 if( !sample_entry || !sample_entry->file || !sample_entry->parent )
2525 return NULL;
2526 isom_audio_entry_t *audio = (isom_audio_entry_t *)sample_entry;
2527 lsmash_audio_summary_t *summary = (lsmash_audio_summary_t *)lsmash_create_summary( LSMASH_SUMMARY_TYPE_AUDIO );
2528 if( !summary )
2529 return NULL;
2530 summary->sample_type = audio->type;
2531 summary->data_ref_index = audio->data_reference_index;
2532 summary->sample_size = audio->samplesize;
2533 summary->channels = audio->channelcount;
2534 summary->frequency = audio->samplerate >> 16;
2535 if( ((isom_stsd_t *)audio->parent)->version == 0
2536 && audio->file->qt_compatible
2537 && isom_is_qt_audio( audio->type ) )
2539 if( audio->version == 0 )
2540 isom_get_implicit_qt_fixed_comp_audio_sample_quants( audio, &summary->samples_in_frame, &summary->bytes_per_frame, &summary->sample_size );
2541 else if( audio->version == 1 )
2543 summary->channels = audio->bytesPerPacket ? audio->bytesPerFrame / audio->bytesPerPacket : audio->channelcount;
2544 summary->sample_size = audio->bytesPerPacket * 8;
2545 summary->samples_in_frame = audio->samplesPerPacket;
2546 summary->bytes_per_frame = audio->bytesPerFrame;
2548 else if( audio->version == 2 )
2550 summary->frequency = (union {uint64_t i; double d;}){audio->audioSampleRate}.d;
2551 summary->channels = audio->numAudioChannels;
2552 summary->sample_size = audio->constBitsPerChannel;
2553 summary->samples_in_frame = audio->constLPCMFramesPerAudioPacket;
2554 summary->bytes_per_frame = audio->constBytesPerAudioPacket;
2556 lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_COMMON,
2557 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2558 if( !specific )
2559 goto fail;
2560 lsmash_qt_audio_common_t *common = (lsmash_qt_audio_common_t *)specific->data.structured;
2561 common->revision_level = audio->revision_level;
2562 common->vendor = audio->vendor;
2563 common->compression_ID = audio->compression_ID;
2564 if( lsmash_add_entry( &summary->opaque->list, specific ) < 0 )
2566 lsmash_destroy_codec_specific_data( specific );
2567 goto fail;
2569 if( isom_is_lpcm_audio( audio ) )
2571 specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS,
2572 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2573 if( !specific )
2574 goto fail;
2575 lsmash_qt_audio_format_specific_flags_t *data = (lsmash_qt_audio_format_specific_flags_t *)specific->data.structured;
2576 if( audio->version == 2 )
2577 data->format_flags = audio->formatSpecificFlags;
2578 else
2580 data->format_flags = QT_LPCM_FORMAT_FLAG_BIG_ENDIAN | QT_LPCM_FORMAT_FLAG_SIGNED_INTEGER;
2581 /* Here, don't override samplesize.
2582 * We should trust samplesize field in the description for misused CODEC indentifier. */
2583 lsmash_codec_type_t audio_type = audio->type;
2584 if( lsmash_check_codec_type_identical( audio_type, QT_CODEC_TYPE_TWOS_AUDIO )
2585 || lsmash_check_codec_type_identical( audio_type, QT_CODEC_TYPE_NONE_AUDIO )
2586 || lsmash_check_codec_type_identical( audio_type, QT_CODEC_TYPE_NOT_SPECIFIED ) )
2588 if( summary->sample_size <= 8 )
2589 data->format_flags &= ~(QT_LPCM_FORMAT_FLAG_BIG_ENDIAN | QT_LPCM_FORMAT_FLAG_SIGNED_INTEGER);
2591 else
2593 if( lsmash_check_codec_type_identical( audio_type, QT_CODEC_TYPE_FL32_AUDIO )
2594 || lsmash_check_codec_type_identical( audio_type, QT_CODEC_TYPE_FL64_AUDIO ) )
2596 data->format_flags &= ~QT_LPCM_FORMAT_FLAG_SIGNED_INTEGER;
2597 data->format_flags |= QT_LPCM_FORMAT_FLAG_FLOAT;
2599 else if( lsmash_check_codec_type_identical( audio_type, QT_CODEC_TYPE_23NI_AUDIO )
2600 || lsmash_check_codec_type_identical( audio_type, QT_CODEC_TYPE_SOWT_AUDIO ) )
2601 data->format_flags &= ~QT_LPCM_FORMAT_FLAG_BIG_ENDIAN;
2604 isom_wave_t *wave = (isom_wave_t *)isom_get_extension_box_format( &audio->extensions, QT_BOX_TYPE_WAVE );
2605 if( wave && wave->enda )
2607 if( wave->enda->littleEndian )
2608 data->format_flags &= ~QT_LPCM_FORMAT_FLAG_BIG_ENDIAN;
2609 else
2610 data->format_flags |= QT_LPCM_FORMAT_FLAG_BIG_ENDIAN;
2612 if( lsmash_add_entry( &summary->opaque->list, specific ) < 0 )
2614 lsmash_destroy_codec_specific_data( specific );
2615 goto fail;
2618 else if( audio->version == 2
2619 && (lsmash_check_codec_type_identical( audio->type, ISOM_CODEC_TYPE_ALAC_AUDIO )
2620 || lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ALAC_AUDIO )) )
2621 switch( audio->formatSpecificFlags )
2623 case QT_ALAC_FORMAT_FLAG_16BIT_SOURCE_DATA :
2624 summary->sample_size = 16;
2625 break;
2626 case QT_ALAC_FORMAT_FLAG_20BIT_SOURCE_DATA :
2627 summary->sample_size = 20;
2628 break;
2629 case QT_ALAC_FORMAT_FLAG_24BIT_SOURCE_DATA :
2630 summary->sample_size = 24;
2631 break;
2632 case QT_ALAC_FORMAT_FLAG_32BIT_SOURCE_DATA :
2633 summary->sample_size = 32;
2634 break;
2635 default :
2636 break;
2639 else if( lsmash_check_codec_type_identical( audio->type, ISOM_CODEC_TYPE_SAMR_AUDIO ) )
2641 summary->channels = 1;
2642 summary->frequency = 8000;
2644 else if( lsmash_check_codec_type_identical( audio->type, ISOM_CODEC_TYPE_SAWB_AUDIO ) )
2646 summary->channels = 1;
2647 summary->frequency = 16000;
2649 uint32_t actual_sampling_rate = 0;
2650 for( lsmash_entry_t *entry = audio->extensions.head; entry; entry = entry->next )
2652 isom_box_t *box = (isom_box_t *)entry->data;
2653 if( !box )
2654 continue;
2655 if( !(box->manager & LSMASH_BINARY_CODED_BOX) )
2657 if( lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_CHAN ) )
2659 lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_CHANNEL_LAYOUT,
2660 LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2661 if( !specific )
2662 goto fail;
2663 isom_chan_t *chan = (isom_chan_t *)box;
2664 lsmash_qt_audio_channel_layout_t *data = (lsmash_qt_audio_channel_layout_t *)specific->data.structured;
2665 data->channelLayoutTag = chan->channelLayoutTag;
2666 data->channelBitmap = chan->channelBitmap;
2667 if( lsmash_add_entry( &summary->opaque->list, specific ) < 0 )
2669 lsmash_destroy_codec_specific_data( specific );
2670 goto fail;
2673 else if( lsmash_check_box_type_identical( box->type, ISOM_BOX_TYPE_ESDS )
2674 || lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_ESDS ) )
2676 isom_esds_t *esds = (isom_esds_t *)box;
2677 if( mp4sys_setup_summary_from_DecoderSpecificInfo( summary, esds->ES ) < 0
2678 || isom_append_structured_mp4sys_decoder_config( summary->opaque, esds ) < 0 )
2679 goto fail;
2681 else if( lsmash_check_box_type_identical( box->type, ISOM_BOX_TYPE_SRAT ) )
2683 isom_srat_t *srat = (isom_srat_t *)box;
2684 actual_sampling_rate = srat->sampling_rate;
2686 else if( lsmash_check_box_type_identical( box->type, QT_BOX_TYPE_WAVE ) )
2688 /* Don't append 'wave' extension itself to the opaque CODEC specific info list. */
2689 isom_wave_t *wave = (isom_wave_t *)box;
2690 lsmash_bs_t *bs = lsmash_bs_create();
2691 if( !bs )
2692 goto fail;
2693 for( lsmash_entry_t *wave_entry = wave->extensions.head; wave_entry; wave_entry = wave_entry->next )
2695 isom_box_t *wave_ext = (isom_box_t *)wave_entry->data;
2696 if( !wave_ext )
2697 continue;
2698 lsmash_box_type_t box_type = LSMASH_BOX_TYPE_INITIALIZER;
2699 if( !(wave_ext->manager & LSMASH_BINARY_CODED_BOX) )
2701 box_type = wave_ext->type;
2702 if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_ENDA ) )
2704 isom_enda_t *enda = (isom_enda_t *)wave_ext;
2705 isom_bs_put_box_common( bs, enda );
2706 lsmash_bs_put_be16( bs, enda->littleEndian );
2708 else if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_MP4A ) )
2710 isom_mp4a_t *mp4a = (isom_mp4a_t *)wave_ext;
2711 isom_bs_put_box_common( bs, mp4a );
2712 lsmash_bs_put_be32( bs, mp4a->unknown );
2714 else if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_CHAN ) )
2716 isom_chan_t *chan = (isom_chan_t *)wave_ext;
2717 isom_bs_put_box_common( bs, chan );
2718 lsmash_bs_put_be32( bs, chan->channelLayoutTag );
2719 lsmash_bs_put_be32( bs, chan->channelBitmap );
2720 lsmash_bs_put_be32( bs, chan->numberChannelDescriptions );
2721 if( chan->channelDescriptions )
2722 for( uint32_t i = 0; i < chan->numberChannelDescriptions; i++ )
2724 isom_channel_description_t *channelDescriptions = (isom_channel_description_t *)(&chan->channelDescriptions[i]);
2725 lsmash_bs_put_be32( bs, channelDescriptions->channelLabel );
2726 lsmash_bs_put_be32( bs, channelDescriptions->channelFlags );
2727 lsmash_bs_put_be32( bs, channelDescriptions->coordinates[0] );
2728 lsmash_bs_put_be32( bs, channelDescriptions->coordinates[1] );
2729 lsmash_bs_put_be32( bs, channelDescriptions->coordinates[2] );
2732 else if( lsmash_check_box_type_identical( box_type, QT_BOX_TYPE_ESDS ) )
2734 isom_esds_t *esds = (isom_esds_t *)wave_ext;
2735 if( !esds
2736 || mp4sys_setup_summary_from_DecoderSpecificInfo( summary, esds->ES ) < 0
2737 || isom_append_structured_mp4sys_decoder_config( summary->opaque, esds ) < 0 )
2739 lsmash_bs_cleanup( bs );
2740 goto fail;
2742 continue;
2744 else
2745 /* Skip Format Box and Terminator Box since they are mandatory and fixed structure. */
2746 continue;
2748 else
2750 if( wave_ext->size < ISOM_BASEBOX_COMMON_SIZE )
2751 continue;
2752 uint8_t *data = wave_ext->binary;
2753 box_type.fourcc = LSMASH_4CC( data[4], data[5], data[6], data[7] );
2754 lsmash_bs_put_bytes( bs, wave_ext->size, wave_ext->binary );
2756 /* Export as binary string. */
2757 uint32_t box_size;
2758 uint8_t *box_data = lsmash_bs_export_data( bs, &box_size );
2759 lsmash_bs_empty( bs );
2760 if( !box_data )
2762 lsmash_bs_cleanup( bs );
2763 goto fail;
2765 /* Append as an unstructured CODEC specific info. */
2766 lsmash_codec_specific_data_type type;
2767 if( box_type.fourcc == QT_BOX_TYPE_CHAN.fourcc )
2768 /* Complete audio channel layout is stored as binary string.
2769 * We distinguish it from one of the outside of 'wave' extension here. */
2770 type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_DECOMPRESSION_PARAMETERS;
2771 else
2773 type = isom_get_codec_specific_data_type( box_type.fourcc );
2774 if( type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_UNKNOWN )
2775 type = LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_DECOMPRESSION_PARAMETERS;
2777 lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( type, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
2778 if( !specific )
2780 lsmash_free( box_data );
2781 lsmash_bs_cleanup( bs );
2782 goto fail;
2784 specific->data.unstructured = box_data;
2785 specific->size = box_size;
2786 if( lsmash_add_entry( &summary->opaque->list, specific ) < 0 )
2788 lsmash_destroy_codec_specific_data( specific );
2789 lsmash_bs_cleanup( bs );
2790 goto fail;
2793 lsmash_bs_cleanup( bs );
2796 else
2798 if( box->size < ISOM_BASEBOX_COMMON_SIZE )
2799 continue;
2800 uint8_t *data = box->binary;
2801 lsmash_compact_box_type_t fourcc = LSMASH_4CC( data[4], data[5], data[6], data[7] );
2802 lsmash_codec_specific_data_type type = isom_get_codec_specific_data_type( fourcc );
2803 lsmash_codec_specific_t *specific = lsmash_create_codec_specific_data( type, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
2804 if( !specific )
2805 goto fail;
2806 specific->size = box->size;
2807 specific->data.unstructured = lsmash_memdup( box->binary, box->size );
2808 if( !specific->data.unstructured
2809 || lsmash_add_entry( &summary->opaque->list, specific ) < 0 )
2811 lsmash_destroy_codec_specific_data( specific );
2812 goto fail;
2814 if( specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS
2815 || specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_AC_3
2816 || specific->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_EC_3 )
2818 specific = lsmash_convert_codec_specific_format( specific, LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
2819 if( !specific )
2820 goto fail;
2821 switch( specific->type )
2823 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_DTS :
2825 lsmash_dts_specific_parameters_t *param = (lsmash_dts_specific_parameters_t *)specific->data.structured;
2826 summary->sample_size = param->pcmSampleDepth;
2827 summary->samples_in_frame = (summary->frequency * (512 << param->FrameDuration)) / param->DTSSamplingFrequency;
2828 break;
2830 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_AC_3 :
2832 lsmash_ac3_specific_parameters_t *param = (lsmash_ac3_specific_parameters_t *)specific->data.structured;
2833 summary->frequency = ac3_get_sample_rate( param );
2834 summary->channels = ac3_get_channel_count( param );
2835 summary->samples_in_frame = 1536;
2836 break;
2838 case LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_AUDIO_EC_3 :
2840 lsmash_eac3_specific_parameters_t *param = (lsmash_eac3_specific_parameters_t *)specific->data.structured;
2841 eac3_update_sample_rate( &summary->frequency, param, NULL );
2842 eac3_update_channel_count( &summary->channels, param );
2843 summary->samples_in_frame = 1536;
2844 break;
2846 default :
2847 break;
2849 lsmash_destroy_codec_specific_data( specific );
2853 /* Set the actual sampling rate. */
2854 if( actual_sampling_rate )
2855 summary->frequency = actual_sampling_rate;
2856 return (lsmash_summary_t *)summary;
2857 fail:
2858 lsmash_cleanup_summary( (lsmash_summary_t *)summary );
2859 return NULL;
2862 lsmash_codec_specific_t *lsmash_get_codec_specific_data( lsmash_summary_t *summary, uint32_t extension_number )
2864 if( !summary || !summary->opaque )
2865 return NULL;
2866 uint32_t i = 0;
2867 for( lsmash_entry_t *entry = summary->opaque->list.head; entry; entry = entry->next )
2868 if( ++i == extension_number )
2869 return (lsmash_codec_specific_t *)entry->data;
2870 return NULL;
2873 uint32_t lsmash_count_codec_specific_data( lsmash_summary_t *summary )
2875 if( !summary || !summary->opaque )
2876 return 0;
2877 return summary->opaque->list.entry_count;
2880 int isom_compare_opaque_extensions( lsmash_summary_t *a, lsmash_summary_t *b )
2882 assert( a && b );
2883 uint32_t in_number_of_extensions = lsmash_count_codec_specific_data( a );
2884 uint32_t out_number_of_extensions = lsmash_count_codec_specific_data( b );
2885 if( out_number_of_extensions != in_number_of_extensions )
2886 return 1;
2887 uint32_t active_number_of_extensions = in_number_of_extensions;
2888 uint32_t identical_count = 0;
2889 for( uint32_t j = 1; j <= in_number_of_extensions; j++ )
2891 lsmash_codec_specific_t *in_cs_orig = lsmash_get_codec_specific_data( a, j );
2892 lsmash_codec_specific_t *in_cs;
2893 lsmash_codec_specific_format compare_format = LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED;
2894 if( in_cs_orig->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
2896 if( in_cs_orig->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_COMMON
2897 || in_cs_orig->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_COMMON
2898 || in_cs_orig->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_FORMAT_SPECIFIC_FLAGS )
2900 compare_format = LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED;
2901 in_cs = in_cs_orig;
2903 else
2905 in_cs = lsmash_convert_codec_specific_format( in_cs_orig, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
2906 if( !in_cs )
2908 /* We don't support the format converter of this data type. */
2909 --active_number_of_extensions;
2910 continue;
2914 else
2915 in_cs = in_cs_orig;
2916 for( uint32_t k = 1; k <= out_number_of_extensions; k++ )
2918 lsmash_codec_specific_t *out_cs_orig = lsmash_get_codec_specific_data( b, k );
2919 if( out_cs_orig->type != in_cs_orig->type )
2920 continue;
2921 lsmash_codec_specific_t *out_cs;
2922 if( out_cs_orig->format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
2924 if( compare_format == LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED )
2925 out_cs = out_cs_orig;
2926 else
2928 out_cs = lsmash_convert_codec_specific_format( out_cs_orig, LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED );
2929 if( !out_cs )
2930 continue;
2933 else
2934 out_cs = out_cs_orig;
2935 int identical;
2936 if( compare_format == LSMASH_CODEC_SPECIFIC_FORMAT_UNSTRUCTURED )
2937 identical = out_cs->size == in_cs->size && !memcmp( out_cs->data.unstructured, in_cs->data.unstructured, in_cs->size );
2938 else
2940 if( in_cs->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_VIDEO_COMMON )
2942 lsmash_qt_video_common_t *in_data = (lsmash_qt_video_common_t *)in_cs->data.structured;
2943 lsmash_qt_video_common_t *out_data = (lsmash_qt_video_common_t *)out_cs->data.structured;
2944 identical = in_data->revision_level == out_data->revision_level
2945 && in_data->vendor == out_data->vendor
2946 && in_data->temporalQuality == out_data->temporalQuality
2947 && in_data->spatialQuality == out_data->spatialQuality
2948 && in_data->horizontal_resolution == out_data->horizontal_resolution
2949 && in_data->vertical_resolution == out_data->vertical_resolution
2950 && in_data->dataSize == out_data->dataSize
2951 && in_data->frame_count == out_data->frame_count
2952 && in_data->color_table_ID == out_data->color_table_ID;
2954 else if( in_cs->type == LSMASH_CODEC_SPECIFIC_DATA_TYPE_QT_AUDIO_COMMON )
2956 lsmash_qt_audio_common_t *in_data = (lsmash_qt_audio_common_t *)in_cs->data.structured;
2957 lsmash_qt_audio_common_t *out_data = (lsmash_qt_audio_common_t *)out_cs->data.structured;
2958 identical = in_data->revision_level == out_data->revision_level
2959 && in_data->vendor == out_data->vendor
2960 && in_data->compression_ID == out_data->compression_ID;
2962 else
2964 lsmash_qt_audio_format_specific_flags_t *in_data = (lsmash_qt_audio_format_specific_flags_t *)in_cs->data.structured;
2965 lsmash_qt_audio_format_specific_flags_t *out_data = (lsmash_qt_audio_format_specific_flags_t *)out_cs->data.structured;
2966 identical = (in_data->format_flags == out_data->format_flags);
2969 if( out_cs != out_cs_orig )
2970 lsmash_destroy_codec_specific_data( out_cs );
2971 if( identical )
2973 ++identical_count;
2974 break;
2977 if( in_cs != in_cs_orig )
2978 lsmash_destroy_codec_specific_data( in_cs );
2980 return (identical_count != active_number_of_extensions);
2983 int isom_get_implicit_qt_fixed_comp_audio_sample_quants
2985 isom_audio_entry_t *audio,
2986 uint32_t *samples_per_packet,
2987 uint32_t *constant_bytes_per_frame,
2988 uint32_t *sample_size
2991 if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_MAC3_AUDIO ) )
2993 *samples_per_packet = 6;
2994 *constant_bytes_per_frame = 2 * audio->channelcount;
2995 *sample_size = 8;
2997 else if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_MAC6_AUDIO ) )
2999 *samples_per_packet = 6;
3000 *constant_bytes_per_frame = audio->channelcount;
3001 *sample_size = 8;
3003 else if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ADPCM17_AUDIO ) )
3005 *samples_per_packet = 64;
3006 *constant_bytes_per_frame = 34 * audio->channelcount;
3007 *sample_size = 16;
3009 else if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_AGSM_AUDIO ) )
3011 *samples_per_packet = 160;
3012 *constant_bytes_per_frame = 33;
3013 *sample_size = 16;
3015 else if( lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ALAW_AUDIO )
3016 || lsmash_check_codec_type_identical( audio->type, QT_CODEC_TYPE_ULAW_AUDIO ) )
3018 *samples_per_packet = 1;
3019 *constant_bytes_per_frame = audio->channelcount;
3020 *sample_size = 16;
3022 else
3023 return 0;
3024 return 1;