From 3b666b75460f004b8c451f3390d1ef87c19f0bb7 Mon Sep 17 00:00:00 2001 From: nu774 Date: Wed, 23 Oct 2013 23:35:23 +0900 Subject: [PATCH] cleanup metadata handling --- src/main.c | 18 ++-- src/metadata.c | 278 ++++++++++++++++++++++++++++--------------------- src/metadata.h | 42 +++++--- 3 files changed, 199 insertions(+), 139 deletions(-) diff --git a/src/main.c b/src/main.c index f4cc14c..83fb754 100644 --- a/src/main.c +++ b/src/main.c @@ -216,7 +216,7 @@ typedef struct aacenc_param_ex_t { unsigned raw_rate; const char *raw_format; - aacenc_tag_param_t tags; + aacenc_tag_store_t tags; char *json_filename; } aacenc_param_ex_t; @@ -398,8 +398,8 @@ int parse_options(int argc, char **argv, aacenc_param_ex_t *params) case M4AF_TAG_TRACK: case M4AF_TAG_DISK: case M4AF_TAG_TEMPO: - aacenc_param_add_itmf_entry(¶ms->tags, ch, 0, optarg, - strlen(optarg), 0); + aacenc_add_tag_to_store(¶ms->tags, ch, 0, optarg, + strlen(optarg), 0); break; case OPT_SHORT_TAG: case OPT_SHORT_TAG_FILE: @@ -432,9 +432,9 @@ int parse_options(int argc, char **argv, aacenc_param_ex_t *params) for (; *optarg; ++optarg) fcc = ((fcc << 8) | (*optarg & 0xff)); } - aacenc_param_add_itmf_entry(¶ms->tags, fcc, optarg, - val, strlen(val), - ch == OPT_SHORT_TAG_FILE); + aacenc_add_tag_to_store(¶ms->tags, fcc, optarg, + val, strlen(val), + ch == OPT_SHORT_TAG_FILE); } break; case OPT_TAG_FROM_JSON: @@ -573,10 +573,10 @@ int finalize_m4a(m4af_ctx_t *m4af, const aacenc_param_ex_t *params, aacenc_tag_entry_t *tag = params->tags.tag_table; if (params->json_filename) - aacenc_put_tags_from_json(m4af, params->json_filename); + aacenc_write_tags_from_json(m4af, params->json_filename); for (i = 0; i < params->tags.tag_count; ++i, ++tag) - aacenc_put_tag_entry(m4af, tag); + aacenc_write_tag_entry(m4af, tag); put_tool_tag(m4af, params, encoder); @@ -774,7 +774,7 @@ END: if (params.output_fp) fclose(params.output_fp); if (encoder) aacEncClose(&encoder); if (output_filename) free(output_filename); - if (params.tags.tag_table) free(params.tags.tag_table); + if (params.tags.tag_table) aacenc_free_tag_store(¶ms.tags); return result; } diff --git a/src/metadata.c b/src/metadata.c index 96b2f28..f2d4fb2 100644 --- a/src/metadata.c +++ b/src/metadata.c @@ -95,6 +95,7 @@ uint32_t get_tag_fcc_from_name(const char *name) return ent ? ent->fcc : 0; } +static char *aacenc_load_tag_from_file(const char *path, uint32_t *data_size) { FILE *fp = 0; @@ -121,48 +122,152 @@ END: return data; } -void aacenc_param_add_itmf_entry(aacenc_tag_param_t *params, uint32_t tag, - const char *key, const char *value, - uint32_t size, int is_file_name) +static +int aacenc_is_string_tag(uint32_t tag) { - aacenc_tag_entry_t *entry; + switch (tag) { + case M4AF_TAG_TITLE: + case M4AF_TAG_ARTIST: + case M4AF_TAG_ALBUM: + case M4AF_TAG_GENRE: + case M4AF_TAG_DATE: + case M4AF_TAG_COMPOSER: + case M4AF_TAG_GROUPING: + case M4AF_TAG_COMMENT: + case M4AF_TAG_LYRICS: + case M4AF_TAG_TOOL: + case M4AF_TAG_ALBUM_ARTIST: + case M4AF_TAG_DESCRIPTION: + case M4AF_TAG_LONG_DESCRIPTION: + case M4AF_TAG_COPYRIGHT: + case M4AF_FOURCC('a','p','I','D'): + case M4AF_FOURCC('c','a','t','g'): + case M4AF_FOURCC('k','e','y','w'): + case M4AF_FOURCC('p','u','r','d'): + case M4AF_FOURCC('p','u','r','l'): + case M4AF_FOURCC('s','o','a','a'): + case M4AF_FOURCC('s','o','a','l'): + case M4AF_FOURCC('s','o','a','r'): + case M4AF_FOURCC('s','o','c','o'): + case M4AF_FOURCC('s','o','n','m'): + case M4AF_FOURCC('s','o','s','n'): + case M4AF_FOURCC('t','v','e','n'): + case M4AF_FOURCC('t','v','n','n'): + case M4AF_FOURCC('t','v','s','h'): + case M4AF_FOURCC('x','i','d',' '): + case M4AF_FOURCC('\xa9','e','n','c'): + case M4AF_FOURCC('\xa9','s','t','3'): + case M4AF_FOURCC('-','-','-','-'): + return 1; + } + return 0; +} + +void aacenc_add_tag_to_store(aacenc_tag_store_t *store, uint32_t tag, + const char *key, const char *value, + uint32_t size, int is_file_name) +{ + aacenc_tag_entry_t entry = { 0 }; + char *dp = 0; if (!is_file_name && !size) return; - if (params->tag_count == params->tag_table_capacity) { - unsigned newsize = params->tag_table_capacity; + entry.tag = tag; + if (tag == M4AF_FOURCC('-','-','-','-')) + entry.name = (char *)key; + + if (is_file_name) { + entry.data = dp = aacenc_load_tag_from_file(value, &size); + entry.data_size = size; + } else if (aacenc_is_string_tag(tag)) { + entry.data = dp = aacenc_to_utf8(value); + entry.data_size = strlen(entry.data); + } else { + entry.data = (char *)value; + entry.data_size = size; + } + aacenc_add_tag_entry_to_store(store, &entry); + free(dp); +} + +void aacenc_add_tag_entry_to_store(void *ctx, const aacenc_tag_entry_t *tag) +{ + aacenc_tag_store_t *store = ctx; + aacenc_tag_entry_t *entry; + if (store->tag_count == store->tag_table_capacity) { + unsigned newsize = store->tag_table_capacity; newsize = newsize ? newsize * 2 : 1; - params->tag_table = - realloc(params->tag_table, newsize * sizeof(aacenc_tag_entry_t)); - params->tag_table_capacity = newsize; + store->tag_table = + realloc(store->tag_table, newsize * sizeof(aacenc_tag_entry_t)); + store->tag_table_capacity = newsize; } - entry = params->tag_table + params->tag_count; - entry->tag = tag; - if (tag == M4AF_FOURCC('-','-','-','-')) - entry->name = key; - entry->data = value; - entry->data_size = size; - entry->is_file_name = is_file_name; - params->tag_count++; + entry = store->tag_table + store->tag_count; + entry->tag = tag->tag; + entry->data_size = tag->data_size; + entry->name = tag->name ? strdup(tag->name) : 0; + entry->data = malloc(tag->data_size + 1); + memcpy(entry->data, tag->data, tag->data_size); + entry->data[tag->data_size] = 0; + store->tag_count++; } static -void tag_put_number_pair(m4af_ctx_t *m4af, uint32_t fcc, - const char *snumber, const char *stotal) +void tag_put_number_pair(aacenc_translate_generic_text_tag_ctx_t *ctx, + uint32_t fcc, unsigned number, unsigned total) { - unsigned number = 0, total = 0; char buf[128]; aacenc_tag_entry_t entry = { 0 }; - if (snumber) sscanf(snumber, "%u/%u", &number, &total); - if (stotal) sscanf(stotal, "%u", &total); if (number) { if (total) sprintf(buf, "%u/%u", number, total); else sprintf(buf, "%u", number); entry.tag = fcc; entry.data = buf; entry.data_size = strlen(buf); - aacenc_put_tag_entry(m4af, &entry); + ctx->add(ctx->add_ctx, &entry); + } +} + +void aacenc_translate_generic_text_tag(void *pctx, const char *key, + const char *val, uint32_t size) +{ + aacenc_translate_generic_text_tag_ctx_t *ctx = pctx; + aacenc_tag_entry_t entry = { 0 }; + uint32_t fcc; + /* + * Since track/disc number pair (number and total) can be stored within + * either single tag or separately, we cannot instantly translate + * them in one-to-one manner. + * Instead, we keep and store them until all tags are processed, + * then finally submit. + */ + if (!key) { + /* use null key as flushing signal */ + tag_put_number_pair(ctx, M4AF_TAG_TRACK, ctx->track, ctx->track_total); + tag_put_number_pair(ctx, M4AF_TAG_DISK, ctx->disc, ctx->disc_total); + return; + } + if (!val || !size) + return; + if ((fcc = get_tag_fcc_from_name(key)) == 0) + return; + + switch (fcc) { + case TAG_TOTAL_DISCS: + sscanf(val, "%d", &ctx->disc_total); break; + case TAG_TOTAL_TRACKS: + sscanf(val, "%d", &ctx->track_total); break; + case M4AF_TAG_DISK: + sscanf(val, "%d/%d", &ctx->disc, &ctx->disc_total); break; + case M4AF_TAG_TRACK: + sscanf(val, "%d/%d", &ctx->track, &ctx->track_total); break; + default: + { + entry.tag = fcc; + entry.data = (char *)val; + entry.data_size = (size == ~0U) ? strlen(val) : size; + ctx->add(ctx->add_ctx, &entry); + } } } @@ -188,7 +293,7 @@ const char *aacenc_json_object_get_string(JSON_Object *obj, const char *key, return val; } -void aacenc_put_tags_from_json(m4af_ctx_t *m4af, const char *json_filename) +void aacenc_write_tags_from_json(m4af_ctx_t *m4af, const char *json_filename) { char *data = 0; JSON_Value *json = 0; @@ -197,12 +302,11 @@ void aacenc_put_tags_from_json(m4af_ctx_t *m4af, const char *json_filename) uint32_t data_size; char *json_dot_path; char *filename = 0; - char *disc = 0; - char *track = 0; - char *total_discs = 0; - char *total_tracks = 0; - aacenc_tag_entry_t entry = { 0 }; - + aacenc_translate_generic_text_tag_ctx_t ctx = { 0 }; + + ctx.add = aacenc_write_tag_entry; + ctx.add_ctx = m4af; + filename = strdup(json_filename); if ((json_dot_path = strchr(filename, '?')) != 0) *json_dot_path++ = '\0'; @@ -226,59 +330,36 @@ void aacenc_put_tags_from_json(m4af_ctx_t *m4af, const char *json_filename) char buf[256]; const char *key = json_object_get_name(root, i); const char *val = aacenc_json_object_get_string(root, key, buf); - uint32_t fcc = get_tag_fcc_from_name(key); - if (!val || !fcc) - continue; - - switch (fcc) { - case TAG_TOTAL_DISCS: - total_discs = realloc(total_discs, strlen(val) + 1); - strcpy(total_discs, val); - break; - case TAG_TOTAL_TRACKS: - total_tracks = realloc(total_tracks, strlen(val) + 1); - strcpy(total_tracks, val); - break; - case M4AF_TAG_DISK: - disc = realloc(disc, strlen(val) + 1); - strcpy(disc, val); - break; - case M4AF_TAG_TRACK: - track = realloc(track, strlen(val) + 1); - strcpy(track, val); - break; - default: - { - entry.tag = fcc; - entry.data = val; - entry.data_size = strlen(val); - aacenc_put_tag_entry(m4af, &entry); - } - } + if (val) aacenc_translate_generic_text_tag(&ctx, key, val, ~0U); } - tag_put_number_pair(m4af, M4AF_TAG_TRACK, track, total_tracks); - tag_put_number_pair(m4af, M4AF_TAG_DISK, disc, total_discs); + aacenc_translate_generic_text_tag(&ctx, 0, 0, 0); DONE: - if (track) free(track); - if (disc) free(disc); - if (total_tracks) free(total_tracks); - if (total_discs) free(total_discs); if (data) free(data); if (filename) free(filename); if (json) json_value_free(json); } -void aacenc_put_tag_entry(m4af_ctx_t *m4af, const aacenc_tag_entry_t *tag) +void aacenc_free_tag_store(aacenc_tag_store_t *store) +{ + if (store->tag_table) { + unsigned i; + for (i = 0; i < store->tag_count; ++i) { + aacenc_tag_entry_t *ent = &store->tag_table[i]; + free(ent->name); + free(ent->data); + } + free(store->tag_table); + store->tag_table = 0; + store->tag_count = 0; + } +} + +void aacenc_write_tag_entry(void *ctx, const aacenc_tag_entry_t *tag) { + m4af_ctx_t *m4af = ctx; unsigned m, n = 0; const char *data = tag->data; - uint32_t data_size = tag->data_size; - char *file_contents = 0; - if (tag->is_file_name) { - data = file_contents = aacenc_load_tag_from_file(tag->data, &data_size); - if (!data) return; - } switch (tag->tag) { case M4AF_TAG_TRACK: if (sscanf(data, "%u/%u", &m, &n) >= 1) @@ -334,59 +415,22 @@ void aacenc_put_tag_entry(m4af_ctx_t *m4af, const aacenc_tag_entry_t *tag) data_type = M4AF_PNG; if (data_type) m4af_add_itmf_short_tag(m4af, tag->tag, data_type, - data, data_size); + data, tag->data_size); break; } case M4AF_FOURCC('-','-','-','-'): { - char *u8 = aacenc_to_utf8(data); - m4af_add_itmf_long_tag(m4af, tag->name, u8); - free(u8); - break; - } - case M4AF_TAG_TITLE: - case M4AF_TAG_ARTIST: - case M4AF_TAG_ALBUM: - case M4AF_TAG_GENRE: - case M4AF_TAG_DATE: - case M4AF_TAG_COMPOSER: - case M4AF_TAG_GROUPING: - case M4AF_TAG_COMMENT: - case M4AF_TAG_LYRICS: - case M4AF_TAG_TOOL: - case M4AF_TAG_ALBUM_ARTIST: - case M4AF_TAG_DESCRIPTION: - case M4AF_TAG_LONG_DESCRIPTION: - case M4AF_TAG_COPYRIGHT: - case M4AF_FOURCC('a','p','I','D'): - case M4AF_FOURCC('c','a','t','g'): - case M4AF_FOURCC('k','e','y','w'): - case M4AF_FOURCC('p','u','r','d'): - case M4AF_FOURCC('p','u','r','l'): - case M4AF_FOURCC('s','o','a','a'): - case M4AF_FOURCC('s','o','a','l'): - case M4AF_FOURCC('s','o','a','r'): - case M4AF_FOURCC('s','o','c','o'): - case M4AF_FOURCC('s','o','n','m'): - case M4AF_FOURCC('s','o','s','n'): - case M4AF_FOURCC('t','v','e','n'): - case M4AF_FOURCC('t','v','n','n'): - case M4AF_FOURCC('t','v','s','h'): - case M4AF_FOURCC('x','i','d',' '): - case M4AF_FOURCC('\xa9','e','n','c'): - case M4AF_FOURCC('\xa9','s','t','3'): - { - char *u8 = aacenc_to_utf8(data); - m4af_add_itmf_string_tag(m4af, tag->tag, u8); - free(u8); + m4af_add_itmf_long_tag(m4af, tag->name, data); break; } default: - fprintf(stderr, "WARNING: unknown/unsupported tag: %c%c%c%c\n", - tag->tag >> 24, (tag->tag >> 16) & 0xff, - (tag->tag >> 8) & 0xff, tag->tag & 0xff); + if (aacenc_is_string_tag(tag->tag)) + m4af_add_itmf_string_tag(m4af, tag->tag, data); + else + fprintf(stderr, "WARNING: unknown/unsupported tag: %c%c%c%c\n", + tag->tag >> 24, (tag->tag >> 16) & 0xff, + (tag->tag >> 8) & 0xff, tag->tag & 0xff); } - if (file_contents) free(file_contents); } diff --git a/src/metadata.h b/src/metadata.h index 66a8762..0438b79 100644 --- a/src/metadata.h +++ b/src/metadata.h @@ -1,28 +1,44 @@ #ifndef METADATA_H #define METADATA_H +#include "m4af.h" + typedef struct aacenc_tag_entry_t { - uint32_t tag; - const char *name; - const char *data; - uint32_t data_size; - int is_file_name; + uint32_t tag; + char *name; + char *data; + uint32_t data_size; } aacenc_tag_entry_t; -typedef struct aacenc_tag_param_t { +typedef struct aacenc_tag_store_t { aacenc_tag_entry_t *tag_table; unsigned tag_count; unsigned tag_table_capacity; -} aacenc_tag_param_t; +} aacenc_tag_store_t; + +typedef struct aacenc_translate_generic_text_tag_ctx_t { + unsigned track, track_total, disc, disc_total; + void (*add)(void *, const aacenc_tag_entry_t *); + void *add_ctx; +} aacenc_translate_generic_text_tag_ctx_t; + +typedef void (*aacenc_tag_callback_t)(void *ctx, const char *key, + const char *value, uint32_t size); + +void aacenc_translate_generic_text_tag(void *ctx, const char *key, + const char *val, uint32_t size); + + +void aacenc_add_tag_to_store(aacenc_tag_store_t *store, uint32_t tag, + const char *key, const char *value, + uint32_t size, int is_file_name); -char *aacenc_load_tag_from_file(const char *path, uint32_t *data_size); +void aacenc_add_tag_entry_to_store(void *store, const aacenc_tag_entry_t *tag); -void aacenc_param_add_itmf_entry(aacenc_tag_param_t *params, uint32_t tag, - const char *key, const char *value, - uint32_t size, int is_file_name); +void aacenc_free_tag_store(aacenc_tag_store_t *store); -void aacenc_put_tags_from_json(m4af_ctx_t *m4af, const char *json_filename); +void aacenc_write_tags_from_json(m4af_ctx_t *m4af, const char *json_filename); -void aacenc_put_tag_entry(m4af_ctx_t *m4af, const aacenc_tag_entry_t *tag); +void aacenc_write_tag_entry(void *m4af, const aacenc_tag_entry_t *tag); #endif -- 2.30.2