1 /*****************************************************************************
2 * meta.c: mp4 meta handling
3 *****************************************************************************
4 * Copyright (C) 2001-2004, 2010, 2014 VLC authors and VideoLAN
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
23 #include "id3genres.h" /* for ATOM_gnre */
26 #include <vlc_charset.h>
32 const uint32_t xa9_type;
33 const vlc_meta_type_t meta_type;
35 { ATOM_0xa9nam, vlc_meta_Title }, /* Full name */
36 { ATOM_0xa9aut, vlc_meta_Artist },
37 { ATOM_0xa9ART, vlc_meta_Artist },
38 { ATOM_0xa9cpy, vlc_meta_Copyright },
39 { ATOM_0xa9day, vlc_meta_Date }, /* Creation Date */
40 { ATOM_0xa9des, vlc_meta_Description }, /* Description */
41 { ATOM_0xa9gen, vlc_meta_Genre }, /* Genre */
42 { ATOM_0xa9alb, vlc_meta_Album }, /* Album */
43 { ATOM_0xa9trk, vlc_meta_TrackNumber }, /* Track */
44 { ATOM_0xa9cmt, vlc_meta_Description }, /* Comment */
45 { ATOM_0xa9url, vlc_meta_URL }, /* URL */
46 { ATOM_0xa9too, vlc_meta_EncodedBy }, /* Encoder Tool */
47 { ATOM_0xa9enc, vlc_meta_EncodedBy }, /* Encoded By */
48 { ATOM_0xa9pub, vlc_meta_Publisher },
49 { ATOM_0xa9dir, vlc_meta_Director },
55 const uint32_t xa9_type;
56 const char metadata[25];
57 } xa9typetoextrameta[] = {
58 { ATOM_0xa9wrt, N_("Writer") },
59 { ATOM_0xa9com, N_("Composer") },
60 { ATOM_0xa9prd, N_("Producer") },
61 { ATOM_0xa9inf, N_("Information") },
62 { ATOM_0xa9dis, N_("Disclaimer") },
63 { ATOM_0xa9req, N_("Requirements") },
64 { ATOM_0xa9fmt, N_("Original Format") },
65 { ATOM_0xa9dsa, N_("Display Source As") },
66 { ATOM_0xa9hst, N_("Host Computer") },
67 { ATOM_0xa9prf, N_("Performers") },
68 { ATOM_0xa9ope, N_("Original Performer") },
69 { ATOM_0xa9src, N_("Providers Source Content") },
70 { ATOM_0xa9wrn, N_("Warning") },
71 { ATOM_0xa9swr, N_("Software") },
72 { ATOM_0xa9lyr, N_("Lyrics") },
73 { ATOM_0xa9mak, N_("Record Company") },
74 { ATOM_0xa9mod, N_("Model") },
75 { ATOM_0xa9PRD, N_("Product") },
76 { ATOM_0xa9grp, N_("Grouping") },
77 { ATOM_0xa9gen, N_("Genre") },
78 { ATOM_0xa9st3, N_("Sub-Title") },
79 { ATOM_0xa9arg, N_("Arranger") },
80 { ATOM_0xa9ard, N_("Art Director") },
81 { ATOM_0xa9cak, N_("Copyright Acknowledgement") },
82 { ATOM_0xa9con, N_("Conductor") },
83 { ATOM_0xa9des, N_("Song Description") },
84 { ATOM_0xa9lnt, N_("Liner Notes") },
85 { ATOM_0xa9phg, N_("Phonogram Rights") },
86 { ATOM_0xa9pub, N_("Publisher") },
87 { ATOM_0xa9sne, N_("Sound Engineer") },
88 { ATOM_0xa9sol, N_("Soloist") },
89 { ATOM_0xa9thx, N_("Thanks") },
90 { ATOM_0xa9xpd, N_("Executive Producer") },
91 { ATOM_vndr, N_("Vendor") },
97 const char *psz_naming;
98 const vlc_meta_type_t meta_type;
99 } com_apple_quicktime_tometa[] = {
100 { "displayname", vlc_meta_NowPlaying },
101 { "software", vlc_meta_EncodedBy },
102 { "Encoded_With", vlc_meta_EncodedBy },
103 { "album", vlc_meta_Album },
104 { "artist", vlc_meta_Artist },
105 { "comment", vlc_meta_Description },
106 { "description", vlc_meta_Description },
107 { "copyright", vlc_meta_Copyright },
108 { "creationdate", vlc_meta_Date },
109 { "director", vlc_meta_Director },
110 { "genre", vlc_meta_Genre },
111 { "publisher", vlc_meta_Publisher },
117 const char *psz_naming;
118 const char *psz_metadata;
119 } com_apple_quicktime_toextrameta[] = {
120 { "information", N_("Information") },
121 { "keywords", N_("Keywords") },
122 { "make", N_("Vendor") },
126 inline static char * StringConvert( const MP4_Box_data_data_t *p_data )
128 if ( !p_data || !p_data->i_blob )
131 switch( p_data->e_wellknowntype )
134 case DATA_WKT_UTF8_SORT:
135 return FromCharset( "UTF-8", p_data->p_blob, p_data->i_blob );
137 case DATA_WKT_UTF16_SORT:
138 return FromCharset( "UTF-16BE", p_data->p_blob, p_data->i_blob );
140 return FromCharset( "SHIFT-JIS", p_data->p_blob, p_data->i_blob );
146 static char * ExtractString( MP4_Box_t *p_box )
148 if ( p_box->i_type == ATOM_data )
149 return StringConvert( p_box->data.p_data );
151 MP4_Box_t *p_data = MP4_BoxGet( p_box, "data" );
153 return StringConvert( BOXDATA(p_data) );
154 else if ( p_box->data.p_string && p_box->data.p_string->psz_text )
156 char *psz_utf = strdup( p_box->data.p_string->psz_text );
157 if (likely( psz_utf ))
158 EnsureUTF8( psz_utf );
165 static bool MatchXA9Type( vlc_meta_t *p_meta, uint32_t i_type, MP4_Box_t *p_box )
167 bool b_matched = false;
169 for( unsigned i = 0; !b_matched && xa9typetometa[i].xa9_type; i++ )
171 if( i_type == xa9typetometa[i].xa9_type )
174 char *psz_utf = ExtractString( p_box );
177 vlc_meta_Set( p_meta, xa9typetometa[i].meta_type, psz_utf );
184 for( unsigned i = 0; !b_matched && xa9typetoextrameta[i].xa9_type; i++ )
186 if( i_type == xa9typetoextrameta[i].xa9_type )
189 char *psz_utf = ExtractString( p_box );
192 vlc_meta_AddExtra( p_meta, _(xa9typetoextrameta[i].metadata), psz_utf );
202 static bool Matchcom_apple_quicktime( vlc_meta_t *p_meta, const char *psz_naming, MP4_Box_t *p_box )
204 bool b_matched = false;
206 for( unsigned i = 0; !b_matched && com_apple_quicktime_tometa[i].psz_naming; i++ )
208 if( !strcmp( psz_naming, com_apple_quicktime_tometa[i].psz_naming ) )
211 char *psz_utf = ExtractString( p_box );
214 vlc_meta_Set( p_meta, com_apple_quicktime_tometa[i].meta_type, psz_utf );
221 for( unsigned i = 0; !b_matched && com_apple_quicktime_toextrameta[i].psz_naming; i++ )
223 if( !strcmp( psz_naming, com_apple_quicktime_toextrameta[i].psz_naming ) )
226 char *psz_utf = ExtractString( p_box );
229 vlc_meta_AddExtra( p_meta, _(com_apple_quicktime_toextrameta[i].psz_metadata), psz_utf );
239 static void SetupmdirMeta( vlc_meta_t *p_meta, MP4_Box_t *p_box )
241 bool b_matched = true;
242 /* XXX Becarefull p_udta can have box that are not 0xa9xx */
243 switch( p_box->i_type )
246 if( p_box->data.p_gnre && p_box->data.p_gnre->i_genre <= NUM_GENRES )
247 vlc_meta_SetGenre( p_meta, ppsz_genres[p_box->data.p_gnre->i_genre - 1] );
251 const MP4_Box_t *p_data = MP4_BoxGet( p_box, "data" );
252 if ( p_data && BOXDATA(p_data) && BOXDATA(p_data)->i_blob >= 4 &&
253 BOXDATA(p_data)->e_wellknowntype == DATA_WKT_RESERVED )
256 snprintf( psz_trck, sizeof( psz_trck ), "%"PRIu16, GetWBE(&BOXDATA(p_data)->p_blob[2]) );
257 vlc_meta_SetTrackNum( p_meta, psz_trck );
258 if( BOXDATA(p_data)->i_blob >= 8 )
260 snprintf( psz_trck, sizeof( psz_trck ), "%"PRIu16, GetWBE(&BOXDATA(p_data)->p_blob[4]) );
261 vlc_meta_Set( p_meta, vlc_meta_TrackTotal, psz_trck );
273 MatchXA9Type( p_meta, p_box->i_type, p_box );
276 static void SetupmdtaMeta( vlc_meta_t *p_meta, MP4_Box_t *p_box, MP4_Box_t *p_keys )
278 if ( !p_keys || !BOXDATA(p_keys) || BOXDATA(p_keys)->i_entry_count == 0 )
280 if ( !p_box->i_index || p_box->i_index > BOXDATA(p_keys)->i_entry_count )
283 const char *psz_naming = BOXDATA(p_keys)->p_entries[p_box->i_index - 1].psz_value;
284 const uint32_t i_namespace = BOXDATA(p_keys)->p_entries[p_box->i_index - 1].i_namespace;
286 if( i_namespace == HANDLER_mdta )
288 if ( !strncmp( "com.apple.quicktime.", psz_naming, 20 ) )
290 Matchcom_apple_quicktime( p_meta, psz_naming + 20, p_box );
293 else if ( i_namespace == ATOM_udta )
295 /* Regular atom inside... could that be even more complex ??? */
296 char *psz_utf = ExtractString( p_box );
299 if ( strlen(psz_utf) == 4 )
301 MatchXA9Type( p_meta,
302 VLC_FOURCC(psz_utf[0],psz_utf[1],psz_utf[2],psz_utf[3]),
310 void SetupMeta( vlc_meta_t *p_meta, MP4_Box_t *p_udta )
312 uint32_t i_handler = 0;
313 if ( p_udta->p_father )
314 i_handler = p_udta->i_handler;
316 for( MP4_Box_t *p_box = p_udta->p_first; p_box; p_box = p_box->p_next )
322 MP4_Box_t *p_keys = MP4_BoxGet( p_udta->p_father, "keys" );
323 SetupmdtaMeta( p_meta, p_box, p_keys );
329 SetupmdirMeta( p_meta, p_box );