9 #elif defined(_MSC_VER)
10 # define SCNd64 "I64d"
22 typedef struct tag_key_mapping_t
{
32 static tag_key_mapping_t tag_mapping_table
[] = {
33 { "album", M4AF_TAG_ALBUM
},
34 { "albumartist", M4AF_TAG_ALBUM_ARTIST
},
35 { "albumartistsort", M4AF_FOURCC('s','o','a','a') },
36 { "albumartistsortorder", M4AF_FOURCC('s','o','a','a') },
37 { "albumsort", M4AF_FOURCC('s','o','a','l') },
38 { "albumsortorder", M4AF_FOURCC('s','o','a','l') },
39 { "artist", M4AF_TAG_ARTIST
},
40 { "artistsort", M4AF_FOURCC('s','o','a','r') },
41 { "artistsortorder", M4AF_FOURCC('s','o','a','r') },
42 { "band", M4AF_TAG_ALBUM_ARTIST
},
43 { "bpm", M4AF_TAG_TEMPO
},
44 { "comment", M4AF_TAG_COMMENT
},
45 { "compilation", M4AF_TAG_COMPILATION
},
46 { "composer", M4AF_TAG_COMPOSER
},
47 { "composersort", M4AF_FOURCC('s','o','c','o') },
48 { "composersortorder", M4AF_FOURCC('s','o','c','o') },
49 { "contentgroup", M4AF_TAG_GROUPING
},
50 { "copyright", M4AF_TAG_COPYRIGHT
},
51 { "date", M4AF_TAG_DATE
},
52 { "disc", M4AF_TAG_DISK
},
53 { "disctotal", TAG_TOTAL_DISCS
},
54 { "discnumber", M4AF_TAG_DISK
},
55 { "genre", M4AF_TAG_GENRE
},
56 { "grouping", M4AF_TAG_GROUPING
},
57 { "itunescompilation", M4AF_TAG_COMPILATION
},
58 { "lyrics", M4AF_TAG_LYRICS
},
59 { "title", M4AF_TAG_TITLE
},
60 { "titlesort", M4AF_FOURCC('s','o','n','m') },
61 { "titlesortorder", M4AF_FOURCC('s','o','n','m') },
62 { "totaldiscs", TAG_TOTAL_DISCS
},
63 { "totaltracks", TAG_TOTAL_TRACKS
},
64 { "track", M4AF_TAG_TRACK
},
65 { "tracknumber", M4AF_TAG_TRACK
},
66 { "tracktotal", TAG_TOTAL_TRACKS
},
67 { "unsyncedlyrics", M4AF_TAG_LYRICS
},
68 { "year", M4AF_TAG_DATE
},
72 int tag_key_comparator(const void *k
, const void *v
)
74 return strcmp((const char *)k
, ((tag_key_mapping_t
*)v
)->name
);
78 uint32_t get_tag_fcc_from_name(const char *name
)
81 const tag_key_mapping_t
*ent
;
83 name_p
= malloc(strlen(name
) + 1);
84 for (p
= name_p
; *name
; ++name
) {
85 unsigned char c
= *name
;
86 if (c
!= ' ' && c
!= '-' && c
!= '_')
90 ent
= bsearch(name_p
, tag_mapping_table
,
91 sizeof(tag_mapping_table
) / sizeof(tag_mapping_table
[0]),
92 sizeof(tag_mapping_table
[0]),
95 return ent
? ent
->fcc
: 0;
98 char *aacenc_load_tag_from_file(const char *path
, uint32_t *data_size
)
104 if ((fp
= aacenc_fopen(path
, "rb")) == NULL
) {
105 aacenc_fprintf(stderr
, "WARNING: %s: %s\n", path
, strerror(errno
));
108 fseeko(fp
, 0, SEEK_END
);
110 if (size
> 5*1024*1024) {
111 aacenc_fprintf(stderr
, "WARNING: %s: size too large\n", path
);
114 fseeko(fp
, 0, SEEK_SET
);
115 data
= malloc(size
+ 1);
116 if (data
) fread(data
, 1, size
, fp
);
118 *data_size
= (uint32_t)size
;
124 void aacenc_param_add_itmf_entry(aacenc_tag_param_t
*params
, uint32_t tag
,
125 const char *key
, const char *value
,
126 uint32_t size
, int is_file_name
)
128 aacenc_tag_entry_t
*entry
;
130 if (!is_file_name
&& !size
)
132 if (params
->tag_count
== params
->tag_table_capacity
) {
133 unsigned newsize
= params
->tag_table_capacity
;
134 newsize
= newsize
? newsize
* 2 : 1;
136 realloc(params
->tag_table
, newsize
* sizeof(aacenc_tag_entry_t
));
137 params
->tag_table_capacity
= newsize
;
139 entry
= params
->tag_table
+ params
->tag_count
;
141 if (tag
== M4AF_FOURCC('-','-','-','-'))
144 entry
->data_size
= size
;
145 entry
->is_file_name
= is_file_name
;
150 void tag_put_number_pair(m4af_ctx_t
*m4af
, uint32_t fcc
,
151 const char *snumber
, const char *stotal
)
153 unsigned number
= 0, total
= 0;
155 aacenc_tag_entry_t entry
= { 0 };
157 if (snumber
) sscanf(snumber
, "%u", &number
);
158 if (stotal
) sscanf(stotal
, "%u", &total
);
160 if (total
) sprintf(buf
, "%u/%u", number
, total
);
161 else sprintf(buf
, "%u", number
);
164 entry
.data_size
= strlen(buf
);
165 aacenc_put_tag_entry(m4af
, &entry
);
169 void aacenc_put_tags_from_json(m4af_ctx_t
*m4af
, const char *json_filename
)
172 JSON_Value
*json
= 0;
180 char *total_discs
= 0;
181 char *total_tracks
= 0;
182 aacenc_tag_entry_t entry
= { 0 };
184 filename
= strdup(json_filename
);
185 if ((json_dot_path
= strchr(filename
, '?')) != 0)
186 *json_dot_path
++ = '\0';
188 if (!(data
= aacenc_load_tag_from_file(filename
, &data_size
)))
190 if (!(json
= json_parse_string(data
))) {
191 aacenc_fprintf(stderr
, "WARNING: failed to parse JSON\n");
194 root
= json_value_get_object(json
);
196 if (!(root
= json_object_dotget_object(root
, json_dot_path
))) {
197 aacenc_fprintf(stderr
, "WARNING: %s not found in JSON\n",
202 nelts
= json_object_get_count(root
);
203 for (i
= 0; i
< nelts
; ++i
) {
208 JSON_Value_Type type
;
210 key
= json_object_get_name(root
, i
);
211 type
= json_value_get_type(json_object_get_value(root
, key
));
212 if (type
== JSONString
)
213 val
= json_object_get_string(root
, key
);
214 else if (type
== JSONNumber
) {
215 double num
= json_object_get_number(root
, key
);
216 sprintf(buf
, "%g", num
);
218 } else if (type
== JSONBoolean
) {
219 int n
= json_object_get_boolean(root
, key
);
220 sprintf(buf
, "%d", n
);
223 fcc
= get_tag_fcc_from_name(key
);
228 case TAG_TOTAL_DISCS
:
229 total_discs
= strdup(val
); break;
230 case TAG_TOTAL_TRACKS
:
231 total_tracks
= strdup(val
); break;
233 disc
= strdup(val
); break;
235 track
= strdup(val
); break;
240 entry
.data_size
= strlen(val
);
241 aacenc_put_tag_entry(m4af
, &entry
);
245 tag_put_number_pair(m4af
, M4AF_TAG_TRACK
, track
, total_tracks
);
246 tag_put_number_pair(m4af
, M4AF_TAG_DISK
, disc
, total_discs
);
248 if (track
) free(track
);
249 if (disc
) free(disc
);
250 if (total_tracks
) free(total_tracks
);
251 if (total_discs
) free(total_discs
);
252 if (data
) free(data
);
253 if (filename
) free(filename
);
254 if (json
) json_value_free(json
);
257 void aacenc_put_tag_entry(m4af_ctx_t
*m4af
, const aacenc_tag_entry_t
*tag
)
260 const char *data
= tag
->data
;
261 uint32_t data_size
= tag
->data_size
;
262 char *file_contents
= 0;
264 if (tag
->is_file_name
) {
265 data
= file_contents
= aacenc_load_tag_from_file(tag
->data
, &data_size
);
270 if (sscanf(data
, "%u/%u", &m
, &n
) >= 1)
271 m4af_add_itmf_track_tag(m4af
, m
, n
);
274 if (sscanf(data
, "%u/%u", &m
, &n
) >= 1)
275 m4af_add_itmf_disk_tag(m4af
, m
, n
);
277 case M4AF_TAG_GENRE_ID3
:
278 if (sscanf(data
, "%u", &n
) == 1)
279 m4af_add_itmf_genre_tag(m4af
, n
);
282 if (sscanf(data
, "%u", &n
) == 1)
283 m4af_add_itmf_int16_tag(m4af
, tag
->tag
, n
);
285 case M4AF_TAG_COMPILATION
:
286 case M4AF_FOURCC('a','k','I','D'):
287 case M4AF_FOURCC('h','d','v','d'):
288 case M4AF_FOURCC('p','c','s','t'):
289 case M4AF_FOURCC('p','g','a','p'):
290 case M4AF_FOURCC('r','t','n','g'):
291 case M4AF_FOURCC('s','t','i','k'):
292 if (sscanf(data
, "%u", &n
) == 1)
293 m4af_add_itmf_int8_tag(m4af
, tag
->tag
, n
);
295 case M4AF_FOURCC('a','t','I','D'):
296 case M4AF_FOURCC('c','m','I','D'):
297 case M4AF_FOURCC('c','n','I','D'):
298 case M4AF_FOURCC('g','e','I','D'):
299 case M4AF_FOURCC('s','f','I','D'):
300 case M4AF_FOURCC('t','v','s','n'):
301 case M4AF_FOURCC('t','v','s','s'):
302 if (sscanf(data
, "%u", &n
) == 1)
303 m4af_add_itmf_int32_tag(m4af
, tag
->tag
, n
);
305 case M4AF_FOURCC('p','l','I','D'):
308 if (sscanf(data
, "%" SCNd64
, &qn
) == 1)
309 m4af_add_itmf_int64_tag(m4af
, tag
->tag
, qn
);
312 case M4AF_TAG_ARTWORK
:
315 if (!memcmp(data
, "GIF", 3))
316 data_type
= M4AF_GIF
;
317 else if (!memcmp(data
, "\xff\xd8\xff", 3))
318 data_type
= M4AF_JPEG
;
319 else if (!memcmp(data
, "\x89PNG", 4))
320 data_type
= M4AF_PNG
;
322 m4af_add_itmf_short_tag(m4af
, tag
->tag
, data_type
,
326 case M4AF_FOURCC('-','-','-','-'):
328 char *u8
= aacenc_to_utf8(data
);
329 m4af_add_itmf_long_tag(m4af
, tag
->name
, u8
);
334 case M4AF_TAG_ARTIST
:
338 case M4AF_TAG_COMPOSER
:
339 case M4AF_TAG_GROUPING
:
340 case M4AF_TAG_COMMENT
:
341 case M4AF_TAG_LYRICS
:
343 case M4AF_TAG_ALBUM_ARTIST
:
344 case M4AF_TAG_DESCRIPTION
:
345 case M4AF_TAG_LONG_DESCRIPTION
:
346 case M4AF_TAG_COPYRIGHT
:
347 case M4AF_FOURCC('a','p','I','D'):
348 case M4AF_FOURCC('c','a','t','g'):
349 case M4AF_FOURCC('k','e','y','w'):
350 case M4AF_FOURCC('p','u','r','d'):
351 case M4AF_FOURCC('p','u','r','l'):
352 case M4AF_FOURCC('s','o','a','a'):
353 case M4AF_FOURCC('s','o','a','l'):
354 case M4AF_FOURCC('s','o','a','r'):
355 case M4AF_FOURCC('s','o','c','o'):
356 case M4AF_FOURCC('s','o','n','m'):
357 case M4AF_FOURCC('s','o','s','n'):
358 case M4AF_FOURCC('t','v','e','n'):
359 case M4AF_FOURCC('t','v','n','n'):
360 case M4AF_FOURCC('t','v','s','h'):
361 case M4AF_FOURCC('x','i','d',' '):
362 case M4AF_FOURCC('\xa9','e','n','c'):
363 case M4AF_FOURCC('\xa9','s','t','3'):
365 char *u8
= aacenc_to_utf8(data
);
366 m4af_add_itmf_string_tag(m4af
, tag
->tag
, u8
);
371 fprintf(stderr
, "WARNING: unknown/unsupported tag: %c%c%c%c\n",
372 tag
->tag
>> 24, (tag
->tag
>> 16) & 0xff,
373 (tag
->tag
>> 8) & 0xff, tag
->tag
& 0xff);
375 if (file_contents
) free(file_contents
);