diff options
Diffstat (limited to 'libavformat/oggparsevorbis.c')
-rw-r--r-- | libavformat/oggparsevorbis.c | 64 |
1 files changed, 50 insertions, 14 deletions
diff --git a/libavformat/oggparsevorbis.c b/libavformat/oggparsevorbis.c index 1804e9a6af..a63e5978d9 100644 --- a/libavformat/oggparsevorbis.c +++ b/libavformat/oggparsevorbis.c @@ -25,12 +25,14 @@ #include <stdlib.h> #include "libavutil/avstring.h" +#include "libavutil/base64.h" #include "libavutil/bswap.h" #include "libavutil/dict.h" #include "libavcodec/bytestream.h" #include "libavcodec/get_bits.h" #include "libavcodec/vorbis_parser.h" #include "avformat.h" +#include "flac_picture.h" #include "internal.h" #include "oggdec.h" #include "vorbiscomment.h" @@ -130,7 +132,26 @@ int ff_vorbis_comment(AVFormatContext *as, AVDictionary **m, memcpy(ct, v, vl); ct[vl] = 0; - if (!ogm_chapter(as, tt, ct)) + if (!strcmp(tt, "METADATA_BLOCK_PICTURE")) { + int ret; + char *pict = av_malloc(vl); + + if (!pict) { + av_log(as, AV_LOG_WARNING, "out-of-memory error. Skipping cover art block.\n"); + av_freep(&tt); + av_freep(&ct); + continue; + } + if ((ret = av_base64_decode(pict, ct, vl)) > 0) + ret = ff_flac_parse_picture(as, pict, ret); + av_freep(&pict); + av_freep(&tt); + av_freep(&ct); + if (ret < 0) { + av_log(as, AV_LOG_WARNING, "Failed to parse cover art block.\n"); + continue; + } + } else if (!ogm_chapter(as, tt, ct)) av_dict_set(m, tt, ct, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL); @@ -177,12 +198,15 @@ static int fixup_vorbis_headers(AVFormatContext *as, uint8_t **buf) { int i, offset, len, err; + int buf_len; unsigned char *ptr; len = priv->len[0] + priv->len[1] + priv->len[2]; - ptr = *buf = av_mallocz(len + len / 255 + 64); + buf_len = len + len / 255 + 64; + ptr = *buf = av_realloc(NULL, buf_len); if (!ptr) return AVERROR(ENOMEM); + memset(*buf, '\0', buf_len); ptr[0] = 2; offset = 1; @@ -245,6 +269,7 @@ static int vorbis_header(AVFormatContext *s, int idx) const uint8_t *p = os->buf + os->pstart + 7; /* skip "\001vorbis" tag */ unsigned blocksize, bs0, bs1; int srate; + int channels; if (os->psize != 30) return AVERROR_INVALIDDATA; @@ -252,7 +277,12 @@ static int vorbis_header(AVFormatContext *s, int idx) if (bytestream_get_le32(&p) != 0) /* vorbis_version */ return AVERROR_INVALIDDATA; - st->codec->channels = bytestream_get_byte(&p); + channels = bytestream_get_byte(&p); + if (st->codec->channels && channels != st->codec->channels) { + av_log(s, AV_LOG_ERROR, "Channel change is not supported\n"); + return AVERROR_PATCHWELCOME; + } + st->codec->channels = channels; srate = bytestream_get_le32(&p); p += 4; // skip maximum bitrate st->codec->bit_rate = bytestream_get_le32(&p); // nominal bitrate @@ -317,23 +347,28 @@ static int vorbis_packet(AVFormatContext *s, int idx) * here we parse the duration of each packet in the first page and compare * the total duration to the page granule to find the encoder delay and * set the first timestamp */ - if (!os->lastpts) { - int seg; + if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) { + int seg, d; uint8_t *last_pkt = os->buf + os->pstart; uint8_t *next_pkt = last_pkt; - int first_duration = 0; avpriv_vorbis_parse_reset(&priv->vp); duration = 0; - for (seg = 0; seg < os->nsegs; seg++) { + seg = os->segp; + d = avpriv_vorbis_parse_frame(&priv->vp, last_pkt, 1); + if (d < 0) { + os->pflags |= AV_PKT_FLAG_CORRUPT; + return 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); if (d < 0) { duration = os->granule; break; } - if (!duration) - first_duration = d; duration += d; last_pkt = next_pkt + os->segments[seg]; } @@ -341,10 +376,11 @@ static int vorbis_packet(AVFormatContext *s, int idx) } os->lastpts = os->lastdts = os->granule - duration; - s->streams[idx]->start_time = os->lastpts + first_duration; - if (s->streams[idx]->duration) - s->streams[idx]->duration -= s->streams[idx]->start_time; - s->streams[idx]->cur_dts = AV_NOPTS_VALUE; + if (s->streams[idx]->start_time == AV_NOPTS_VALUE) { + s->streams[idx]->start_time = FFMAX(os->lastpts, 0); + if (s->streams[idx]->duration) + s->streams[idx]->duration -= s->streams[idx]->start_time; + } priv->final_pts = AV_NOPTS_VALUE; avpriv_vorbis_parse_reset(&priv->vp); } @@ -352,7 +388,7 @@ 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); - if (duration <= 0) { + if (duration < 0) { os->pflags |= AV_PKT_FLAG_CORRUPT; return 0; } |