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
);
170 const char *aacenc_json_object_get_string(JSON_Object
*obj
, const char *key
,
173 JSON_Value_Type type
;
176 type
= json_value_get_type(json_object_get_value(obj
, key
));
177 if (type
== JSONString
)
178 val
= json_object_get_string(obj
, key
);
179 else if (type
== JSONNumber
) {
180 double num
= json_object_get_number(obj
, key
);
181 sprintf(buf
, "%.15g", num
);
183 } else if (type
== JSONBoolean
) {
184 int n
= json_object_get_boolean(obj
, key
);
185 sprintf(buf
, "%d", n
);
191 void aacenc_put_tags_from_json(m4af_ctx_t
*m4af
, const char *json_filename
)
194 JSON_Value
*json
= 0;
202 char *total_discs
= 0;
203 char *total_tracks
= 0;
204 aacenc_tag_entry_t entry
= { 0 };
206 filename
= strdup(json_filename
);
207 if ((json_dot_path
= strchr(filename
, '?')) != 0)
208 *json_dot_path
++ = '\0';
210 if (!(data
= aacenc_load_tag_from_file(filename
, &data_size
)))
212 if (!(json
= json_parse_string(data
))) {
213 aacenc_fprintf(stderr
, "WARNING: failed to parse JSON\n");
216 root
= json_value_get_object(json
);
218 if (!(root
= json_object_dotget_object(root
, json_dot_path
))) {
219 aacenc_fprintf(stderr
, "WARNING: %s not found in JSON\n",
224 nelts
= json_object_get_count(root
);
225 for (i
= 0; i
< nelts
; ++i
) {
227 const char *key
= json_object_get_name(root
, i
);
228 const char *val
= aacenc_json_object_get_string(root
, key
, buf
);
229 uint32_t fcc
= get_tag_fcc_from_name(key
);
234 case TAG_TOTAL_DISCS
:
235 total_discs
= realloc(total_discs
, strlen(val
) + 1);
236 strcpy(total_discs
, val
);
238 case TAG_TOTAL_TRACKS
:
239 total_tracks
= realloc(total_tracks
, strlen(val
) + 1);
240 strcpy(total_tracks
, val
);
243 disc
= realloc(disc
, strlen(val
) + 1);
247 track
= realloc(track
, strlen(val
) + 1);
254 entry
.data_size
= strlen(val
);
255 aacenc_put_tag_entry(m4af
, &entry
);
259 tag_put_number_pair(m4af
, M4AF_TAG_TRACK
, track
, total_tracks
);
260 tag_put_number_pair(m4af
, M4AF_TAG_DISK
, disc
, total_discs
);
262 if (track
) free(track
);
263 if (disc
) free(disc
);
264 if (total_tracks
) free(total_tracks
);
265 if (total_discs
) free(total_discs
);
266 if (data
) free(data
);
267 if (filename
) free(filename
);
268 if (json
) json_value_free(json
);
271 void aacenc_put_tag_entry(m4af_ctx_t
*m4af
, const aacenc_tag_entry_t
*tag
)
274 const char *data
= tag
->data
;
275 uint32_t data_size
= tag
->data_size
;
276 char *file_contents
= 0;
278 if (tag
->is_file_name
) {
279 data
= file_contents
= aacenc_load_tag_from_file(tag
->data
, &data_size
);
284 if (sscanf(data
, "%u/%u", &m
, &n
) >= 1)
285 m4af_add_itmf_track_tag(m4af
, m
, n
);
288 if (sscanf(data
, "%u/%u", &m
, &n
) >= 1)
289 m4af_add_itmf_disk_tag(m4af
, m
, n
);
291 case M4AF_TAG_GENRE_ID3
:
292 if (sscanf(data
, "%u", &n
) == 1)
293 m4af_add_itmf_genre_tag(m4af
, n
);
296 if (sscanf(data
, "%u", &n
) == 1)
297 m4af_add_itmf_int16_tag(m4af
, tag
->tag
, n
);
299 case M4AF_TAG_COMPILATION
:
300 case M4AF_FOURCC('a','k','I','D'):
301 case M4AF_FOURCC('h','d','v','d'):
302 case M4AF_FOURCC('p','c','s','t'):
303 case M4AF_FOURCC('p','g','a','p'):
304 case M4AF_FOURCC('r','t','n','g'):
305 case M4AF_FOURCC('s','t','i','k'):
306 if (sscanf(data
, "%u", &n
) == 1)
307 m4af_add_itmf_int8_tag(m4af
, tag
->tag
, n
);
309 case M4AF_FOURCC('a','t','I','D'):
310 case M4AF_FOURCC('c','m','I','D'):
311 case M4AF_FOURCC('c','n','I','D'):
312 case M4AF_FOURCC('g','e','I','D'):
313 case M4AF_FOURCC('s','f','I','D'):
314 case M4AF_FOURCC('t','v','s','n'):
315 case M4AF_FOURCC('t','v','s','s'):
316 if (sscanf(data
, "%u", &n
) == 1)
317 m4af_add_itmf_int32_tag(m4af
, tag
->tag
, n
);
319 case M4AF_FOURCC('p','l','I','D'):
322 if (sscanf(data
, "%" SCNd64
, &qn
) == 1)
323 m4af_add_itmf_int64_tag(m4af
, tag
->tag
, qn
);
326 case M4AF_TAG_ARTWORK
:
329 if (!memcmp(data
, "GIF", 3))
330 data_type
= M4AF_GIF
;
331 else if (!memcmp(data
, "\xff\xd8\xff", 3))
332 data_type
= M4AF_JPEG
;
333 else if (!memcmp(data
, "\x89PNG", 4))
334 data_type
= M4AF_PNG
;
336 m4af_add_itmf_short_tag(m4af
, tag
->tag
, data_type
,
340 case M4AF_FOURCC('-','-','-','-'):
342 char *u8
= aacenc_to_utf8(data
);
343 m4af_add_itmf_long_tag(m4af
, tag
->name
, u8
);
348 case M4AF_TAG_ARTIST
:
352 case M4AF_TAG_COMPOSER
:
353 case M4AF_TAG_GROUPING
:
354 case M4AF_TAG_COMMENT
:
355 case M4AF_TAG_LYRICS
:
357 case M4AF_TAG_ALBUM_ARTIST
:
358 case M4AF_TAG_DESCRIPTION
:
359 case M4AF_TAG_LONG_DESCRIPTION
:
360 case M4AF_TAG_COPYRIGHT
:
361 case M4AF_FOURCC('a','p','I','D'):
362 case M4AF_FOURCC('c','a','t','g'):
363 case M4AF_FOURCC('k','e','y','w'):
364 case M4AF_FOURCC('p','u','r','d'):
365 case M4AF_FOURCC('p','u','r','l'):
366 case M4AF_FOURCC('s','o','a','a'):
367 case M4AF_FOURCC('s','o','a','l'):
368 case M4AF_FOURCC('s','o','a','r'):
369 case M4AF_FOURCC('s','o','c','o'):
370 case M4AF_FOURCC('s','o','n','m'):
371 case M4AF_FOURCC('s','o','s','n'):
372 case M4AF_FOURCC('t','v','e','n'):
373 case M4AF_FOURCC('t','v','n','n'):
374 case M4AF_FOURCC('t','v','s','h'):
375 case M4AF_FOURCC('x','i','d',' '):
376 case M4AF_FOURCC('\xa9','e','n','c'):
377 case M4AF_FOURCC('\xa9','s','t','3'):
379 char *u8
= aacenc_to_utf8(data
);
380 m4af_add_itmf_string_tag(m4af
, tag
->tag
, u8
);
385 fprintf(stderr
, "WARNING: unknown/unsupported tag: %c%c%c%c\n",
386 tag
->tag
>> 24, (tag
->tag
>> 16) & 0xff,
387 (tag
->tag
>> 8) & 0xff, tag
->tag
& 0xff);
389 if (file_contents
) free(file_contents
);