diff --git a/libavformat/flac_picture.c b/libavformat/flac_picture.c
index 53e24b28b7..73edc7e238 100644
--- a/libavformat/flac_picture.c
+++ b/libavformat/flac_picture.c
@@ -20,6 +20,7 @@
  */
 
 #include "libavutil/intreadwrite.h"
+#include "libavutil/pixdesc.h"
 #include "libavcodec/bytestream.h"
 #include "libavcodec/png.h"
 #include "avformat.h"
@@ -29,7 +30,8 @@
 
 #define MAX_TRUNC_PICTURE_SIZE (500 * 1024 * 1024)
 
-int ff_flac_parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size, int truncate_workaround)
+int ff_flac_parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size,
+                          int ogg_index, int truncate_workaround)
 {
     const CodecMime *mime = ff_id3v2_mime_tags;
     enum AVCodecID id = AV_CODEC_ID_NONE;
@@ -180,6 +182,8 @@ int ff_flac_parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size, int tr
     av_dict_set(&st->metadata, "comment", ff_id3v2_picture_types[type], 0);
     if (desc)
         av_dict_set(&st->metadata, "title", desc, AV_DICT_DONT_STRDUP_VAL);
+    if (ogg_index >= 0)
+        av_dict_set_int(&st->metadata, "ogg_attach", ogg_index, 0);
 
     return 0;
 
@@ -189,3 +193,109 @@ fail:
 
     return ret;
 }
+
+int ff_flac_picture_length(struct AVFormatContext *s, AVPacket *pkt) {
+    const CodecMime *mime = ff_id3v2_mime_tags;
+    AVDictionaryEntry *e;
+    const char *mimetype = NULL, *desc = "";
+    const AVStream *st = s->streams[pkt->stream_index];
+    int mimelen, desclen;
+
+    if (!pkt->data)
+        return 0;
+
+    /* get the mimetype */
+    while (mime->id != AV_CODEC_ID_NONE) {
+        if (mime->id == st->codecpar->codec_id) {
+            mimetype = mime->str;
+            break;
+        }
+        mime++;
+    }
+    if (!mimetype)
+        return 0;
+    mimelen = strlen(mimetype);
+
+    /* get the description */
+    if ((e = av_dict_get(st->metadata, "title", NULL, 0)))
+        desc = e->value;
+    desclen = strlen(desc);
+
+    return 4 + 4 + mimelen + 4 + desclen + 4 + 4 + 4 + 4 + 4 + pkt->size;
+}
+
+int ff_flac_write_picture(struct AVFormatContext *s, AVIOContext *pb,
+                          AVPacket *pkt, unsigned *attached_types)
+{
+    const AVPixFmtDescriptor *pixdesc;
+    const CodecMime *mime = ff_id3v2_mime_tags;
+    AVDictionaryEntry *e;
+    const char *mimetype = NULL, *desc = "";
+    const AVStream *st = s->streams[pkt->stream_index];
+    int i, mimelen, desclen, type = 0;
+
+    if (!pkt->data)
+        return 0;
+
+    while (mime->id != AV_CODEC_ID_NONE) {
+        if (mime->id == st->codecpar->codec_id) {
+            mimetype = mime->str;
+            break;
+        }
+        mime++;
+    }
+    if (!mimetype) {
+        av_log(s, AV_LOG_ERROR, "No mimetype is known for stream %d, cannot "
+               "write an attached picture.\n", st->index);
+        return AVERROR(EINVAL);
+    }
+    mimelen = strlen(mimetype);
+
+    /* get the picture type */
+    e = av_dict_get(st->metadata, "comment", NULL, 0);
+    for (i = 0; e && i < FF_ARRAY_ELEMS(ff_id3v2_picture_types); i++) {
+        if (!av_strcasecmp(e->value, ff_id3v2_picture_types[i])) {
+            type = i;
+            break;
+        }
+    }
+
+    if ((*attached_types & (1 << type)) & 0x6) {
+        av_log(s, AV_LOG_ERROR, "Duplicate attachment for type '%s'\n", ff_id3v2_picture_types[type]);
+        return AVERROR(EINVAL);
+    }
+
+    if (type == 1 && (st->codecpar->codec_id != AV_CODEC_ID_PNG ||
+                      st->codecpar->width != 32 ||
+                      st->codecpar->height != 32)) {
+        av_log(s, AV_LOG_ERROR, "File icon attachment must be a 32x32 PNG");
+        return AVERROR(EINVAL);
+    }
+
+    *attached_types |= (1 << type);
+
+    /* get the description */
+    if ((e = av_dict_get(st->metadata, "title", NULL, 0)))
+        desc = e->value;
+    desclen = strlen(desc);
+
+    avio_wb32(pb, type);
+
+    avio_wb32(pb, mimelen);
+    avio_write(pb, mimetype, mimelen);
+
+    avio_wb32(pb, desclen);
+    avio_write(pb, desc, desclen);
+
+    avio_wb32(pb, st->codecpar->width);
+    avio_wb32(pb, st->codecpar->height);
+    if ((pixdesc = av_pix_fmt_desc_get(st->codecpar->format)))
+        avio_wb32(pb, av_get_bits_per_pixel(pixdesc));
+    else
+        avio_wb32(pb, 0);
+    avio_wb32(pb, 0);
+
+    avio_wb32(pb, pkt->size);
+    avio_write(pb, pkt->data, pkt->size);
+    return 0;
+}
diff --git a/libavformat/flac_picture.h b/libavformat/flac_picture.h
index 61fd0c8806..9fc18b05ee 100644
--- a/libavformat/flac_picture.h
+++ b/libavformat/flac_picture.h
@@ -26,6 +26,10 @@
 
 #define RETURN_ERROR(code) do { ret = (code); goto fail; } while (0)
 
-int ff_flac_parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size, int truncate_workaround);
+int ff_flac_parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size,
+                          int ogg_index, int truncate_workaround);
+int ff_flac_picture_length(struct AVFormatContext *s, AVPacket *pkt);
+int ff_flac_write_picture(struct AVFormatContext *s, AVIOContext *pb,
+                          AVPacket *pkt, unsigned *attached_types);
 
 #endif /* AVFORMAT_FLAC_PICTURE_H */
diff --git a/libavformat/flacdec.c b/libavformat/flacdec.c
index 79c05f14bf..4e9676a71d 100644
--- a/libavformat/flacdec.c
+++ b/libavformat/flacdec.c
@@ -146,7 +146,7 @@ static int flac_read_header(AVFormatContext *s)
             }
             av_freep(&buffer);
         } else if (metadata_type == FLAC_METADATA_TYPE_PICTURE) {
-            ret = ff_flac_parse_picture(s, buffer, metadata_size, 1);
+            ret = ff_flac_parse_picture(s, buffer, metadata_size, 1, -1);
             av_freep(&buffer);
             if (ret < 0) {
                 av_log(s, AV_LOG_ERROR, "Error parsing attached picture.\n");
@@ -177,7 +177,7 @@ static int flac_read_header(AVFormatContext *s)
             if (metadata_type == FLAC_METADATA_TYPE_VORBIS_COMMENT) {
                 AVDictionaryEntry *chmask;
 
-                ret = ff_vorbis_comment(s, &s->metadata, buffer, metadata_size, 1);
+                ret = ff_vorbis_comment(s, &s->metadata, buffer, metadata_size, -1);
                 if (ret < 0) {
                     av_log(s, AV_LOG_WARNING, "error parsing VorbisComment metadata\n");
                 } else if (ret > 0) {
diff --git a/libavformat/flacenc.c b/libavformat/flacenc.c
index b947a3b067..db8972f56f 100644
--- a/libavformat/flacenc.c
+++ b/libavformat/flacenc.c
@@ -21,11 +21,11 @@
 
 #include "libavutil/channel_layout.h"
 #include "libavutil/opt.h"
-#include "libavutil/pixdesc.h"
 #include "libavcodec/flac.h"
 #include "avformat.h"
 #include "avio_internal.h"
 #include "flacenc.h"
+#include "flac_picture.h"
 #include "id3v2.h"
 #include "internal.h"
 #include "vorbiscomment.h"
@@ -70,100 +70,15 @@ static int flac_write_block_comment(AVIOContext *pb, AVDictionary **m,
 
     avio_w8(pb, last_block ? 0x84 : 0x04);
     avio_wb24(pb, len);
-    ff_vorbiscomment_write(pb, *m, vendor, NULL, 0);
+    ff_vorbiscomment_write(pb, *m, vendor, NULL, 0, 0);
 
     return 0;
 }
 
-static int flac_write_picture(struct AVFormatContext *s, AVPacket *pkt)
-{
-    FlacMuxerContext *c = s->priv_data;
-    AVIOContext *pb = s->pb;
-    const AVPixFmtDescriptor *pixdesc;
-    const CodecMime *mime = ff_id3v2_mime_tags;
-    AVDictionaryEntry *e;
-    const char *mimetype = NULL, *desc = "";
-    const AVStream *st = s->streams[pkt->stream_index];
-    int i, mimelen, desclen, type = 0, blocklen;
-
-    if (!pkt->data)
-        return 0;
-
-    while (mime->id != AV_CODEC_ID_NONE) {
-        if (mime->id == st->codecpar->codec_id) {
-            mimetype = mime->str;
-            break;
-        }
-        mime++;
-    }
-    if (!mimetype) {
-        av_log(s, AV_LOG_ERROR, "No mimetype is known for stream %d, cannot "
-               "write an attached picture.\n", st->index);
-        return AVERROR(EINVAL);
-    }
-    mimelen = strlen(mimetype);
-
-    /* get the picture type */
-    e = av_dict_get(st->metadata, "comment", NULL, 0);
-    for (i = 0; e && i < FF_ARRAY_ELEMS(ff_id3v2_picture_types); i++) {
-        if (!av_strcasecmp(e->value, ff_id3v2_picture_types[i])) {
-            type = i;
-            break;
-        }
-    }
-
-    if ((c->attached_types & (1 << type)) & 0x6) {
-        av_log(s, AV_LOG_ERROR, "Duplicate attachment for type '%s'\n", ff_id3v2_picture_types[type]);
-        return AVERROR(EINVAL);
-    }
-
-    if (type == 1 && (st->codecpar->codec_id != AV_CODEC_ID_PNG ||
-                      st->codecpar->width != 32 ||
-                      st->codecpar->height != 32)) {
-        av_log(s, AV_LOG_ERROR, "File icon attachment must be a 32x32 PNG");
-        return AVERROR(EINVAL);
-    }
-
-    c->attached_types |= (1 << type);
-
-    /* get the description */
-    if ((e = av_dict_get(st->metadata, "title", NULL, 0)))
-        desc = e->value;
-    desclen = strlen(desc);
-
-    blocklen = 4 + 4 + mimelen + 4 + desclen + 4 + 4 + 4 + 4 + 4 + pkt->size;
-    if (blocklen >= 1<<24) {
-        av_log(s, AV_LOG_ERROR, "Picture block too big %d >= %d\n", blocklen, 1<<24);
-        return AVERROR(EINVAL);
-    }
-
-    avio_w8(pb, 0x06);
-    avio_wb24(pb, blocklen);
-
-    avio_wb32(pb, type);
-
-    avio_wb32(pb, mimelen);
-    avio_write(pb, mimetype, mimelen);
-
-    avio_wb32(pb, desclen);
-    avio_write(pb, desc, desclen);
-
-    avio_wb32(pb, st->codecpar->width);
-    avio_wb32(pb, st->codecpar->height);
-    if ((pixdesc = av_pix_fmt_desc_get(st->codecpar->format)))
-        avio_wb32(pb, av_get_bits_per_pixel(pixdesc));
-    else
-        avio_wb32(pb, 0);
-    avio_wb32(pb, 0);
-
-    avio_wb32(pb, pkt->size);
-    avio_write(pb, pkt->data, pkt->size);
-    return 0;
-}
-
 static int flac_finish_header(struct AVFormatContext *s)
 {
     int i, ret, padding = s->metadata_header_padding;
+    FlacMuxerContext *pd = s->priv_data;
     if (padding < 0)
         padding = 8192;
     /* The FLAC specification states that 24 bits are used to represent the
@@ -175,7 +90,14 @@ static int flac_finish_header(struct AVFormatContext *s)
         AVPacket *pkt = st->priv_data;
         if (!pkt)
             continue;
-        ret = flac_write_picture(s, pkt);
+        int picture_len = ff_flac_picture_length(s, pkt);
+        if (picture_len >= 1<<24) {
+            av_log(s, AV_LOG_ERROR, "Picture block too big %d >= %d\n", picture_len, 1<<24);
+            return AVERROR(EINVAL);
+        }
+        avio_w8(s->pb, 0x06);
+        avio_wb24(s->pb, picture_len);
+        ret = ff_flac_write_picture(s, s->pb, pkt, &pd->attached_types);
         av_packet_unref(pkt);
         if (ret < 0 && (s->error_recognition & AV_EF_EXPLODE))
             return ret;
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index bb3a126c29..fcbf3e0497 100644
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@ -2005,7 +2005,7 @@ static int matroska_parse_flac(AVFormatContext *s,
             AVDictionary *dict = NULL;
             AVDictionaryEntry *chmask;
 
-            ff_vorbis_comment(s, &dict, p, block_size, 0);
+            ff_vorbis_comment(s, &dict, p, block_size, -2);
             chmask = av_dict_get(dict, "WAVEFORMATEXTENSIBLE_CHANNEL_MASK", NULL, 0);
             if (chmask) {
                 uint64_t mask = strtol(chmask->value, NULL, 0);
diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index 1c1ea71f59..00bd769962 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -666,7 +666,7 @@ static int put_flac_codecpriv(AVFormatContext *s, AVIOContext *pb,
         avio_w8(pb, 0x84);
         avio_wb24(pb, len);
 
-        ff_vorbiscomment_write(pb, dict, vendor, NULL, 0);
+        ff_vorbiscomment_write(pb, dict, vendor, NULL, 0, 0);
 
         av_dict_free(&dict);
     }
diff --git a/libavformat/oggdec.h b/libavformat/oggdec.h
index 629a1d6262..58d7c86a4e 100644
--- a/libavformat/oggdec.h
+++ b/libavformat/oggdec.h
@@ -131,7 +131,8 @@ extern const struct ogg_codec ff_vorbis_codec;
 extern const struct ogg_codec ff_vp8_codec;
 
 int ff_vorbis_comment(AVFormatContext *ms, AVDictionary **m,
-                      const uint8_t *buf, int size, int parse_picture);
+                      const uint8_t *buf, int size,
+                      int parse_picture_index);
 
 int ff_vorbis_stream_comment(AVFormatContext *as, AVStream *st,
                              const uint8_t *buf, int size);
diff --git a/libavformat/oggenc.c b/libavformat/oggenc.c
index f5032759a6..4223690956 100644
--- a/libavformat/oggenc.c
+++ b/libavformat/oggenc.c
@@ -21,6 +21,7 @@
 
 #include <stdint.h>
 
+#include "libavutil/base64.h"
 #include "libavutil/crc.h"
 #include "libavutil/mathematics.h"
 #include "libavutil/opt.h"
@@ -30,6 +31,7 @@
 #include "libavcodec/flac.h"
 #include "avformat.h"
 #include "avio_internal.h"
+#include "flac_picture.h"
 #include "internal.h"
 #include "vorbiscomment.h"
 
@@ -46,6 +48,11 @@ typedef struct OGGPage {
     uint16_t size;
 } OGGPage;
 
+typedef struct OGGPageList {
+    OGGPage page;
+    struct OGGPageList *next;
+} OGGPageList;
+
 typedef struct OGGStreamContext {
     unsigned page_counter;
     uint8_t *header[3];
@@ -61,12 +68,16 @@ typedef struct OGGStreamContext {
     OGGPage page; ///< current page
     unsigned serial_num; ///< serial number
     int64_t last_granule; ///< last packet granule
+    /* for embeded pictures */
+    OGGPageList *comments;
+    unsigned int attach_count;
+    unsigned attached_types;
 } OGGStreamContext;
 
-typedef struct OGGPageList {
-    OGGPage page;
-    struct OGGPageList *next;
-} OGGPageList;
+typedef struct OGGAttachContext {
+    int attach_to;
+    unsigned int count;
+} OGGAttachContext;
 
 typedef struct OGGContext {
     const AVClass *class;
@@ -74,6 +85,7 @@ typedef struct OGGContext {
     int pref_size; ///< preferred page size (0 => fill all segments)
     int64_t pref_duration;      ///< preferred page duration (0 => fill all segments)
     int serial_offset;
+    unsigned int attach_count;
 } OGGContext;
 
 #define OFFSET(x) offsetof(OGGContext, x)
@@ -169,7 +181,7 @@ static int ogg_reset_cur_page(OGGStreamContext *oggstream)
     return 0;
 }
 
-static int ogg_buffer_page(AVFormatContext *s, OGGStreamContext *oggstream)
+static int ogg_buffer_page(AVFormatContext *s, OGGStreamContext *oggstream, OGGPageList **page)
 {
     OGGContext *ogg = s->priv_data;
     OGGPageList **p = &ogg->page_list;
@@ -190,6 +202,7 @@ static int ogg_buffer_page(AVFormatContext *s, OGGStreamContext *oggstream)
     }
     l->next = *p;
     *p = l;
+    if (page) *page = l;
 
     return 0;
 }
@@ -214,14 +227,14 @@ static int ogg_buffer_data(AVFormatContext *s, AVStream *st,
          ogg_granule_to_timestamp(oggstream, oggstream->last_granule) + 1 ||
          ogg_key_granule(oggstream, granule))) {
         if (oggstream->page.granule != -1)
-            ogg_buffer_page(s, oggstream);
+            ogg_buffer_page(s, oggstream, NULL);
         flush = 1;
     }
 
     // avoid a continued page
     if (!header && oggstream->page.size > 0 &&
         MAX_PAGE_SIZE - oggstream->page.size < size) {
-        ogg_buffer_page(s, oggstream);
+        ogg_buffer_page(s, oggstream, NULL);
     }
 
     for (i = 0; i < total_segments; ) {
@@ -255,34 +268,87 @@ static int ogg_buffer_data(AVFormatContext *s, AVStream *st,
                                          st->time_base, AV_TIME_BASE_Q);
 
             if (page->segments_count == 255) {
-                ogg_buffer_page(s, oggstream);
+                ogg_buffer_page(s, oggstream, NULL);
             } else if (!header) {
                 if ((ogg->pref_size     > 0 && page->size   >= ogg->pref_size) ||
                     (ogg->pref_duration > 0 && next - start >= ogg->pref_duration)) {
-                    ogg_buffer_page(s, oggstream);
+                    ogg_buffer_page(s, oggstream, NULL);
                 }
             }
         }
     }
 
     if (flush && oggstream->page.granule != -1)
-        ogg_buffer_page(s, oggstream);
+        ogg_buffer_page(s, oggstream, NULL);
+
+    return 0;
+}
+
+static int ogg_append_page(AVFormatContext *s, OGGPageList **page_list,
+                           uint8_t *data, unsigned size, int new_packet)
+{
+    int seg_size = 255, started = 0;
+    OGGPage *p = &(*page_list)->page;
+    int64_t granule = p->granule;
+
+    if (!new_packet) {
+        p->granule = -1;
+        int append = FFMIN(255 - p->segments[p->segments_count - 1], size);
+        memcpy(p->data + p->size, data, append);
+        p->size += append;
+        seg_size = (p->segments[p->segments_count - 1] += append);
+        data += append;
+        size -= append;
+        started = 1;
+    }
 
+    while (size > 0 || seg_size == 255) {
+        if (p->segments_count == 255) {
+            OGGPageList *new_page = av_malloc(sizeof(OGGPageList));
+            if (!new_page)
+                return AVERROR(ENOMEM);
+            new_page->page = (OGGPage) {
+                .start_granule = p->start_granule,
+                .granule = -1,
+                .stream_index = p->stream_index,
+                .flags = started,
+                .segments_count = 0,
+                .size = 0,
+            };
+            new_page->next = (*page_list)->next;
+            (*page_list)->next = new_page;
+            (*page_list) = new_page;
+            p = &new_page->page;
+            ((OGGStreamContext *) s->streams[p->stream_index]->priv_data)->page_count++;
+        }
+
+        seg_size = FFMIN(255, size);
+        memcpy(p->data + p->size, data, seg_size);
+        p->size += seg_size;
+        p->segments[p->segments_count++] = seg_size;
+        data += seg_size;
+        size -= seg_size;
+        started = 1;
+    }
+
+    p->granule = granule;
     return 0;
 }
 
 static uint8_t *ogg_write_vorbiscomment(int64_t offset, int bitexact,
                                         int *header_len, AVDictionary **m, int framing_bit,
-                                        AVChapter **chapters, unsigned int nb_chapters)
+                                        AVChapter **chapters, unsigned int nb_chapters,
+                                        unsigned int nb_attach)
 {
     const char *vendor = bitexact ? "ffmpeg" : LIBAVFORMAT_IDENT;
     AVIOContext pb;
-    int64_t size;
+    int64_t comment_size, size;
     uint8_t *p;
 
     ff_metadata_conv(m, ff_vorbiscomment_metadata_conv, NULL);
 
-    size = offset + ff_vorbiscomment_length(*m, vendor, chapters, nb_chapters) + framing_bit;
+    comment_size = ff_vorbiscomment_length(*m, vendor, chapters, nb_chapters);
+    size = offset + comment_size + framing_bit;
     if (size > INT_MAX)
         return NULL;
     p = av_mallocz(size);
@@ -290,7 +356,7 @@ static uint8_t *ogg_write_vorbiscomment(int64_t offset, int bitexact,
         return NULL;
 
     ffio_init_context(&pb, p + offset, size - offset, 1, NULL, NULL, NULL, NULL);
-    ff_vorbiscomment_write(&pb, *m, vendor, chapters, nb_chapters);
+    ff_vorbiscomment_write(&pb, *m, vendor, chapters, nb_chapters, nb_attach);
     if (framing_bit)
         avio_w8(&pb, 1);
 
@@ -317,18 +383,21 @@ static int ogg_build_flac_headers(AVCodecParameters *par,
     bytestream_put_buffer(&p, "FLAC", 4);
     bytestream_put_byte(&p, 1); // major version
     bytestream_put_byte(&p, 0); // minor version
-    bytestream_put_be16(&p, 1); // headers packets without this one
+    bytestream_put_be16(&p, 1 + oggstream->attach_count); // headers packets without this one
     bytestream_put_buffer(&p, "fLaC", 4);
     bytestream_put_byte(&p, 0x00); // streaminfo
     bytestream_put_be24(&p, 34);
     bytestream_put_buffer(&p, par->extradata, FLAC_STREAMINFO_SIZE);
 
     // second packet: VorbisComment
-    p = ogg_write_vorbiscomment(4, bitexact, &oggstream->header_len[1], m, 0, NULL, 0);
+    p = ogg_write_vorbiscomment(4, bitexact, &oggstream->header_len[1], m, 0, NULL, 0, 0);
     if (!p)
         return AVERROR(ENOMEM);
     oggstream->header[1] = p;
-    bytestream_put_byte(&p, 0x84); // last metadata block and vorbis comment
+    if (!oggstream->attach_count)
+        bytestream_put_byte(&p, 0x84); // last metadata block and vorbis comment
+    else
+        bytestream_put_byte(&p, 0x04); // vorbis comment followed by attachments
     bytestream_put_be24(&p, oggstream->header_len[1] - 4);
 
     return 0;
@@ -355,7 +424,8 @@ static int ogg_build_speex_headers(AVCodecParameters *par,
     AV_WL32(&oggstream->header[0][68], 0);  // set extra_headers to 0
 
     // second packet: VorbisComment
-    p = ogg_write_vorbiscomment(0, bitexact, &oggstream->header_len[1], m, 0, NULL, 0);
+    p = ogg_write_vorbiscomment(0, bitexact, &oggstream->header_len[1], m, 0,
+                                NULL, 0, oggstream->attach_count);
     if (!p)
         return AVERROR(ENOMEM);
     oggstream->header[1] = p;
@@ -384,7 +454,8 @@ static int ogg_build_opus_headers(AVCodecParameters *par,
     bytestream_put_buffer(&p, par->extradata, par->extradata_size);
 
     /* second packet: VorbisComment */
-    p = ogg_write_vorbiscomment(8, bitexact, &oggstream->header_len[1], m, 0, chapters, nb_chapters);
+    p = ogg_write_vorbiscomment(8, bitexact, &oggstream->header_len[1], m, 0,
+                                chapters, nb_chapters, oggstream->attach_count);
     if (!p)
         return AVERROR(ENOMEM);
     oggstream->header[1] = p;
@@ -428,8 +499,9 @@ static int ogg_build_vp8_headers(AVFormatContext *s, AVStream *st,
     bytestream_put_be32(&p, st->time_base.num);
 
     /* optional second packet: VorbisComment */
-    if (av_dict_get(st->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX)) {
-        p = ogg_write_vorbiscomment(7, bitexact, &oggstream->header_len[1], &st->metadata, 0, NULL, 0);
+    if (av_dict_get(st->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX) || oggstream->attach_count) {
+        p = ogg_write_vorbiscomment(7, bitexact, &oggstream->header_len[1], &st->metadata, 0,
+                                    NULL, 0, oggstream->attach_count);
         if (!p)
             return AVERROR(ENOMEM);
         oggstream->header[1] = p;
@@ -470,22 +542,18 @@ static int ogg_init(AVFormatContext *s)
 {
     OGGContext *ogg = s->priv_data;
     OGGStreamContext *oggstream = NULL;
-    int i, j;
+    OGGAttachContext *attachstream = NULL;
+    AVStream *st;
+    int i, j, k = 0;
 
     if (ogg->pref_size)
         av_log(s, AV_LOG_WARNING, "The pagesize option is deprecated\n");
 
+    // init stream priv_data
     for (i = 0; i < s->nb_streams; i++) {
-        AVStream *st = s->streams[i];
-        unsigned serial_num = i + ogg->serial_offset;
-
-        if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
-            if (st->codecpar->codec_id == AV_CODEC_ID_OPUS)
-                /* Opus requires a fixed 48kHz clock */
-                avpriv_set_pts_info(st, 64, 1, 48000);
-            else
-                avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
-        }
+        st = s->streams[i];
+        if (st->disposition & AV_DISPOSITION_ATTACHED_PIC)
+            continue;
 
         if (st->codecpar->codec_id != AV_CODEC_ID_VORBIS &&
             st->codecpar->codec_id != AV_CODEC_ID_THEORA &&
@@ -497,14 +565,82 @@ static int ogg_init(AVFormatContext *s)
             return AVERROR(EINVAL);
         }
 
+        oggstream = av_mallocz(sizeof(*oggstream));
+        if (!oggstream)
+            return AVERROR(ENOMEM);
+        st->priv_data = oggstream;
+    }
+
+    // setup attachment association
+    for (i = 0; i < s->nb_streams; i++) {
+        st = s->streams[i];
+        if (!(st->disposition & AV_DISPOSITION_ATTACHED_PIC))
+            continue;
+        ogg->attach_count++;
+
+        if (st->codecpar->codec_id != AV_CODEC_ID_GIF &&
+            st->codecpar->codec_id != AV_CODEC_ID_MJPEG &&
+            st->codecpar->codec_id != AV_CODEC_ID_PNG &&
+            st->codecpar->codec_id != AV_CODEC_ID_TIFF &&
+            st->codecpar->codec_id != AV_CODEC_ID_BMP) {
+            av_log(s, AV_LOG_ERROR, "Unsupported attachment codec id in stream %d\n", i);
+            return AVERROR(EINVAL);
+        }
+
+        attachstream = av_mallocz(sizeof(*attachstream));
+        if (!attachstream)
+            return AVERROR(ENOMEM);
+        st->priv_data = attachstream;
+
+        int attached = 0;
+        AVDictionaryEntry *e = av_dict_get(st->metadata, "ogg_attach", NULL, 0);
+        if (e) {
+            int ogg_attach = -1;
+            int res = sscanf(e->value, "%d", &ogg_attach);
+            if (res > 0 && ogg_attach >= 0 && ogg_attach < s->nb_streams &&
+                !(s->streams[ogg_attach]->disposition & AV_DISPOSITION_ATTACHED_PIC)) {
+                attachstream->attach_to = ogg_attach;
+                oggstream = s->streams[ogg_attach]->priv_data;
+                oggstream->attach_count++;
+                attached = 1;
+            }
+        }
+
+        for (j = 0; !attached && j < s->nb_streams; ++j) {
+            if (!(s->streams[j]->disposition & AV_DISPOSITION_ATTACHED_PIC)) {
+                attachstream->attach_to = j;
+                oggstream = s->streams[j]->priv_data;
+                oggstream->attach_count++;
+                attached = 1;
+            }
+        }
+        if (!attached) {
+            av_log(s, AV_LOG_ERROR, "Cannot add attachment %d without an audio/video stream\n", i);
+            return AVERROR(EINVAL);
+        }
+    }
+
+    for (i = 0; i < s->nb_streams; i++) {
+        st = s->streams[i];
+        if (st->disposition & AV_DISPOSITION_ATTACHED_PIC)
+            continue;
+
+        unsigned serial_num = k++ + ogg->serial_offset;
+
+        if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
+            if (st->codecpar->codec_id == AV_CODEC_ID_OPUS)
+                /* Opus requires a fixed 48kHz clock */
+                avpriv_set_pts_info(st, 64, 1, 48000);
+            else
+                avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
+        }
+
         if ((!st->codecpar->extradata || !st->codecpar->extradata_size) &&
             st->codecpar->codec_id != AV_CODEC_ID_VP8) {
             av_log(s, AV_LOG_ERROR, "No extradata present\n");
             return AVERROR_INVALIDDATA;
         }
-        oggstream = av_mallocz(sizeof(*oggstream));
-        if (!oggstream)
-            return AVERROR(ENOMEM);
+        oggstream = st->priv_data;
 
         oggstream->page.stream_index = i;
 
@@ -521,7 +657,6 @@ static int ogg_init(AVFormatContext *s)
 
         av_dict_copy(&st->metadata, s->metadata, AV_DICT_DONT_OVERWRITE);
 
-        st->priv_data = oggstream;
         if (st->codecpar->codec_id == AV_CODEC_ID_FLAC) {
             int err = ogg_build_flac_headers(st->codecpar, oggstream,
                                              s->flags & AVFMT_FLAG_BITEXACT,
@@ -557,7 +692,8 @@ static int ogg_init(AVFormatContext *s)
             uint8_t *p;
             const char *cstr = st->codecpar->codec_id == AV_CODEC_ID_VORBIS ? "vorbis" : "theora";
             int header_type = st->codecpar->codec_id == AV_CODEC_ID_VORBIS ? 3 : 0x81;
-            int framing_bit = st->codecpar->codec_id == AV_CODEC_ID_VORBIS ? 1 : 0;
+            int framing_bit = oggstream->attach_count > 0 ? 0 : 
+                              st->codecpar->codec_id == AV_CODEC_ID_VORBIS ? 1 : 0;
 
             if (avpriv_split_xiph_headers(st->codecpar->extradata, st->codecpar->extradata_size,
                                       st->codecpar->codec_id == AV_CODEC_ID_VORBIS ? 30 : 42,
@@ -569,7 +705,7 @@ static int ogg_init(AVFormatContext *s)
 
             p = ogg_write_vorbiscomment(7, s->flags & AVFMT_FLAG_BITEXACT,
                                         &oggstream->header_len[1], &st->metadata,
-                                        framing_bit, NULL, 0);
+                                        framing_bit, NULL, 0, oggstream->attach_count);
             oggstream->header[1] = p;
             if (!p)
                 return AVERROR(ENOMEM);
@@ -601,36 +737,129 @@ static int ogg_init(AVFormatContext *s)
 
 static int ogg_write_header(AVFormatContext *s)
 {
+    OGGContext *ogg = s->priv_data;
     OGGStreamContext *oggstream = NULL;
-    int i, j;
+    int j;
 
     for (j = 0; j < s->nb_streams; j++) {
+        if (s->streams[j]->disposition & AV_DISPOSITION_ATTACHED_PIC)
+            continue;
         oggstream = s->streams[j]->priv_data;
         ogg_buffer_data(s, s->streams[j], oggstream->header[0],
                         oggstream->header_len[0], 0, 1);
         oggstream->page.flags |= 2; // bos
-        ogg_buffer_page(s, oggstream);
+        ogg_buffer_page(s, oggstream, NULL);
     }
+    ogg_write_pages(s, 2);
+
     for (j = 0; j < s->nb_streams; j++) {
+        if (s->streams[j]->disposition & AV_DISPOSITION_ATTACHED_PIC)
+            continue;
         AVStream *st = s->streams[j];
         oggstream = st->priv_data;
-        for (i = 1; i < 3; i++) {
-            if (oggstream->header_len[i])
-                ogg_buffer_data(s, st, oggstream->header[i],
-                                oggstream->header_len[i], 0, 1);
+        if (oggstream->header_len[1]) {
+            ogg_buffer_data(s, st, oggstream->header[1],
+                            oggstream->header_len[1], 0, 1);
+            ogg_buffer_page(s, oggstream, &oggstream->comments);
+        }
+        if (oggstream->header_len[2]) {
+            ogg_buffer_data(s, st, oggstream->header[2],
+                            oggstream->header_len[2], 0, 1);
+            ogg_buffer_page(s, oggstream, NULL);
         }
-        ogg_buffer_page(s, oggstream);
     }
 
     oggstream->page.start_granule = AV_NOPTS_VALUE;
 
-    ogg_write_pages(s, 2);
+    if (!ogg->attach_count)
+        ogg_write_pages(s, 2);
+
+    return 0;
+}
+
+static int ogg_write_attached_packet_internal(AVFormatContext *s, AVPacket *pkt)
+{
+    OGGContext *ogg = s->priv_data;
+    AVStream *st = s->streams[pkt->stream_index];
+    OGGAttachContext *attachstream = st->priv_data;
+    AVStream *base_st = s->streams[attachstream->attach_to];
+    OGGStreamContext *oggstream = base_st->priv_data;
+    uint8_t *data;
+    int data_len;
+    int ret;
+
+    attachstream->count++;
+    // Only use the first packet received for each attached stream
+    if (attachstream->count == 2)
+        av_log(s, AV_LOG_WARNING, "Attached stream %d has too many packets, ignoring\n",
+               pkt->stream_index);
+    if (attachstream->count > 1)
+        return 0;
+
+    if (!ogg->attach_count || !oggstream->attach_count) {
+        av_log(s, AV_LOG_ERROR, "More attached streams than expected\n");
+        return -1;
+    }
+
+    AVIOContext *pb;
+    avio_open_dyn_buf(&pb);
+    if (!pb)
+        return AVERROR(ENOMEM);
 
+    if (base_st->codecpar->codec_id == AV_CODEC_ID_FLAC) {
+        int picture_len = ff_flac_picture_length(s, pkt);
+        if (picture_len >= 1<<24) {
+            av_log(s, AV_LOG_ERROR, "Picture block too big %d >= %d\n", picture_len, 1<<24);
+            return AVERROR(EINVAL);
+        }
+        if (oggstream->attach_count == 1)
+            avio_w8(pb, 0x86); // last attachment
+        else
+            avio_w8(pb, 0x06);
+        avio_wb24(pb, picture_len);
+        ff_flac_write_picture(s, pb, pkt, &oggstream->attached_types);
+        data_len = avio_close_dyn_buf(pb, &data);
+        if (!data || data_len < 0)
+            return AVERROR(ENOMEM);
+    } else {
+        uint8_t *bin_data;
+        int bin_data_len;
+        ff_flac_write_picture(s, pb, pkt, &oggstream->attached_types);
+        bin_data_len = avio_close_dyn_buf(pb, &bin_data);
+        if (!bin_data || bin_data_len < 0)
+            return AVERROR(ENOMEM);
+
+        data_len = 4 + 23 + AV_BASE64_SIZE(bin_data_len) - 1;
+        data = av_malloc(data_len + 1);
+        if (!data)
+            return AVERROR(ENOMEM);
+        AV_WL32(data, data_len - 4);
+        strcpy(data + 4, "METADATA_BLOCK_PICTURE=");
+        av_base64_encode(data + 4 + 23, data_len - 4 - 23 + 1, bin_data, bin_data_len);
+        av_free(bin_data);
+
+        // add framing bit when required
+        if (oggstream->attach_count == 1 &&
+            base_st->codecpar->codec_id == AV_CODEC_ID_VORBIS)
+            data[data_len++] = 1;
+    }
+
+    ret = ogg_append_page(s, &oggstream->comments, data, data_len,
+                          base_st->codecpar->codec_id == AV_CODEC_ID_FLAC);
+    av_free(data);
+    if (ret < 0)
+        return ret;
+
+    oggstream->attach_count--;
+    ogg->attach_count--;
+    if (!ogg->attach_count)
+        ogg_write_pages(s, 0);
     return 0;
 }
 
 static int ogg_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
 {
+    OGGContext *ogg = s->priv_data;
     AVStream *st = s->streams[pkt->stream_index];
     OGGStreamContext *oggstream = st->priv_data;
     int ret;
@@ -674,7 +903,9 @@ static int ogg_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
     if (ret < 0)
         return ret;
 
-    ogg_write_pages(s, 0);
+    if (!ogg->attach_count) {
+        ogg_write_pages(s, 0);
+    }
 
     oggstream->last_granule = granule;
 
@@ -683,15 +914,26 @@ static int ogg_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
 
 static int ogg_write_packet(AVFormatContext *s, AVPacket *pkt)
 {
+    OGGContext *ogg = s->priv_data;
     int i;
 
-    if (pkt)
-        return ogg_write_packet_internal(s, pkt);
+    if (pkt) {
+        AVStream *st = s->streams[pkt->stream_index];
+        if (st->disposition & AV_DISPOSITION_ATTACHED_PIC)
+            return ogg_write_attached_packet_internal(s, pkt);
+        else
+            return ogg_write_packet_internal(s, pkt);
+    }
+
+    if (ogg->attach_count)
+        return 0;
 
     for (i = 0; i < s->nb_streams; i++) {
+        if (s->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC)
+            continue;
         OGGStreamContext *oggstream = s->streams[i]->priv_data;
         if (oggstream->page.segments_count)
-            ogg_buffer_page(s, oggstream);
+            ogg_buffer_page(s, oggstream, NULL);
     }
 
     ogg_write_pages(s, 2);
@@ -700,14 +942,20 @@ static int ogg_write_packet(AVFormatContext *s, AVPacket *pkt)
 
 static int ogg_write_trailer(AVFormatContext *s)
 {
+    OGGContext *ogg = s->priv_data;
     int i;
 
+    if (ogg->attach_count)
+        av_log(s, AV_LOG_WARNING, "Some attached images were never written\n");
+
     /* flush current page if needed */
     for (i = 0; i < s->nb_streams; i++) {
+        if (s->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC)
+            continue;
         OGGStreamContext *oggstream = s->streams[i]->priv_data;
 
         if (oggstream->page.size > 0)
-            ogg_buffer_page(s, oggstream);
+            ogg_buffer_page(s, oggstream, NULL);
     }
 
     ogg_write_pages(s, 1);
@@ -723,16 +971,18 @@ static void ogg_free(AVFormatContext *s)
 
     for (i = 0; i < s->nb_streams; i++) {
         AVStream *st = s->streams[i];
-        OGGStreamContext *oggstream = st->priv_data;
-        if (!oggstream)
-            continue;
-        if (st->codecpar->codec_id == AV_CODEC_ID_FLAC ||
-            st->codecpar->codec_id == AV_CODEC_ID_SPEEX ||
-            st->codecpar->codec_id == AV_CODEC_ID_OPUS ||
-            st->codecpar->codec_id == AV_CODEC_ID_VP8) {
-            av_freep(&oggstream->header[0]);
-        }
-        av_freep(&oggstream->header[1]);
+        if (!(s->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC)) {
+            OGGStreamContext *oggstream = st->priv_data;
+            if (!oggstream)
+                continue;
+            if (st->codecpar->codec_id == AV_CODEC_ID_FLAC ||
+                st->codecpar->codec_id == AV_CODEC_ID_SPEEX ||
+                st->codecpar->codec_id == AV_CODEC_ID_OPUS ||
+                st->codecpar->codec_id == AV_CODEC_ID_VP8) {
+                av_freep(&oggstream->header[0]);
+            }
+            av_freep(&oggstream->header[1]);
+         }
     }
 
     while (p) {
@@ -743,6 +993,28 @@ static void ogg_free(AVFormatContext *s)
     ogg->page_list = NULL;
 }
 
+static int ogg_query_codec(enum AVCodecID id, int std_compliance)
+{
+    switch (id) {
+        case AV_CODEC_ID_VORBIS:
+        case AV_CODEC_ID_THEORA:
+        case AV_CODEC_ID_SPEEX:
+        case AV_CODEC_ID_FLAC:
+        case AV_CODEC_ID_OPUS:
+        case AV_CODEC_ID_VP8:
+            return 1;
+        case AV_CODEC_ID_GIF:
+        case AV_CODEC_ID_MJPEG:
+        case AV_CODEC_ID_PNG:
+        case AV_CODEC_ID_TIFF:
+        case AV_CODEC_ID_BMP:
+            return MKTAG('A', 'P', 'I', 'C');
+        default:
+            return 0;
+    }
+    return 0;
+}
+
 #if CONFIG_OGG_MUXER
 OGG_CLASS(ogg, Ogg)
 AVOutputFormat ff_ogg_muxer = {
@@ -771,6 +1043,7 @@ AVOutputFormat ff_ogg_muxer = {
     .deinit            = ogg_free,
     .flags             = AVFMT_TS_NEGATIVE | AVFMT_TS_NONSTRICT | AVFMT_ALLOW_FLUSH,
     .priv_class        = &ogg_muxer_class,
+    .query_codec       = ogg_query_codec,
 };
 #endif
 
@@ -783,6 +1056,7 @@ AVOutputFormat ff_oga_muxer = {
     .extensions        = "oga",
     .priv_data_size    = sizeof(OGGContext),
     .audio_codec       = AV_CODEC_ID_FLAC,
+    .video_codec       = AV_CODEC_ID_MJPEG,
     .init              = ogg_init,
     .write_header      = ogg_write_header,
     .write_packet      = ogg_write_packet,
@@ -790,6 +1064,7 @@ AVOutputFormat ff_oga_muxer = {
     .deinit            = ogg_free,
     .flags             = AVFMT_TS_NEGATIVE | AVFMT_ALLOW_FLUSH,
     .priv_class        = &oga_muxer_class,
+    .query_codec       = ogg_query_codec,
 };
 #endif
 
@@ -812,6 +1087,7 @@ AVOutputFormat ff_ogv_muxer = {
     .deinit            = ogg_free,
     .flags             = AVFMT_TS_NEGATIVE | AVFMT_TS_NONSTRICT | AVFMT_ALLOW_FLUSH,
     .priv_class        = &ogv_muxer_class,
+    .query_codec       = ogg_query_codec,
 };
 #endif
 
@@ -824,6 +1100,7 @@ AVOutputFormat ff_spx_muxer = {
     .extensions        = "spx",
     .priv_data_size    = sizeof(OGGContext),
     .audio_codec       = AV_CODEC_ID_SPEEX,
+    .video_codec       = AV_CODEC_ID_MJPEG,
     .init              = ogg_init,
     .write_header      = ogg_write_header,
     .write_packet      = ogg_write_packet,
@@ -831,6 +1108,7 @@ AVOutputFormat ff_spx_muxer = {
     .deinit            = ogg_free,
     .flags             = AVFMT_TS_NEGATIVE | AVFMT_ALLOW_FLUSH,
     .priv_class        = &spx_muxer_class,
+    .query_codec       = ogg_query_codec,
 };
 #endif
 
@@ -843,6 +1121,7 @@ AVOutputFormat ff_opus_muxer = {
     .extensions        = "opus",
     .priv_data_size    = sizeof(OGGContext),
     .audio_codec       = AV_CODEC_ID_OPUS,
+    .video_codec       = AV_CODEC_ID_MJPEG,
     .init              = ogg_init,
     .write_header      = ogg_write_header,
     .write_packet      = ogg_write_packet,
@@ -850,5 +1129,6 @@ AVOutputFormat ff_opus_muxer = {
     .deinit            = ogg_free,
     .flags             = AVFMT_TS_NEGATIVE | AVFMT_ALLOW_FLUSH,
     .priv_class        = &opus_muxer_class,
+    .query_codec       = ogg_query_codec,
 };
 #endif
diff --git a/libavformat/oggparseflac.c b/libavformat/oggparseflac.c
index 4e85b05c67..840d1b73ef 100644
--- a/libavformat/oggparseflac.c
+++ b/libavformat/oggparseflac.c
@@ -22,6 +22,7 @@
 #include "libavcodec/get_bits.h"
 #include "libavcodec/flac.h"
 #include "avformat.h"
+#include "flac_picture.h"
 #include "internal.h"
 #include "oggdec.h"
 
@@ -72,6 +73,9 @@ flac_header (AVFormatContext * s, int idx)
         avpriv_set_pts_info(st, 64, 1, samplerate);
     } else if (mdt == FLAC_METADATA_TYPE_VORBIS_COMMENT) {
         ff_vorbis_stream_comment(s, st, os->buf + os->pstart + 4, os->psize - 4);
+    } else if (mdt == FLAC_METADATA_TYPE_PICTURE) {
+        int ret = ff_flac_parse_picture(s, os->buf + os->pstart + 4, os->psize - 4, idx, 1);
+        if (ret < 0) return ret;
     }
 
     return 1;
diff --git a/libavformat/oggparsevorbis.c b/libavformat/oggparsevorbis.c
index 0e8c25c030..c400fe8587 100644
--- a/libavformat/oggparsevorbis.c
+++ b/libavformat/oggparsevorbis.c
@@ -75,7 +75,7 @@ static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val)
 int ff_vorbis_stream_comment(AVFormatContext *as, AVStream *st,
                              const uint8_t *buf, int size)
 {
-    int updates = ff_vorbis_comment(as, &st->metadata, buf, size, 1);
+    int updates = ff_vorbis_comment(as, &st->metadata, buf, size, st->index);
 
     if (updates > 0) {
         st->event_flags |= AVSTREAM_EVENT_FLAG_METADATA_UPDATED;
@@ -86,7 +86,7 @@ int ff_vorbis_stream_comment(AVFormatContext *as, AVStream *st,
 
 int ff_vorbis_comment(AVFormatContext *as, AVDictionary **m,
                       const uint8_t *buf, int size,
-                      int parse_picture)
+                      int parse_picture_index)
 {
     const uint8_t *p   = buf;
     const uint8_t *end = buf + size;
@@ -151,7 +151,7 @@ int ff_vorbis_comment(AVFormatContext *as, AVDictionary **m,
              * 'METADATA_BLOCK_PICTURE'. This is the preferred and
              * recommended way of embedding cover art within VorbisComments."
              */
-            if (!av_strcasecmp(tt, "METADATA_BLOCK_PICTURE") && parse_picture) {
+            if (!av_strcasecmp(tt, "METADATA_BLOCK_PICTURE") && parse_picture_index > -2) {
                 int ret, len = AV_BASE64_DECODE_SIZE(vl);
                 char *pict = av_malloc(len);
 
@@ -165,7 +165,7 @@ int ff_vorbis_comment(AVFormatContext *as, AVDictionary **m,
                 av_freep(&tt);
                 av_freep(&ct);
                 if (ret > 0)
-                    ret = ff_flac_parse_picture(as, pict, ret, 0);
+                    ret = ff_flac_parse_picture(as, pict, ret, parse_picture_index, 0);
                 av_freep(&pict);
                 if (ret < 0) {
                     av_log(as, AV_LOG_WARNING, "Failed to parse cover art block.\n");
diff --git a/libavformat/vorbiscomment.c b/libavformat/vorbiscomment.c
index a929634cc0..89127236fa 100644
--- a/libavformat/vorbiscomment.c
+++ b/libavformat/vorbiscomment.c
@@ -21,6 +21,7 @@
 
 #include "avio.h"
 #include "avformat.h"
+#include "flac_picture.h"
 #include "metadata.h"
 #include "vorbiscomment.h"
 #include "libavutil/dict.h"
@@ -43,6 +44,12 @@ int64_t ff_vorbiscomment_length(const AVDictionary *m, const char *vendor_string
 {
     int64_t len = 8;
     len += strlen(vendor_string);
+    if (m) {
+        AVDictionaryEntry *tag = NULL;
+        while ((tag = av_dict_get(m, "", tag, AV_DICT_IGNORE_SUFFIX))) {
+            len += 4 +strlen(tag->key) + 1 + strlen(tag->value);
+        }
+    }
     if (chapters && nb_chapters) {
         for (int i = 0; i < nb_chapters; i++) {
             AVDictionaryEntry *tag = NULL;
@@ -53,18 +60,12 @@ int64_t ff_vorbiscomment_length(const AVDictionary *m, const char *vendor_string
             }
         }
     }
-    if (m) {
-        AVDictionaryEntry *tag = NULL;
-        while ((tag = av_dict_get(m, "", tag, AV_DICT_IGNORE_SUFFIX))) {
-            len += 4 +strlen(tag->key) + 1 + strlen(tag->value);
-        }
-    }
     return len;
 }
 
-int ff_vorbiscomment_write(AVIOContext *pb, const AVDictionary *m,
-                           const char *vendor_string,
-                           AVChapter **chapters, unsigned int nb_chapters)
+int ff_vorbiscomment_write(AVIOContext *pb, const AVDictionary *m, const char *vendor_string,
+                           AVChapter **chapters, unsigned int nb_chapters,
+                           int external_count)
 {
     int cm_count = 0;
     avio_wl32(pb, strlen(vendor_string));
@@ -74,10 +75,11 @@ int ff_vorbiscomment_write(AVIOContext *pb, const AVDictionary *m,
             cm_count += av_dict_count(chapters[i]->metadata) + 1;
         }
     }
+    int count = av_dict_count(m) + cm_count + external_count;
+    avio_wl32(pb, count);
+
     if (m) {
-        int count = av_dict_count(m) + cm_count;
         AVDictionaryEntry *tag = NULL;
-        avio_wl32(pb, count);
         while ((tag = av_dict_get(m, "", tag, AV_DICT_IGNORE_SUFFIX))) {
             int64_t len1 = strlen(tag->key);
             int64_t len2 = strlen(tag->value);
@@ -88,6 +90,8 @@ int ff_vorbiscomment_write(AVIOContext *pb, const AVDictionary *m,
             avio_w8(pb, '=');
             avio_write(pb, tag->value, len2);
         }
+    }
+    if (chapters && nb_chapters) {
         for (int i = 0; i < nb_chapters; i++) {
             AVChapter *chp = chapters[i];
             char chapter_time[13];
@@ -107,7 +111,7 @@ int ff_vorbiscomment_write(AVIOContext *pb, const AVDictionary *m,
             avio_w8(pb, '=');
             avio_write(pb, chapter_time, 12);
 
-            tag = NULL;
+            AVDictionaryEntry *tag = NULL;
             while ((tag = av_dict_get(chapters[i]->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
                 int64_t len1 = !strcmp(tag->key, "title") ? 4 : strlen(tag->key);
                 int64_t len2 = strlen(tag->value);
@@ -124,7 +128,7 @@ int ff_vorbiscomment_write(AVIOContext *pb, const AVDictionary *m,
                 avio_write(pb, tag->value, len2);
             }
         }
-    } else
-        avio_wl32(pb, 0);
+    }
+
     return 0;
 }
diff --git a/libavformat/vorbiscomment.h b/libavformat/vorbiscomment.h
index 7cacd0b2a0..1dc9ed1da0 100644
--- a/libavformat/vorbiscomment.h
+++ b/libavformat/vorbiscomment.h
@@ -48,9 +48,9 @@ int64_t ff_vorbiscomment_length(const AVDictionary *m, const char *vendor_string
  * @param chapters The chapters to write.
  * @param nb_chapters The number of chapters to write.
  */
-int ff_vorbiscomment_write(AVIOContext *pb, const AVDictionary *m,
-                           const char *vendor_string,
-                           AVChapter **chapters, unsigned int nb_chapters);
+int ff_vorbiscomment_write(AVIOContext *pb, const AVDictionary *m, const char *vendor_string,
+                           AVChapter **chapters, unsigned int nb_chapters,
+                           int external_count);
 
 extern const AVMetadataConv ff_vorbiscomment_metadata_conv[];
 
