[FFmpeg-devel] [PATCH 2/5] metadata: add new conversion API

Anton Khirnov anton
Sun Oct 3 21:14:23 CEST 2010


From: Anton Khirnov <wyskas at gmail.com>

Track current metadata format in AVMetadata and add av_metadata_clone()
function for copying/replacing metadata.
---
 libavformat/asfdec.c         |    2 +
 libavformat/avformat.h       |   16 +++++++++++
 libavformat/avidec.c         |    1 +
 libavformat/id3v2.c          |    2 +
 libavformat/matroskadec.c    |    2 +
 libavformat/metadata.c       |   59 ++++++++++++++++++++++++++++++++++++++++++
 libavformat/metadata.h       |    1 +
 libavformat/nutdec.c         |    2 +
 libavformat/oggparsevorbis.c |    3 ++
 9 files changed, 88 insertions(+), 0 deletions(-)

diff --git a/libavformat/asfdec.c b/libavformat/asfdec.c
index 6741f8c..59b075c 100644
--- a/libavformat/asfdec.c
+++ b/libavformat/asfdec.c
@@ -204,6 +204,8 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap)
     get_byte(pb);
     get_byte(pb);
     memset(&asf->asfid2avid, -1, sizeof(asf->asfid2avid));
+
+    av_metadata_clone(&s->metadata, &s->metadata, ff_asf_metadata_conv, NULL, 0);
     for(;;) {
         uint64_t gpos= url_ftell(pb);
         get_guid(pb, &g);
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 362a056..a9fb39f 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -198,6 +198,22 @@ void av_metadata_conv(struct AVFormatContext *ctx, const AVMetadataConv *d_conv,
                                                    const AVMetadataConv *s_conv);
 
 /**
+ * Copy metadata from src to dst, converting between their respective formats.
+ * dst may be equal to src -- for in-place conversion -- or empty (i.e. a
+ * pointer to NULL), in both cases it is initialized to dst_fmt format.
+ * Otherwise dst_fmt is ignored. src may be a pointer to NULL, in which case
+ * dst is initialized, but nothing is copied.
+ *
+ * @param pattern Used to copy only some keys. If non-NULL, it is passed
+ *                directly to av_metadata_get().
+ * @param flags   Passed directly to av_metadata_get/set. If pattern is NULL,
+ *                defaults to AV_METADATA_IGNORE_SUFFIX|AV_METADATA_DONT_OVERWRITE.
+ * @return >= 0 on success otherwise an error code <0
+ */
+int av_metadata_clone(AVMetadata **src, AVMetadata **dst, const AVMetadataConv *dst_fmt,
+                      const char *pattern, int flags);
+
+/**
  * Free all the memory allocated for an AVMetadata struct.
  */
 void av_metadata_free(AVMetadata **m);
diff --git a/libavformat/avidec.c b/libavformat/avidec.c
index 84ccaec..6bd4fd9 100644
--- a/libavformat/avidec.c
+++ b/libavformat/avidec.c
@@ -275,6 +275,7 @@ static int avi_read_tag(AVFormatContext *s, AVStream *st, uint32_t tag, uint32_t
 
 static void avi_read_info(AVFormatContext *s, uint64_t end)
 {
+    av_metadata_clone(&s->metadata, &s->metadata, ff_avi_metadata_conv, NULL, 0);
     while (url_ftell(s->pb) < end) {
         uint32_t tag  = get_le32(s->pb);
         uint32_t size = get_le32(s->pb);
diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c
index 364720f..7b4f950 100644
--- a/libavformat/id3v2.c
+++ b/libavformat/id3v2.c
@@ -193,6 +193,8 @@ void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags)
         goto error;
     }
 
+    av_metadata_clone(&s->metadata, &s->metadata, ff_id3v2_metadata_conv, NULL, 0);
+
     unsync = flags & 0x80;
 
     if (isv34 && flags & 0x40) /* Extended header present, just skip over it */
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index 0d0285e..964ed8c 100644
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@ -1031,6 +1031,8 @@ static void matroska_convert_tag(AVFormatContext *s, EbmlList *list,
     char key[1024];
     int i;
 
+    av_metadata_clone(metadata, metadata, ff_mkv_metadata_conv, NULL, 0);
+
     for (i=0; i < list->nb_elem; i++) {
         const char *lang = strcmp(tags[i].lang, "und") ? tags[i].lang : NULL;
         if (prefix)  snprintf(key, sizeof(key), "%s/%s", prefix, tags[i].name);
diff --git a/libavformat/metadata.c b/libavformat/metadata.c
index 8fc1771..2a91219 100644
--- a/libavformat/metadata.c
+++ b/libavformat/metadata.c
@@ -152,3 +152,62 @@ void av_metadata_conv(AVFormatContext *ctx, const AVMetadataConv *d_conv,
     for (i=0; i<ctx->nb_programs; i++)
         metadata_conv(&ctx->programs[i]->metadata, d_conv, s_conv);
 }
+
+int av_metadata_clone(AVMetadata **src, AVMetadata **dst, const AVMetadataConv *dst_fmt,
+                      const char *pattern, int flags)
+{
+    int ret;
+    AVMetadataTag *mtag = NULL;
+    const AVMetadataConv *d_conv = (*dst && *dst != *src) ? (*dst)->cur_fmt : dst_fmt;
+    const AVMetadataConv *s_conv = *src ? (*src)->cur_fmt : NULL;
+    const AVMetadataConv *sc, *dc;
+    const char *key;
+    AVMetadata *tmp = av_mallocz(sizeof(*tmp));
+
+    if (!tmp)
+        return AVERROR(ENOMEM);
+    tmp->cur_fmt = d_conv;
+
+    if (!pattern && !flags)
+        flags = AV_METADATA_IGNORE_SUFFIX | AV_METADATA_DONT_OVERWRITE;
+
+    if (*src)
+        while ((mtag = av_metadata_get(*src, pattern ? pattern : "", mtag, flags))) {
+            key = mtag->key;
+            if (s_conv)
+                for (sc=s_conv; sc->native; sc++)
+                    if (!strcasecmp(key, sc->native)) {
+                        key = sc->generic;
+                        break;
+                    }
+            if (d_conv)
+                for (dc=d_conv; dc->native; dc++)
+                    if (!strcasecmp(key, dc->generic)) {
+                        key = dc->native;
+                        break;
+                    }
+            if ((ret = av_metadata_set2(&tmp, key, mtag->value, flags)) < 0) {
+                av_metadata_free(&tmp);
+                return ret;
+            }
+        }
+
+    if (src == dst)
+        av_metadata_free(src);
+    if (!*dst)
+        *dst = tmp;
+    else {
+        mtag = NULL;
+        while ((mtag = av_metadata_get(tmp, "", mtag, AV_METADATA_IGNORE_SUFFIX)))
+            if ((ret = av_metadata_set2(dst, mtag->key, mtag->value, flags)) < 0)
+                break;
+        av_metadata_free(&tmp);
+        if (ret < 0)
+            return ret;
+    }
+
+    if (*dst)
+        (*dst)->cur_fmt = d_conv;
+
+    return 0;
+}
diff --git a/libavformat/metadata.h b/libavformat/metadata.h
index 3706bc4..4e54904 100644
--- a/libavformat/metadata.h
+++ b/libavformat/metadata.h
@@ -33,6 +33,7 @@
 struct AVMetadata{
     int count;
     AVMetadataTag *elems;
+    const AVMetadataConv *cur_fmt;
 };
 
 struct AVMetadataConv{
diff --git a/libavformat/nutdec.c b/libavformat/nutdec.c
index 7db06fa..3dc608f 100644
--- a/libavformat/nutdec.c
+++ b/libavformat/nutdec.c
@@ -429,6 +429,8 @@ static int decode_info_header(NUTContext *nut){
     } else
         metadata = &s->metadata;
 
+    av_metadata_clone(metadata, metadata, ff_nut_metadata_conv, NULL, 0);
+
     for(i=0; i<count; i++){
         get_str(bc, name, sizeof(name));
         value= get_s(bc);
diff --git a/libavformat/oggparsevorbis.c b/libavformat/oggparsevorbis.c
index c7f8149..45d3b6d 100644
--- a/libavformat/oggparsevorbis.c
+++ b/libavformat/oggparsevorbis.c
@@ -29,6 +29,7 @@
 #include "libavcodec/bytestream.h"
 #include "avformat.h"
 #include "oggdec.h"
+#include "vorbiscomment.h"
 
 static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val)
 {
@@ -84,6 +85,8 @@ ff_vorbis_comment(AVFormatContext * as, AVMetadata **m, const uint8_t *buf, int
 
     n = bytestream_get_le32(&p);
 
+    av_metadata_clone(m, m, ff_vorbiscomment_metadata_conv, NULL, 0);
+
     while (end - p >= 4 && n > 0) {
         const char *t, *v;
         int tl, vl;
-- 
1.7.1




More information about the ffmpeg-devel mailing list