diff options
author | Anton Khirnov <anton@khirnov.net> | 2013-05-28 17:43:22 +0200 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2013-05-28 18:19:03 +0200 |
commit | 88de0c7901ee2bd6021cf32def87ce98ce63155c (patch) | |
tree | 423547285b33d42d7946fb8267f68d06e06950f4 | |
parent | 01656fd47694d76e30cac356632b98482263428d (diff) | |
download | ffmpeg-88de0c7901ee2bd6021cf32def87ce98ce63155c.tar.gz |
apetag: add support for writing APE tags
This will be useful in the WavPack muxer.
-rw-r--r-- | libavformat/apetag.c | 56 | ||||
-rw-r--r-- | libavformat/apetag.h | 5 |
2 files changed, 61 insertions, 0 deletions
diff --git a/libavformat/apetag.c b/libavformat/apetag.c index 0d2cb973fb..68f2df6c56 100644 --- a/libavformat/apetag.c +++ b/libavformat/apetag.c @@ -23,12 +23,14 @@ #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; +} diff --git a/libavformat/apetag.h b/libavformat/apetag.h index 279972ff6e..36e3211fc8 100644 --- a/libavformat/apetag.h +++ b/libavformat/apetag.h @@ -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 */ |