From ffea273a28179d2b5bbc24f967517bcf80940c63 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sat, 11 Feb 2012 19:24:51 +0100 Subject: tag_handler: handle arbitrary name/value pairs The new method pair() receives an arbitrary name/value pair. Support for this is being added to a few decoder plugins. --- src/decoder/ffmpeg_metadata.c | 20 ++++++++++++++++++++ src/decoder/flac_metadata.c | 13 +++++++++++++ src/decoder/mp4ff_decoder_plugin.c | 2 ++ src/decoder/vorbis_comments.c | 13 +++++++++++++ src/decoder/wavpack_decoder_plugin.c | 27 +++++++++++++++++++++++++++ src/tag_ape.c | 2 ++ src/tag_handler.h | 18 ++++++++++++++++++ src/tag_id3.c | 19 +++++++++++-------- test/read_tags.c | 9 ++++++++- 9 files changed, 114 insertions(+), 9 deletions(-) diff --git a/src/decoder/ffmpeg_metadata.c b/src/decoder/ffmpeg_metadata.c index 5325c1ca..df700fc0 100644 --- a/src/decoder/ffmpeg_metadata.c +++ b/src/decoder/ffmpeg_metadata.c @@ -50,6 +50,21 @@ ffmpeg_copy_metadata(enum tag_type type, type, mt->value); } +#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51,5,0) + +static void +ffmpeg_scan_pairs(AVDictionary *dict, + const struct tag_handler *handler, void *handler_ctx) +{ + AVDictionaryEntry *i = NULL; + + while ((i = av_dict_get(dict, "", i, AV_DICT_IGNORE_SUFFIX)) != NULL) + tag_handler_invoke_pair(handler, handler_ctx, + i->key, i->value); +} + +#endif + void ffmpeg_scan_dictionary(AVDictionary *dict, const struct tag_handler *handler, void *handler_ctx) @@ -62,4 +77,9 @@ ffmpeg_scan_dictionary(AVDictionary *dict, i->name != NULL; ++i) ffmpeg_copy_metadata(i->type, dict, i->name, handler, handler_ctx); + +#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51,5,0) + if (handler->pair != NULL) + ffmpeg_scan_pairs(dict, handler, handler_ctx); +#endif } diff --git a/src/decoder/flac_metadata.c b/src/decoder/flac_metadata.c index 9e138ef9..bd1eaf32 100644 --- a/src/decoder/flac_metadata.c +++ b/src/decoder/flac_metadata.c @@ -196,6 +196,19 @@ flac_scan_comment(const char *char_tnum, const FLAC__StreamMetadata_VorbisComment_Entry *entry, const struct tag_handler *handler, void *handler_ctx) { + if (handler->pair != NULL) { + char *name = g_strdup((const char*)entry->entry); + char *value = strchr(name, '='); + + if (value != NULL && value > name) { + *value++ = 0; + tag_handler_invoke_pair(handler, handler_ctx, + name, value); + } + + g_free(name); + } + for (const struct tag_table *i = flac_tags; i->name != NULL; ++i) if (flac_copy_comment(entry, i->name, i->type, char_tnum, handler, handler_ctx)) diff --git a/src/decoder/mp4ff_decoder_plugin.c b/src/decoder/mp4ff_decoder_plugin.c index e1e48770..ca78a22d 100644 --- a/src/decoder/mp4ff_decoder_plugin.c +++ b/src/decoder/mp4ff_decoder_plugin.c @@ -414,6 +414,8 @@ mp4ff_scan_stream(struct input_stream *is, mp4ff_meta_get_by_index(mp4fh, i, &item, &value); + tag_handler_invoke_pair(handler, handler_ctx, item, value); + enum tag_type type = mp4ff_tag_name_parse(item); if (type != TAG_NUM_OF_ITEM_TYPES) tag_handler_invoke_tag(handler, handler_ctx, diff --git a/src/decoder/vorbis_comments.c b/src/decoder/vorbis_comments.c index e94ee3d0..6c2d57b7 100644 --- a/src/decoder/vorbis_comments.c +++ b/src/decoder/vorbis_comments.c @@ -106,6 +106,19 @@ static void vorbis_scan_comment(const char *comment, const struct tag_handler *handler, void *handler_ctx) { + if (handler->pair != NULL) { + char *name = g_strdup((const char*)comment); + char *value = strchr(name, '='); + + if (value != NULL && value > name) { + *value++ = 0; + tag_handler_invoke_pair(handler, handler_ctx, + name, value); + } + + g_free(name); + } + for (const struct tag_table *i = vorbis_tags; i->name != NULL; ++i) if (vorbis_copy_comment(comment, i->name, i->type, handler, handler_ctx)) diff --git a/src/decoder/wavpack_decoder_plugin.c b/src/decoder/wavpack_decoder_plugin.c index 7ba50ba3..88a4854b 100644 --- a/src/decoder/wavpack_decoder_plugin.c +++ b/src/decoder/wavpack_decoder_plugin.c @@ -286,6 +286,19 @@ wavpack_scan_tag_item(WavpackContext *wpc, const char *name, } +static void +wavpack_scan_pair(WavpackContext *wpc, const char *name, + const struct tag_handler *handler, void *handler_ctx) +{ + char buffer[1024]; + int len = WavpackGetTagItem(wpc, name, buffer, sizeof(buffer)); + if (len <= 0 || (unsigned)len >= sizeof(buffer)) + return; + + tag_handler_invoke_pair(handler, handler_ctx, name, buffer); + +} + /* * Reads metainfo from the specified file. */ @@ -313,6 +326,20 @@ wavpack_scan_file(const char *fname, wavpack_scan_tag_item(wpc, i->name, i->type, handler, handler_ctx); + if (handler->pair != NULL) { + char name[64]; + + for (int i = 0, n = WavpackGetNumTagItems(wpc); + i < n; ++i) { + int len = WavpackGetTagItemIndexed(wpc, i, name, + sizeof(name)); + if (len <= 0 || (unsigned)len >= sizeof(name)) + continue; + + wavpack_scan_pair(wpc, name, handler, handler_ctx); + } + } + WavpackCloseFile(wpc); return true; diff --git a/src/tag_ape.c b/src/tag_ape.c index 93d935b7..068a9aa6 100644 --- a/src/tag_ape.c +++ b/src/tag_ape.c @@ -49,6 +49,8 @@ tag_ape_import_item(unsigned long flags, if ((flags & (0x3 << 1)) != 0) return; + tag_handler_invoke_pair(handler, handler_ctx, key, value); + enum tag_type type = tag_ape_name_parse(key); if (type == TAG_NUM_OF_ITEM_TYPES) return; diff --git a/src/tag_handler.h b/src/tag_handler.h index 13e40f38..65391858 100644 --- a/src/tag_handler.h +++ b/src/tag_handler.h @@ -43,6 +43,12 @@ struct tag_handler { * invalid after returning */ void (*tag)(enum tag_type type, const char *value, void *ctx); + + /** + * A name-value pair has been read. It is the codec specific + * representation of tags. + */ + void (*pair)(const char *key, const char *value, void *ctx); }; static inline void @@ -67,6 +73,18 @@ tag_handler_invoke_tag(const struct tag_handler *handler, void *ctx, handler->tag(type, value, ctx); } +static inline void +tag_handler_invoke_pair(const struct tag_handler *handler, void *ctx, + const char *name, const char *value) +{ + assert(handler != NULL); + assert(name != NULL); + assert(value != NULL); + + if (handler->pair != NULL) + handler->pair(name, value, ctx); +} + /** * This #tag_handler implementation adds tag values to a #tag object * (casted from the context pointer). diff --git a/src/tag_id3.c b/src/tag_id3.c index 8becb481..05870152 100644 --- a/src/tag_id3.c +++ b/src/tag_id3.c @@ -282,18 +282,21 @@ tag_id3_import_musicbrainz(struct id3_tag *id3_tag, if (name == NULL) continue; - type = tag_id3_parse_txxx_name((const char*)name); - free(name); - - if (type == TAG_NUM_OF_ITEM_TYPES) - continue; - value = tag_id3_getstring(frame, 2); if (value == NULL) continue; - tag_handler_invoke_tag(handler, handler_ctx, - type, (const char*)value); + tag_handler_invoke_pair(handler, handler_ctx, + (const char *)name, + (const char *)value); + + type = tag_id3_parse_txxx_name((const char*)name); + free(name); + + if (type != TAG_NUM_OF_ITEM_TYPES) + tag_handler_invoke_tag(handler, handler_ctx, + type, (const char*)value); + free(value); } } diff --git a/test/read_tags.c b/test/read_tags.c index 9fcf1acf..b5ca8e55 100644 --- a/test/read_tags.c +++ b/test/read_tags.c @@ -145,13 +145,20 @@ print_duration(unsigned seconds, G_GNUC_UNUSED void *ctx) static void print_tag(enum tag_type type, const char *value, G_GNUC_UNUSED void *ctx) { - g_print("%s=%s\n", tag_item_names[type], value); + g_print("[%s]=%s\n", tag_item_names[type], value); empty = false; } +static void +print_pair(const char *name, const char *value, G_GNUC_UNUSED void *ctx) +{ + g_print("\"%s\"=%s\n", name, value); +} + static const struct tag_handler print_handler = { .duration = print_duration, .tag = print_tag, + .pair = print_pair, }; int main(int argc, char **argv) -- cgit v1.2.3