cleanup metadata handling
authornu774 <honeycomb77@gmail.com>
Wed, 23 Oct 2013 14:35:23 +0000 (23:35 +0900)
committernu774 <honeycomb77@gmail.com>
Wed, 23 Oct 2013 14:35:23 +0000 (23:35 +0900)
src/main.c
src/metadata.c
src/metadata.h

index f4cc14cc056622800e9f5d463468d8c86894c177..83fb75459c85e1315f33947dc1691f80f4cc36f2 100644 (file)
@@ -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(&params->tags, ch, 0, optarg,
-                                        strlen(optarg), 0);
+            aacenc_add_tag_to_store(&params->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(&params->tags, fcc, optarg,
-                                            val, strlen(val),
-                                            ch == OPT_SHORT_TAG_FILE);
+                aacenc_add_tag_to_store(&params->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(&params.tags);
 
     return result;
 }
index 96b2f28d8bd79b5e5a5e79632f70fa79ca25ddc2..f2d4fb23e072e310c813ece870fd765f207d033f 100644 (file)
@@ -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);
 }
 
 
index 66a876272d74325f99c5ddca9ea6c1511a317818..0438b791a857875fe4c73e0e9efdf01d24a01d9b 100644 (file)
@@ -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
This page took 0.022739 seconds and 4 git commands to generate.