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.
This commit is contained in:
parent
1783aac438
commit
ffea273a28
@ -50,6 +50,21 @@ ffmpeg_copy_metadata(enum tag_type type,
|
|||||||
type, mt->value);
|
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
|
void
|
||||||
ffmpeg_scan_dictionary(AVDictionary *dict,
|
ffmpeg_scan_dictionary(AVDictionary *dict,
|
||||||
const struct tag_handler *handler, void *handler_ctx)
|
const struct tag_handler *handler, void *handler_ctx)
|
||||||
@ -62,4 +77,9 @@ ffmpeg_scan_dictionary(AVDictionary *dict,
|
|||||||
i->name != NULL; ++i)
|
i->name != NULL; ++i)
|
||||||
ffmpeg_copy_metadata(i->type, dict, i->name,
|
ffmpeg_copy_metadata(i->type, dict, i->name,
|
||||||
handler, handler_ctx);
|
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
|
||||||
}
|
}
|
||||||
|
@ -196,6 +196,19 @@ flac_scan_comment(const char *char_tnum,
|
|||||||
const FLAC__StreamMetadata_VorbisComment_Entry *entry,
|
const FLAC__StreamMetadata_VorbisComment_Entry *entry,
|
||||||
const struct tag_handler *handler, void *handler_ctx)
|
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)
|
for (const struct tag_table *i = flac_tags; i->name != NULL; ++i)
|
||||||
if (flac_copy_comment(entry, i->name, i->type, char_tnum,
|
if (flac_copy_comment(entry, i->name, i->type, char_tnum,
|
||||||
handler, handler_ctx))
|
handler, handler_ctx))
|
||||||
|
@ -414,6 +414,8 @@ mp4ff_scan_stream(struct input_stream *is,
|
|||||||
|
|
||||||
mp4ff_meta_get_by_index(mp4fh, i, &item, &value);
|
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);
|
enum tag_type type = mp4ff_tag_name_parse(item);
|
||||||
if (type != TAG_NUM_OF_ITEM_TYPES)
|
if (type != TAG_NUM_OF_ITEM_TYPES)
|
||||||
tag_handler_invoke_tag(handler, handler_ctx,
|
tag_handler_invoke_tag(handler, handler_ctx,
|
||||||
|
@ -106,6 +106,19 @@ static void
|
|||||||
vorbis_scan_comment(const char *comment,
|
vorbis_scan_comment(const char *comment,
|
||||||
const struct tag_handler *handler, void *handler_ctx)
|
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)
|
for (const struct tag_table *i = vorbis_tags; i->name != NULL; ++i)
|
||||||
if (vorbis_copy_comment(comment, i->name, i->type,
|
if (vorbis_copy_comment(comment, i->name, i->type,
|
||||||
handler, handler_ctx))
|
handler, handler_ctx))
|
||||||
|
@ -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.
|
* 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,
|
wavpack_scan_tag_item(wpc, i->name, i->type,
|
||||||
handler, handler_ctx);
|
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);
|
WavpackCloseFile(wpc);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -49,6 +49,8 @@ tag_ape_import_item(unsigned long flags,
|
|||||||
if ((flags & (0x3 << 1)) != 0)
|
if ((flags & (0x3 << 1)) != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
tag_handler_invoke_pair(handler, handler_ctx, key, value);
|
||||||
|
|
||||||
enum tag_type type = tag_ape_name_parse(key);
|
enum tag_type type = tag_ape_name_parse(key);
|
||||||
if (type == TAG_NUM_OF_ITEM_TYPES)
|
if (type == TAG_NUM_OF_ITEM_TYPES)
|
||||||
return;
|
return;
|
||||||
|
@ -43,6 +43,12 @@ struct tag_handler {
|
|||||||
* invalid after returning
|
* invalid after returning
|
||||||
*/
|
*/
|
||||||
void (*tag)(enum tag_type type, const char *value, void *ctx);
|
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
|
static inline void
|
||||||
@ -67,6 +73,18 @@ tag_handler_invoke_tag(const struct tag_handler *handler, void *ctx,
|
|||||||
handler->tag(type, value, 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
|
* This #tag_handler implementation adds tag values to a #tag object
|
||||||
* (casted from the context pointer).
|
* (casted from the context pointer).
|
||||||
|
@ -282,18 +282,21 @@ tag_id3_import_musicbrainz(struct id3_tag *id3_tag,
|
|||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
continue;
|
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);
|
value = tag_id3_getstring(frame, 2);
|
||||||
if (value == NULL)
|
if (value == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
tag_handler_invoke_tag(handler, handler_ctx,
|
tag_handler_invoke_pair(handler, handler_ctx,
|
||||||
type, (const char*)value);
|
(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);
|
free(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,13 +145,20 @@ print_duration(unsigned seconds, G_GNUC_UNUSED void *ctx)
|
|||||||
static void
|
static void
|
||||||
print_tag(enum tag_type type, const char *value, G_GNUC_UNUSED void *ctx)
|
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;
|
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 = {
|
static const struct tag_handler print_handler = {
|
||||||
.duration = print_duration,
|
.duration = print_duration,
|
||||||
.tag = print_tag,
|
.tag = print_tag,
|
||||||
|
.pair = print_pair,
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
|
Loading…
Reference in New Issue
Block a user