apetag: add support for writing APE tags
authorAnton Khirnov <anton@khirnov.net>
Tue, 28 May 2013 15:43:22 +0000 (17:43 +0200)
committerAnton Khirnov <anton@khirnov.net>
Tue, 28 May 2013 16:19:03 +0000 (18:19 +0200)
This will be useful in the WavPack muxer.

libavformat/apetag.c
libavformat/apetag.h

index 0d2cb97..68f2df6 100644 (file)
 #include "libavutil/intreadwrite.h"
 #include "libavutil/dict.h"
 #include "avformat.h"
+#include "avio_internal.h"
 #include "apetag.h"
 #include "internal.h"
 
 #define APE_TAG_VERSION               2000
 #define APE_TAG_FOOTER_BYTES          32
 #define APE_TAG_FLAG_CONTAINS_HEADER  (1 << 31)
+#define APE_TAG_FLAG_CONTAINS_FOOTER  (1 << 30)
 #define APE_TAG_FLAG_IS_HEADER        (1 << 29)
 #define APE_TAG_FLAG_IS_BINARY        (1 << 1)
 
@@ -169,3 +171,57 @@ int64_t ff_ape_parse_tag(AVFormatContext *s)
 
     return tag_start;
 }
+
+int ff_ape_write_tag(AVFormatContext *s)
+{
+    AVDictionaryEntry *e = NULL;
+    int64_t start, end;
+    int size, count = 0;
+
+    if (!s->pb->seekable)
+        return 0;
+
+    start = avio_tell(s->pb);
+
+    // header
+    avio_write(s->pb, "APETAGEX", 8);   // id
+    avio_wl32 (s->pb, APE_TAG_VERSION); // version
+    avio_wl32(s->pb, 0);                // reserve space for size
+    avio_wl32(s->pb, 0);                // reserve space for tag count
+
+    // flags
+    avio_wl32(s->pb, APE_TAG_FLAG_CONTAINS_HEADER | APE_TAG_FLAG_CONTAINS_FOOTER |
+                     APE_TAG_FLAG_IS_HEADER);
+    ffio_fill(s->pb, 0, 8);             // reserved
+
+    while ((e = av_dict_get(s->metadata, "", e, AV_DICT_IGNORE_SUFFIX))) {
+        int val_len = strlen(e->value);
+
+        avio_wl32(s->pb, val_len);            // value length
+        avio_wl32(s->pb, 0);                  // item flags
+        avio_put_str(s->pb, e->key);          // key
+        avio_write(s->pb, e->value, val_len); // value
+        count++;
+    }
+
+    size = avio_tell(s->pb) - start;
+
+    // footer
+    avio_write(s->pb, "APETAGEX", 8);   // id
+    avio_wl32 (s->pb, APE_TAG_VERSION); // version
+    avio_wl32(s->pb, size);             // size
+    avio_wl32(s->pb, count);            // tag count
+
+    // flags
+    avio_wl32(s->pb, APE_TAG_FLAG_CONTAINS_HEADER | APE_TAG_FLAG_CONTAINS_FOOTER);
+    ffio_fill(s->pb, 0, 8);             // reserved
+
+    // update values in the header
+    end = avio_tell(s->pb);
+    avio_seek(s->pb, start + 12, SEEK_SET);
+    avio_wl32(s->pb, size);
+    avio_wl32(s->pb, count);
+    avio_seek(s->pb, end, SEEK_SET);
+
+    return 0;
+}
index 279972f..36e3211 100644 (file)
@@ -32,4 +32,9 @@
  */
 int64_t ff_ape_parse_tag(AVFormatContext *s);
 
+/**
+ * Write an APE tag into a file.
+ */
+int ff_ape_write_tag(AVFormatContext *s);
+
 #endif /* AVFORMAT_APETAG_H */