diff options
Diffstat (limited to 'libavformat/oggparsevorbis.c')
-rw-r--r-- | libavformat/oggparsevorbis.c | 50 |
1 files changed, 34 insertions, 16 deletions
diff --git a/libavformat/oggparsevorbis.c b/libavformat/oggparsevorbis.c index db462fc865..da029a47df 100644 --- a/libavformat/oggparsevorbis.c +++ b/libavformat/oggparsevorbis.c @@ -173,11 +173,15 @@ static unsigned int fixup_vorbis_headers(AVFormatContext * as, struct oggvorbis_private *priv, uint8_t **buf) { - int i,offset, len; + int i,offset, len, 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 (!*buf) + return 0; + memset(*buf, '\0', buf_len); ptr[0] = 2; offset = 1; @@ -213,12 +217,12 @@ vorbis_header (AVFormatContext * s, int idx) int pkt_type = os->buf[os->pstart]; if (!(pkt_type & 1)) - return 0; + return os->private ? 0 : -1; if (!os->private) { os->private = av_mallocz(sizeof(struct oggvorbis_private)); if (!os->private) - return 0; + return -1; } if (os->psize < 1 || pkt_type > 5) @@ -233,11 +237,14 @@ vorbis_header (AVFormatContext * s, int idx) priv->len[pkt_type >> 1] = os->psize; priv->packet[pkt_type >> 1] = av_mallocz(os->psize); + if (!priv->packet[pkt_type >> 1]) + return AVERROR(ENOMEM); memcpy(priv->packet[pkt_type >> 1], os->buf + os->pstart, os->psize); if (os->buf[os->pstart] == 1) { 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 -1; @@ -245,7 +252,12 @@ vorbis_header (AVFormatContext * s, int idx) if (bytestream_get_le32(&p) != 0) /* vorbis_version */ return -1; - 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 @@ -306,33 +318,39 @@ 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]; } next_pkt += os->segments[seg]; } 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); } @@ -340,7 +358,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; } |