diff --git a/libavformat/oggparsevorbis.c b/libavformat/oggparsevorbis.c index 1c746376a8..b565232275 100644 --- a/libavformat/oggparsevorbis.c +++ b/libavformat/oggparsevorbis.c @@ -242,6 +242,36 @@ static void vorbis_cleanup(AVFormatContext *s, int idx) av_freep(&priv->packet[i]); } +static int vorbis_update_metadata(AVFormatContext *s, int idx) +{ + struct ogg *ogg = s->priv_data; + struct ogg_stream *os = ogg->streams + idx; + AVStream *st = s->streams[idx]; + int ret; + + if (os->psize <= 8) + return 0; + + /* New metadata packet; release old data. */ + av_dict_free(&st->metadata); + ret = ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, + os->psize - 8); + if (ret < 0) + return ret; + + /* Update the metadata if possible. */ + av_freep(&os->new_metadata); + if (st->metadata) { + os->new_metadata = av_packet_pack_dictionary(st->metadata, &os->new_metadata_size); + /* Send an empty dictionary to indicate that metadata has been cleared. */ + } else { + os->new_metadata = av_malloc(1); + os->new_metadata_size = 0; + } + + return ret; +} + static int vorbis_header(AVFormatContext *s, int idx) { struct ogg *ogg = s->priv_data; @@ -317,9 +347,7 @@ static int vorbis_header(AVFormatContext *s, int idx) avpriv_set_pts_info(st, 64, 1, srate); } } else if (os->buf[os->pstart] == 3) { - if (os->psize > 8 && - ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, - os->psize - 8) >= 0) { + if (vorbis_update_metadata(s, idx) >= 0) { // drop all metadata we parsed and which is not required by libvorbis unsigned new_len = 7 + 4 + AV_RL32(priv->packet[1] + 7) + 4 + 1; if (new_len >= 16 && new_len < os->psize) { @@ -350,7 +378,7 @@ static int vorbis_packet(AVFormatContext *s, int idx) struct ogg *ogg = s->priv_data; struct ogg_stream *os = ogg->streams + idx; struct oggvorbis_private *priv = os->private; - int duration; + int duration, flags = 0; /* first packet handling * here we parse the duration of each packet in the first page and compare @@ -364,19 +392,25 @@ static int vorbis_packet(AVFormatContext *s, int idx) avpriv_vorbis_parse_reset(&priv->vp); duration = 0; seg = os->segp; - d = avpriv_vorbis_parse_frame(&priv->vp, last_pkt, 1); + d = avpriv_vorbis_parse_frame_flags(&priv->vp, last_pkt, 1, &flags); if (d < 0) { os->pflags |= AV_PKT_FLAG_CORRUPT; return 0; + } else if (flags & VORBIS_FLAG_COMMENT) { + vorbis_update_metadata(s, idx); + flags = 0; } duration += d; last_pkt = next_pkt = next_pkt + os->psize; for (; seg < os->nsegs; seg++) { if (os->segments[seg] < 255) { - int d = avpriv_vorbis_parse_frame(&priv->vp, last_pkt, 1); + int d = avpriv_vorbis_parse_frame_flags(&priv->vp, last_pkt, 1, &flags); if (d < 0) { duration = os->granule; break; + } else if (flags & VORBIS_FLAG_COMMENT) { + vorbis_update_metadata(s, idx); + flags = 0; } duration += d; last_pkt = next_pkt + os->segments[seg]; @@ -396,10 +430,13 @@ static int vorbis_packet(AVFormatContext *s, int idx) /* parse packet duration */ if (os->psize > 0) { - duration = avpriv_vorbis_parse_frame(&priv->vp, os->buf + os->pstart, 1); + duration = avpriv_vorbis_parse_frame_flags(&priv->vp, os->buf + os->pstart, 1, &flags); if (duration < 0) { os->pflags |= AV_PKT_FLAG_CORRUPT; return 0; + } else if (flags & VORBIS_FLAG_COMMENT) { + vorbis_update_metadata(s, idx); + flags = 0; } os->pduration = duration; }