list: Decide the entry eliminator of list at its initialization.
[L-SMASH.git] / core / meta.c
bloba0d55dcd0c408d1aa4bb23e3c5b31cff123d9a8a
1 /*****************************************************************************
2 * meta.c
3 *****************************************************************************
4 * Copyright (C) 2012-2017 L-SMASH project
6 * Authors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 *****************************************************************************/
21 /* This file is available under an ISC license. */
23 #include "common/internal.h" /* must be placed first */
25 #include <string.h>
26 #include <stdlib.h>
28 #include "box.h"
30 static isom_data_t *isom_add_metadata( lsmash_file_t *file,
31 lsmash_itunes_metadata_item item,
32 char *meaning_string, char *name_string )
34 assert( LSMASH_IS_EXISTING_BOX( file->moov ) );
35 if( ((item == ITUNES_METADATA_ITEM_CUSTOM) && (!meaning_string || !meaning_string[0]) )
36 || (LSMASH_IS_NON_EXISTING_BOX( file->moov->udta )
37 && LSMASH_IS_BOX_ADDITION_FAILURE( isom_add_udta( file->moov ) ))
38 || (LSMASH_IS_NON_EXISTING_BOX( file->moov->udta->meta )
39 && LSMASH_IS_BOX_ADDITION_FAILURE( isom_add_meta( file->moov->udta ) ))
40 || (LSMASH_IS_NON_EXISTING_BOX( file->moov->udta->meta->ilst )
41 && LSMASH_IS_BOX_ADDITION_FAILURE( isom_add_ilst( file->moov->udta->meta ) )) )
42 return NULL;
43 if( LSMASH_IS_NON_EXISTING_BOX( file->moov->udta->meta->hdlr ) )
45 if( LSMASH_IS_BOX_ADDITION_FAILURE( isom_add_hdlr( file->moov->udta->meta ) )
46 || isom_setup_handler_reference( file->moov->udta->meta->hdlr, ISOM_META_HANDLER_TYPE_ITUNES_METADATA ) < 0 )
47 return NULL;
49 isom_ilst_t *ilst = file->moov->udta->meta->ilst;
50 if( LSMASH_IS_BOX_ADDITION_FAILURE( isom_add_metaitem( ilst, item ) ) )
51 return NULL;
52 isom_metaitem_t *metaitem = (isom_metaitem_t *)ilst->metaitem_list.tail->data;
53 if( item == ITUNES_METADATA_ITEM_CUSTOM )
55 if( LSMASH_IS_BOX_ADDITION_FAILURE( isom_add_mean( metaitem ) ) )
56 goto fail;
57 isom_mean_t *mean = metaitem->mean;
58 mean->meaning_string_length = strlen( meaning_string ); /* No null terminator */
59 mean->meaning_string = lsmash_memdup( meaning_string, mean->meaning_string_length );
60 if( !mean->meaning_string )
61 goto fail;
62 if( name_string && name_string[0] )
64 if( LSMASH_IS_BOX_ADDITION_FAILURE( isom_add_name( metaitem ) ) )
65 goto fail;
66 isom_name_t *name = metaitem->name;
67 name->name_length = strlen( name_string ); /* No null terminator */
68 name->name = lsmash_memdup( name_string, name->name_length );
69 if( !name->name )
70 goto fail;
73 if( LSMASH_IS_BOX_ADDITION_FAILURE( isom_add_data( metaitem ) ) )
74 goto fail;
75 return metaitem->data;
76 fail:
77 isom_remove_box_by_itself( metaitem );
78 return NULL;
81 static int isom_set_itunes_metadata_string( lsmash_file_t *file,
82 lsmash_itunes_metadata_item item,
83 lsmash_itunes_metadata_value_t value, char *meaning, char *name )
85 uint32_t value_length = strlen( value.string );
86 if( item == ITUNES_METADATA_ITEM_DESCRIPTION && value_length > 255 )
87 item = ITUNES_METADATA_ITEM_LONG_DESCRIPTION;
88 isom_data_t *data = isom_add_metadata( file, item, meaning, name );
89 if( LSMASH_IS_NON_EXISTING_BOX( data ) )
90 return LSMASH_ERR_NAMELESS;
91 data->type_code = ITUNES_METADATA_SUBTYPE_UTF8;
92 data->value_length = value_length; /* No null terminator */
93 data->value = lsmash_memdup( value.string, data->value_length );
94 if( !data->value )
96 isom_ilst_t *ilst = file->moov->udta->meta->ilst;
97 isom_remove_box_by_itself( ilst->metaitem_list.tail->data );
98 return LSMASH_ERR_MEMORY_ALLOC;
100 return 0;
103 static int isom_set_itunes_metadata_integer( lsmash_file_t *file,
104 lsmash_itunes_metadata_item item,
105 lsmash_itunes_metadata_value_t value, char *meaning, char *name )
107 static const struct
109 lsmash_itunes_metadata_item item;
110 int length;
111 } metadata_code_type_table[] =
113 { ITUNES_METADATA_ITEM_EPISODE_GLOBAL_ID, 1 },
114 { ITUNES_METADATA_ITEM_PREDEFINED_GENRE, 2 },
115 { ITUNES_METADATA_ITEM_CONTENT_RATING, 1 },
116 { ITUNES_METADATA_ITEM_MEDIA_TYPE, 1 },
117 { ITUNES_METADATA_ITEM_BEATS_PER_MINUTE, 2 },
118 { ITUNES_METADATA_ITEM_TV_EPISODE, 4 },
119 { ITUNES_METADATA_ITEM_TV_SEASON, 4 },
120 { ITUNES_METADATA_ITEM_ITUNES_ACCOUNT_TYPE, 1 },
121 { ITUNES_METADATA_ITEM_ITUNES_ARTIST_ID, 4 },
122 { ITUNES_METADATA_ITEM_ITUNES_COMPOSER_ID, 4 },
123 { ITUNES_METADATA_ITEM_ITUNES_CATALOG_ID, 4 },
124 { ITUNES_METADATA_ITEM_ITUNES_TV_GENRE_ID, 4 },
125 { ITUNES_METADATA_ITEM_ITUNES_PLAYLIST_ID, 8 },
126 { ITUNES_METADATA_ITEM_ITUNES_COUNTRY_CODE, 4 },
127 { ITUNES_METADATA_ITEM_CUSTOM, 8 },
128 { 0, 0 }
130 int i;
131 for( i = 0; metadata_code_type_table[i].item; i++ )
132 if( item == metadata_code_type_table[i].item )
133 break;
134 if( metadata_code_type_table[i].length == 0 )
135 return LSMASH_ERR_NAMELESS;
136 isom_data_t *data = isom_add_metadata( file, item, meaning, name );
137 if( LSMASH_IS_NON_EXISTING_BOX( data ) )
138 return LSMASH_ERR_NAMELESS;
139 if( item == ITUNES_METADATA_ITEM_PREDEFINED_GENRE )
140 data->type_code = ITUNES_METADATA_SUBTYPE_IMPLICIT;
141 else
142 data->type_code = ITUNES_METADATA_SUBTYPE_INTEGER;
143 data->value_length = metadata_code_type_table[i].length;
144 uint8_t temp[8];
145 for( i = 0; i < data->value_length; i++ )
147 int shift = (data->value_length - i - 1) * 8;
148 temp[i] = (value.integer >> shift) & 0xff;
150 data->value = lsmash_memdup( temp, data->value_length );
151 if( !data->value )
153 isom_ilst_t *ilst = file->moov->udta->meta->ilst;
154 isom_remove_box_by_itself( ilst->metaitem_list.tail->data );
155 return LSMASH_ERR_MEMORY_ALLOC;
157 return 0;
160 static int isom_set_itunes_metadata_boolean( lsmash_file_t *file,
161 lsmash_itunes_metadata_item item,
162 lsmash_itunes_metadata_value_t value, char *meaning, char *name )
164 isom_data_t *data = isom_add_metadata( file, item, meaning, name );
165 if( LSMASH_IS_NON_EXISTING_BOX( data ) )
166 return LSMASH_ERR_NAMELESS;
167 data->type_code = ITUNES_METADATA_SUBTYPE_INTEGER;
168 data->value_length = 1;
169 uint8_t temp = (uint8_t)value.boolean;
170 data->value = lsmash_memdup( &temp, 1 );
171 if( !data->value )
173 isom_ilst_t *ilst = file->moov->udta->meta->ilst;
174 isom_remove_box_by_itself( ilst->metaitem_list.tail->data );
175 return LSMASH_ERR_MEMORY_ALLOC;
177 return 0;
180 static int isom_set_itunes_metadata_binary( lsmash_file_t *file,
181 lsmash_itunes_metadata_item item,
182 lsmash_itunes_metadata_value_t value, char *meaning, char *name )
184 isom_data_t *data = isom_add_metadata( file, item, meaning, name );
185 if( LSMASH_IS_NON_EXISTING_BOX( data ) )
186 return LSMASH_ERR_NAMELESS;
187 switch( item )
189 case ITUNES_METADATA_ITEM_COVER_ART :
190 if( value.binary.subtype != ITUNES_METADATA_SUBTYPE_JPEG
191 && value.binary.subtype != ITUNES_METADATA_SUBTYPE_PNG
192 && value.binary.subtype != ITUNES_METADATA_SUBTYPE_BMP )
193 return LSMASH_ERR_FUNCTION_PARAM;
194 break;
195 case ITUNES_METADATA_ITEM_DISC_NUMBER :
196 case ITUNES_METADATA_ITEM_TRACK_NUMBER :
197 value.binary.subtype = ITUNES_METADATA_SUBTYPE_IMPLICIT;
198 break;
199 default :
200 break;
202 switch( value.binary.subtype )
204 case ITUNES_METADATA_SUBTYPE_UUID :
205 if( value.binary.size != 16 )
206 return LSMASH_ERR_FUNCTION_PARAM;
207 break;
208 case ITUNES_METADATA_SUBTYPE_DURATION :
209 if( value.binary.size != 4 )
210 return LSMASH_ERR_FUNCTION_PARAM;
211 break;
212 case ITUNES_METADATA_SUBTYPE_TIME :
213 if( value.binary.size != 4 && value.binary.size != 8 )
214 return LSMASH_ERR_FUNCTION_PARAM;
215 break;
216 case ITUNES_METADATA_SUBTYPE_INTEGER :
217 if( value.binary.size != 1 && value.binary.size != 2
218 && value.binary.size != 3 && value.binary.size != 4
219 && value.binary.size != 8 )
220 return LSMASH_ERR_FUNCTION_PARAM;
221 break;
222 case ITUNES_METADATA_SUBTYPE_RIAAPA :
223 if( value.binary.size != 1 )
224 return LSMASH_ERR_FUNCTION_PARAM;
225 break;
226 default :
227 break;
229 data->type_code = value.binary.subtype;
230 data->value_length = value.binary.size;
231 data->value = lsmash_memdup( value.binary.data, value.binary.size );
232 if( !data->value )
234 isom_ilst_t *ilst = file->moov->udta->meta->ilst;
235 isom_remove_box_by_itself( ilst->metaitem_list.tail->data );
236 return LSMASH_ERR_MEMORY_ALLOC;
238 return 0;
241 int lsmash_set_itunes_metadata( lsmash_root_t *root, lsmash_itunes_metadata_t metadata )
243 if( isom_check_initializer_present( root ) < 0 )
244 return LSMASH_ERR_FUNCTION_PARAM;
245 static const struct
247 lsmash_itunes_metadata_item item;
248 int (*func_set_itunes_metadata)( lsmash_file_t *, lsmash_itunes_metadata_item, lsmash_itunes_metadata_value_t, char *, char * );
249 } itunes_metadata_function_mapping[] =
251 { ITUNES_METADATA_ITEM_ALBUM_NAME, isom_set_itunes_metadata_string },
252 { ITUNES_METADATA_ITEM_ARTIST, isom_set_itunes_metadata_string },
253 { ITUNES_METADATA_ITEM_USER_COMMENT, isom_set_itunes_metadata_string },
254 { ITUNES_METADATA_ITEM_RELEASE_DATE, isom_set_itunes_metadata_string },
255 { ITUNES_METADATA_ITEM_ENCODED_BY, isom_set_itunes_metadata_string },
256 { ITUNES_METADATA_ITEM_USER_GENRE, isom_set_itunes_metadata_string },
257 { ITUNES_METADATA_ITEM_GROUPING, isom_set_itunes_metadata_string },
258 { ITUNES_METADATA_ITEM_LYRICS, isom_set_itunes_metadata_string },
259 { ITUNES_METADATA_ITEM_TITLE, isom_set_itunes_metadata_string },
260 { ITUNES_METADATA_ITEM_TRACK_SUBTITLE, isom_set_itunes_metadata_string },
261 { ITUNES_METADATA_ITEM_ENCODING_TOOL, isom_set_itunes_metadata_string },
262 { ITUNES_METADATA_ITEM_COMPOSER, isom_set_itunes_metadata_string },
263 { ITUNES_METADATA_ITEM_ALBUM_ARTIST, isom_set_itunes_metadata_string },
264 { ITUNES_METADATA_ITEM_PODCAST_CATEGORY, isom_set_itunes_metadata_string },
265 { ITUNES_METADATA_ITEM_COPYRIGHT, isom_set_itunes_metadata_string },
266 { ITUNES_METADATA_ITEM_DESCRIPTION, isom_set_itunes_metadata_string },
267 { ITUNES_METADATA_ITEM_GROUPING_DRAFT, isom_set_itunes_metadata_string },
268 { ITUNES_METADATA_ITEM_PODCAST_KEYWORD, isom_set_itunes_metadata_string },
269 { ITUNES_METADATA_ITEM_LONG_DESCRIPTION, isom_set_itunes_metadata_string },
270 { ITUNES_METADATA_ITEM_PURCHASE_DATE, isom_set_itunes_metadata_string },
271 { ITUNES_METADATA_ITEM_TV_EPISODE_ID, isom_set_itunes_metadata_string },
272 { ITUNES_METADATA_ITEM_TV_NETWORK, isom_set_itunes_metadata_string },
273 { ITUNES_METADATA_ITEM_TV_SHOW_NAME, isom_set_itunes_metadata_string },
274 { ITUNES_METADATA_ITEM_ITUNES_PURCHASE_ACCOUNT_ID, isom_set_itunes_metadata_string },
275 { ITUNES_METADATA_ITEM_ITUNES_SORT_ALBUM, isom_set_itunes_metadata_string },
276 { ITUNES_METADATA_ITEM_ITUNES_SORT_ARTIST, isom_set_itunes_metadata_string },
277 { ITUNES_METADATA_ITEM_ITUNES_SORT_ALBUM_ARTIST, isom_set_itunes_metadata_string },
278 { ITUNES_METADATA_ITEM_ITUNES_SORT_COMPOSER, isom_set_itunes_metadata_string },
279 { ITUNES_METADATA_ITEM_ITUNES_SORT_NAME, isom_set_itunes_metadata_string },
280 { ITUNES_METADATA_ITEM_ITUNES_SORT_SHOW, isom_set_itunes_metadata_string },
281 { ITUNES_METADATA_ITEM_EPISODE_GLOBAL_ID, isom_set_itunes_metadata_integer },
282 { ITUNES_METADATA_ITEM_PREDEFINED_GENRE, isom_set_itunes_metadata_integer },
283 { ITUNES_METADATA_ITEM_CONTENT_RATING, isom_set_itunes_metadata_integer },
284 { ITUNES_METADATA_ITEM_MEDIA_TYPE, isom_set_itunes_metadata_integer },
285 { ITUNES_METADATA_ITEM_BEATS_PER_MINUTE, isom_set_itunes_metadata_integer },
286 { ITUNES_METADATA_ITEM_TV_EPISODE, isom_set_itunes_metadata_integer },
287 { ITUNES_METADATA_ITEM_TV_SEASON, isom_set_itunes_metadata_integer },
288 { ITUNES_METADATA_ITEM_ITUNES_ACCOUNT_TYPE, isom_set_itunes_metadata_integer },
289 { ITUNES_METADATA_ITEM_ITUNES_ARTIST_ID, isom_set_itunes_metadata_integer },
290 { ITUNES_METADATA_ITEM_ITUNES_COMPOSER_ID, isom_set_itunes_metadata_integer },
291 { ITUNES_METADATA_ITEM_ITUNES_CATALOG_ID, isom_set_itunes_metadata_integer },
292 { ITUNES_METADATA_ITEM_ITUNES_TV_GENRE_ID, isom_set_itunes_metadata_integer },
293 { ITUNES_METADATA_ITEM_ITUNES_PLAYLIST_ID, isom_set_itunes_metadata_integer },
294 { ITUNES_METADATA_ITEM_ITUNES_COUNTRY_CODE, isom_set_itunes_metadata_integer },
295 { ITUNES_METADATA_ITEM_DISC_COMPILATION, isom_set_itunes_metadata_boolean },
296 { ITUNES_METADATA_ITEM_HIGH_DEFINITION_VIDEO, isom_set_itunes_metadata_boolean },
297 { ITUNES_METADATA_ITEM_PODCAST, isom_set_itunes_metadata_boolean },
298 { ITUNES_METADATA_ITEM_GAPLESS_PLAYBACK, isom_set_itunes_metadata_boolean },
299 { ITUNES_METADATA_ITEM_COVER_ART, isom_set_itunes_metadata_binary },
300 { ITUNES_METADATA_ITEM_DISC_NUMBER, isom_set_itunes_metadata_binary },
301 { ITUNES_METADATA_ITEM_TRACK_NUMBER, isom_set_itunes_metadata_binary },
302 { 0, NULL }
304 lsmash_file_t *file = root->file;
305 for( int i = 0; itunes_metadata_function_mapping[i].func_set_itunes_metadata; i++ )
306 if( metadata.item == itunes_metadata_function_mapping[i].item )
307 return itunes_metadata_function_mapping[i].func_set_itunes_metadata( file, metadata.item, metadata.value, metadata.meaning, metadata.name );
308 if( metadata.item == ITUNES_METADATA_ITEM_CUSTOM )
309 switch( metadata.type )
311 case ITUNES_METADATA_TYPE_STRING :
312 return isom_set_itunes_metadata_string( file, metadata.item, metadata.value, metadata.meaning, metadata.name );
313 case ITUNES_METADATA_TYPE_INTEGER :
314 return isom_set_itunes_metadata_integer( file, metadata.item, metadata.value, metadata.meaning, metadata.name );
315 case ITUNES_METADATA_TYPE_BOOLEAN :
316 return isom_set_itunes_metadata_boolean( file, metadata.item, metadata.value, metadata.meaning, metadata.name );
317 case ITUNES_METADATA_TYPE_BINARY :
318 return isom_set_itunes_metadata_binary( file, metadata.item, metadata.value, metadata.meaning, metadata.name );
319 default :
320 break;
322 return LSMASH_ERR_FUNCTION_PARAM;
325 static lsmash_itunes_metadata_type isom_get_itunes_metadata_type( lsmash_itunes_metadata_item item )
327 static const struct
329 lsmash_itunes_metadata_item item;
330 lsmash_itunes_metadata_type type;
331 } itunes_metadata_item_type_mapping[] =
333 { ITUNES_METADATA_ITEM_ALBUM_NAME, ITUNES_METADATA_TYPE_STRING },
334 { ITUNES_METADATA_ITEM_ARTIST, ITUNES_METADATA_TYPE_STRING },
335 { ITUNES_METADATA_ITEM_USER_COMMENT, ITUNES_METADATA_TYPE_STRING },
336 { ITUNES_METADATA_ITEM_RELEASE_DATE, ITUNES_METADATA_TYPE_STRING },
337 { ITUNES_METADATA_ITEM_ENCODED_BY, ITUNES_METADATA_TYPE_STRING },
338 { ITUNES_METADATA_ITEM_USER_GENRE, ITUNES_METADATA_TYPE_STRING },
339 { ITUNES_METADATA_ITEM_GROUPING, ITUNES_METADATA_TYPE_STRING },
340 { ITUNES_METADATA_ITEM_LYRICS, ITUNES_METADATA_TYPE_STRING },
341 { ITUNES_METADATA_ITEM_TITLE, ITUNES_METADATA_TYPE_STRING },
342 { ITUNES_METADATA_ITEM_TRACK_SUBTITLE, ITUNES_METADATA_TYPE_STRING },
343 { ITUNES_METADATA_ITEM_ENCODING_TOOL, ITUNES_METADATA_TYPE_STRING },
344 { ITUNES_METADATA_ITEM_COMPOSER, ITUNES_METADATA_TYPE_STRING },
345 { ITUNES_METADATA_ITEM_ALBUM_ARTIST, ITUNES_METADATA_TYPE_STRING },
346 { ITUNES_METADATA_ITEM_PODCAST_CATEGORY, ITUNES_METADATA_TYPE_STRING },
347 { ITUNES_METADATA_ITEM_COPYRIGHT, ITUNES_METADATA_TYPE_STRING },
348 { ITUNES_METADATA_ITEM_DESCRIPTION, ITUNES_METADATA_TYPE_STRING },
349 { ITUNES_METADATA_ITEM_GROUPING_DRAFT, ITUNES_METADATA_TYPE_STRING },
350 { ITUNES_METADATA_ITEM_PODCAST_KEYWORD, ITUNES_METADATA_TYPE_STRING },
351 { ITUNES_METADATA_ITEM_LONG_DESCRIPTION, ITUNES_METADATA_TYPE_STRING },
352 { ITUNES_METADATA_ITEM_PURCHASE_DATE, ITUNES_METADATA_TYPE_STRING },
353 { ITUNES_METADATA_ITEM_TV_EPISODE_ID, ITUNES_METADATA_TYPE_STRING },
354 { ITUNES_METADATA_ITEM_TV_NETWORK, ITUNES_METADATA_TYPE_STRING },
355 { ITUNES_METADATA_ITEM_TV_SHOW_NAME, ITUNES_METADATA_TYPE_STRING },
356 { ITUNES_METADATA_ITEM_ITUNES_PURCHASE_ACCOUNT_ID, ITUNES_METADATA_TYPE_STRING },
357 { ITUNES_METADATA_ITEM_ITUNES_SORT_ALBUM, ITUNES_METADATA_TYPE_STRING },
358 { ITUNES_METADATA_ITEM_ITUNES_SORT_ARTIST, ITUNES_METADATA_TYPE_STRING },
359 { ITUNES_METADATA_ITEM_ITUNES_SORT_ALBUM_ARTIST, ITUNES_METADATA_TYPE_STRING },
360 { ITUNES_METADATA_ITEM_ITUNES_SORT_COMPOSER, ITUNES_METADATA_TYPE_STRING },
361 { ITUNES_METADATA_ITEM_ITUNES_SORT_NAME, ITUNES_METADATA_TYPE_STRING },
362 { ITUNES_METADATA_ITEM_ITUNES_SORT_SHOW, ITUNES_METADATA_TYPE_STRING },
363 { ITUNES_METADATA_ITEM_EPISODE_GLOBAL_ID, ITUNES_METADATA_TYPE_INTEGER },
364 { ITUNES_METADATA_ITEM_PREDEFINED_GENRE, ITUNES_METADATA_TYPE_INTEGER },
365 { ITUNES_METADATA_ITEM_CONTENT_RATING, ITUNES_METADATA_TYPE_INTEGER },
366 { ITUNES_METADATA_ITEM_MEDIA_TYPE, ITUNES_METADATA_TYPE_INTEGER },
367 { ITUNES_METADATA_ITEM_BEATS_PER_MINUTE, ITUNES_METADATA_TYPE_INTEGER },
368 { ITUNES_METADATA_ITEM_TV_EPISODE, ITUNES_METADATA_TYPE_INTEGER },
369 { ITUNES_METADATA_ITEM_TV_SEASON, ITUNES_METADATA_TYPE_INTEGER },
370 { ITUNES_METADATA_ITEM_ITUNES_ACCOUNT_TYPE, ITUNES_METADATA_TYPE_INTEGER },
371 { ITUNES_METADATA_ITEM_ITUNES_ARTIST_ID, ITUNES_METADATA_TYPE_INTEGER },
372 { ITUNES_METADATA_ITEM_ITUNES_COMPOSER_ID, ITUNES_METADATA_TYPE_INTEGER },
373 { ITUNES_METADATA_ITEM_ITUNES_CATALOG_ID, ITUNES_METADATA_TYPE_INTEGER },
374 { ITUNES_METADATA_ITEM_ITUNES_TV_GENRE_ID, ITUNES_METADATA_TYPE_INTEGER },
375 { ITUNES_METADATA_ITEM_ITUNES_PLAYLIST_ID, ITUNES_METADATA_TYPE_INTEGER },
376 { ITUNES_METADATA_ITEM_ITUNES_COUNTRY_CODE, ITUNES_METADATA_TYPE_INTEGER },
377 { ITUNES_METADATA_ITEM_DISC_COMPILATION, ITUNES_METADATA_TYPE_BOOLEAN },
378 { ITUNES_METADATA_ITEM_HIGH_DEFINITION_VIDEO, ITUNES_METADATA_TYPE_BOOLEAN },
379 { ITUNES_METADATA_ITEM_PODCAST, ITUNES_METADATA_TYPE_BOOLEAN },
380 { ITUNES_METADATA_ITEM_GAPLESS_PLAYBACK, ITUNES_METADATA_TYPE_BOOLEAN },
381 { ITUNES_METADATA_ITEM_COVER_ART, ITUNES_METADATA_TYPE_BINARY },
382 { ITUNES_METADATA_ITEM_DISC_NUMBER, ITUNES_METADATA_TYPE_BINARY },
383 { ITUNES_METADATA_ITEM_TRACK_NUMBER, ITUNES_METADATA_TYPE_BINARY },
384 { 0, ITUNES_METADATA_TYPE_NONE }
386 for( int i = 0; itunes_metadata_item_type_mapping[i].type != ITUNES_METADATA_TYPE_NONE; i++ )
387 if( item == itunes_metadata_item_type_mapping[i].item )
388 return itunes_metadata_item_type_mapping[i].type;
389 return ITUNES_METADATA_TYPE_NONE;
392 int lsmash_get_itunes_metadata( lsmash_root_t *root, uint32_t metadata_number, lsmash_itunes_metadata_t *metadata )
394 if( isom_check_initializer_present( root ) < 0 || !metadata )
395 return LSMASH_ERR_FUNCTION_PARAM;
396 lsmash_file_t *file = root->file->initializer;
397 if( !file->moov->udta->meta->ilst )
398 return LSMASH_ERR_NAMELESS;
399 isom_ilst_t *ilst = file->moov->udta->meta->ilst;
400 isom_metaitem_t *metaitem = (isom_metaitem_t *)lsmash_list_get_entry_data( &ilst->metaitem_list, metadata_number );
401 if( LSMASH_IS_NON_EXISTING_BOX( metaitem )
402 || LSMASH_IS_NON_EXISTING_BOX( metaitem->data )
403 || metaitem->data->value == NULL
404 || metaitem->data->value_length == 0 )
405 return LSMASH_ERR_NAMELESS;
406 metadata->item = metaitem->type.fourcc;
407 metadata->type = isom_get_itunes_metadata_type( metadata->item );
408 /* Get 'meaning'. */
409 int err = LSMASH_ERR_MEMORY_ALLOC;
410 isom_mean_t *mean = metaitem->mean;
411 if( LSMASH_IS_NON_EXISTING_BOX( mean ) )
413 uint8_t *temp = lsmash_malloc( mean->meaning_string_length + 1 );
414 if( !temp )
415 goto fail;
416 memcpy( temp, mean->meaning_string, mean->meaning_string_length );
417 temp[ mean->meaning_string_length ] = 0;
418 metadata->meaning = (char *)temp;
420 else
421 metadata->meaning = NULL;
422 /* Get 'name'. */
423 isom_name_t *name = metaitem->name;
424 if( LSMASH_IS_NON_EXISTING_BOX( name ) )
426 uint8_t *temp = lsmash_malloc( name->name_length + 1 );
427 if( !temp )
428 goto fail;
429 memcpy( temp, name->name, name->name_length );
430 temp[ name->name_length ] = 0;
431 metadata->name = (char *)temp;
433 else
434 metadata->name = NULL;
435 /* Get 'value'. */
436 isom_data_t *data = metaitem->data;
437 switch( metadata->type )
439 case ITUNES_METADATA_TYPE_STRING :
441 uint8_t *temp = lsmash_malloc( data->value_length + 1 );
442 if( !temp )
443 goto fail;
444 memcpy( temp, data->value, data->value_length );
445 temp[ data->value_length ] = 0;
446 metadata->value.string = (char *)temp;
447 break;
449 case ITUNES_METADATA_TYPE_INTEGER :
450 if( data->value_length > 8 )
452 err = LSMASH_ERR_INVALID_DATA;
453 goto fail;
455 metadata->value.integer = 0;
456 for( uint32_t i = 0; i < data->value_length; i++ )
458 int shift = (data->value_length - i - 1) * 8;
459 metadata->value.integer |= (uint64_t)data->value[i] << shift;
461 break;
462 case ITUNES_METADATA_TYPE_BOOLEAN :
463 metadata->value.boolean = !!data->value[0];
464 break;
465 default :
466 metadata->type = ITUNES_METADATA_TYPE_BINARY;
467 metadata->value.binary.subtype = data->type_code;
468 metadata->value.binary.size = data->value_length;
469 metadata->value.binary.data = lsmash_memdup( data->value, data->value_length );
470 if( !metadata->value.binary.data )
471 goto fail;
472 break;
474 return 0;
475 fail:
476 lsmash_freep( &metadata->meaning );
477 lsmash_freep( &metadata->name );
478 return err;
481 uint32_t lsmash_count_itunes_metadata( lsmash_root_t *root )
483 if( isom_check_initializer_present( root ) < 0
484 || !root->file->initializer->moov->udta->meta->ilst )
485 return 0;
486 return root->file->initializer->moov->udta->meta->ilst->metaitem_list.entry_count;
489 void lsmash_cleanup_itunes_metadata( lsmash_itunes_metadata_t *metadata )
491 if( !metadata )
492 return;
493 lsmash_freep( &metadata->meaning );
494 lsmash_freep( &metadata->name );
495 if( metadata->type == ITUNES_METADATA_TYPE_STRING )
496 lsmash_freep( &metadata->value.string );
497 else if( metadata->type == ITUNES_METADATA_TYPE_BINARY )
498 lsmash_freep( &metadata->value.binary.data );