return ent ? ent->fcc : 0;
}
+static
char *aacenc_load_tag_from_file(const char *path, uint32_t *data_size)
{
FILE *fp = 0;
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);
+ }
}
}
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;
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';
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)
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);
}