--- libavcodec/vorbisdec.c | 37 +---- libavformat/oggparsevorbis.c | 174 +++++++++++++-------- tests/ref/fate/ogg-vorbis-chained-meta.txt | 3 - 3 files changed, 117 insertions(+), 97 deletions(-)
diff --git a/libavcodec/vorbisdec.c b/libavcodec/vorbisdec.c index a778dc6b58..f069ac6ab3 100644 --- a/libavcodec/vorbisdec.c +++ b/libavcodec/vorbisdec.c @@ -1776,39 +1776,17 @@ static int vorbis_decode_frame(AVCodecContext *avctx, AVFrame *frame, GetBitContext *gb = &vc->gb; float *channel_ptrs[255]; int i, len, ret; + const int8_t *new_extradata; + size_t new_extradata_size; ff_dlog(NULL, "packet length %d \n", buf_size); - if (*buf == 1 && buf_size > 7) { - if ((ret = init_get_bits8(gb, buf + 1, buf_size - 1)) < 0) - return ret; - - vorbis_free(vc); - if ((ret = vorbis_parse_id_hdr(vc))) { - av_log(avctx, AV_LOG_ERROR, "Id header corrupt.\n"); - vorbis_free(vc); - return ret; - } - - av_channel_layout_uninit(&avctx->ch_layout); - if (vc->audio_channels > 8) { - avctx->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC; - avctx->ch_layout.nb_channels = vc->audio_channels; - } else { - av_channel_layout_copy(&avctx->ch_layout, &ff_vorbis_ch_layouts[vc->audio_channels - 1]); - } - - avctx->sample_rate = vc->audio_samplerate; - return buf_size; - } - - if (*buf == 3 && buf_size > 7) { - av_log(avctx, AV_LOG_DEBUG, "Ignoring comment header\n"); - return buf_size; - } + new_extradata = av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, + &new_extradata_size); - if (*buf == 5 && buf_size > 7 && vc->channel_residues && !vc->modes) { - if ((ret = init_get_bits8(gb, buf + 1, buf_size - 1)) < 0) + if (new_extradata && *new_extradata == 5 && new_extradata_size > 7 && + vc->channel_residues && !vc->modes) { + if ((ret = init_get_bits8(gb, new_extradata + 1, new_extradata_size - 1)) < 0) return ret; if ((ret = vorbis_parse_setup_hdr(vc))) { @@ -1816,7 +1794,6 @@ static int vorbis_decode_frame(AVCodecContext *avctx, AVFrame *frame, vorbis_free(vc); return ret; } - return buf_size; } if (!vc->channel_residues || !vc->modes) { diff --git a/libavformat/oggparsevorbis.c b/libavformat/oggparsevorbis.c index 9f50ab9ffc..452728b54d 100644 --- a/libavformat/oggparsevorbis.c +++ b/libavformat/oggparsevorbis.c @@ -293,6 +293,62 @@ static int vorbis_update_metadata(AVFormatContext *s, int idx) return ret; } +static int vorbis_parse_header(AVFormatContext *s, AVStream *st, + const uint8_t *p, unsigned int psize) +{ + unsigned blocksize, bs0, bs1; + int srate; + int channels; + + if (psize != 30) + return AVERROR_INVALIDDATA; + + p += 7; /* skip "\001vorbis" tag */ + + if (bytestream_get_le32(&p) != 0) /* vorbis_version */ + return AVERROR_INVALIDDATA; + + channels = bytestream_get_byte(&p); + if (st->codecpar->ch_layout.nb_channels && + channels != st->codecpar->ch_layout.nb_channels) { + av_log(s, AV_LOG_ERROR, "Channel change is not supported\n"); + return AVERROR_PATCHWELCOME; + } + st->codecpar->ch_layout.nb_channels = channels; + srate = bytestream_get_le32(&p); + p += 4; // skip maximum bitrate + st->codecpar->bit_rate = bytestream_get_le32(&p); // nominal bitrate + p += 4; // skip minimum bitrate + + blocksize = bytestream_get_byte(&p); + bs0 = blocksize & 15; + bs1 = blocksize >> 4; + + if (bs0 > bs1) + return AVERROR_INVALIDDATA; + if (bs0 < 6 || bs1 > 13) + return AVERROR_INVALIDDATA; + + if (bytestream_get_byte(&p) != 1) /* framing_flag */ + return AVERROR_INVALIDDATA; + + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + st->codecpar->codec_id = AV_CODEC_ID_VORBIS; + + if (srate > 0) { + if (st->codecpar->sample_rate && + srate != st->codecpar->sample_rate) { + av_log(s, AV_LOG_ERROR, "Sample rate change is not supported\n"); + return AVERROR_PATCHWELCOME; + } + + st->codecpar->sample_rate = srate; + avpriv_set_pts_info(st, 64, 1, srate); + } + + return 1; +} + static int vorbis_header(AVFormatContext *s, int idx) { struct ogg *ogg = s->priv_data; @@ -300,6 +356,7 @@ static int vorbis_header(AVFormatContext *s, int idx) struct ogg_stream *os = ogg->streams + idx; struct oggvorbis_private *priv; int pkt_type = os->buf[os->pstart]; + int ret; if (!os->private) { os->private = av_mallocz(sizeof(struct oggvorbis_private)); @@ -327,56 +384,18 @@ static int vorbis_header(AVFormatContext *s, int idx) priv->len[pkt_type >> 1] = os->psize; priv->packet[pkt_type >> 1] = av_memdup(os->buf + os->pstart, os->psize); + if (!priv->packet[pkt_type >> 1]) return AVERROR(ENOMEM); - 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 AVERROR_INVALIDDATA; - - if (bytestream_get_le32(&p) != 0) /* vorbis_version */ - return AVERROR_INVALIDDATA; - - channels = bytestream_get_byte(&p); - if (st->codecpar->ch_layout.nb_channels && - channels != st->codecpar->ch_layout.nb_channels) { - av_log(s, AV_LOG_ERROR, "Channel change is not supported\n"); - return AVERROR_PATCHWELCOME; - } - st->codecpar->ch_layout.nb_channels = channels; - srate = bytestream_get_le32(&p); - p += 4; // skip maximum bitrate - st->codecpar->bit_rate = bytestream_get_le32(&p); // nominal bitrate - p += 4; // skip minimum bitrate - - blocksize = bytestream_get_byte(&p); - bs0 = blocksize & 15; - bs1 = blocksize >> 4; - - if (bs0 > bs1) - return AVERROR_INVALIDDATA; - if (bs0 < 6 || bs1 > 13) - return AVERROR_INVALIDDATA; - - if (bytestream_get_byte(&p) != 1) /* framing_flag */ - return AVERROR_INVALIDDATA; - - st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; - st->codecpar->codec_id = AV_CODEC_ID_VORBIS; - - if (srate > 0) { - st->codecpar->sample_rate = srate; - avpriv_set_pts_info(st, 64, 1, srate); - } - } else if (os->buf[os->pstart] == 3) { + + if (pkt_type == 1) + return vorbis_parse_header(s, st, os->buf + os->pstart, os->psize); + + if (pkt_type == 3) { if (vorbis_update_metadata(s, idx) >= 0 && priv->len[1] > 10) { unsigned new_len; - int ret = ff_replaygain_export(st, st->metadata); + ret = ff_replaygain_export(st, st->metadata); if (ret < 0) return ret; @@ -388,25 +407,25 @@ static int vorbis_header(AVFormatContext *s, int idx) priv->len[1] = new_len; } } - } else { - int ret; - if (priv->vp) - return AVERROR_INVALIDDATA; + return 1; + } - ret = fixup_vorbis_headers(s, priv, &st->codecpar->extradata); - if (ret < 0) { - st->codecpar->extradata_size = 0; - return ret; - } - st->codecpar->extradata_size = ret; + if (priv->vp) + return AVERROR_INVALIDDATA; - priv->vp = av_vorbis_parse_init(st->codecpar->extradata, st->codecpar->extradata_size); - if (!priv->vp) { - av_freep(&st->codecpar->extradata); - st->codecpar->extradata_size = 0; - return AVERROR_UNKNOWN; - } + ret = fixup_vorbis_headers(s, priv, &st->codecpar->extradata); + if (ret < 0) { + st->codecpar->extradata_size = 0; + return ret; + } + st->codecpar->extradata_size = ret; + + priv->vp = av_vorbis_parse_init(st->codecpar->extradata, st->codecpar->extradata_size); + if (!priv->vp) { + av_freep(&st->codecpar->extradata); + st->codecpar->extradata_size = 0; + return AVERROR_UNKNOWN; } return 1; @@ -418,6 +437,8 @@ static int vorbis_packet(AVFormatContext *s, int idx) struct ogg_stream *os = ogg->streams + idx; struct oggvorbis_private *priv = os->private; int duration, flags = 0; + int skip_packet = 0; + int ret; if (!priv->vp) return AVERROR_INVALIDDATA; @@ -480,10 +501,35 @@ static int vorbis_packet(AVFormatContext *s, int idx) if (duration < 0) { os->pflags |= AV_PKT_FLAG_CORRUPT; return 0; - } else if (flags & VORBIS_FLAG_COMMENT) { - vorbis_update_metadata(s, idx); + } + + if (flags & VORBIS_FLAG_HEADER) { + ret = vorbis_parse_header(s, s->streams[idx], os->buf + os->pstart, os->psize); + if (ret < 0) + return ret; + + skip_packet = 1; + } + + if (flags & VORBIS_FLAG_COMMENT) { + ret = vorbis_update_metadata(s, idx); + if (ret < 0) + return ret; + flags = 0; + skip_packet = 1; } + + if (flags & VORBIS_FLAG_SETUP) { + ret = av_reallocp(&os->new_extradata, os->psize); + if (ret < 0) + return ret; + + memcpy(os->new_extradata, os->buf + os->pstart, os->psize); + os->new_extradata_size = os->psize; + skip_packet = 1; + } + os->pduration = duration; } @@ -505,7 +551,7 @@ static int vorbis_packet(AVFormatContext *s, int idx) priv->final_duration += os->pduration; } - return 0; + return skip_packet; } const struct ogg_codec ff_vorbis_codec = { diff --git a/tests/ref/fate/ogg-vorbis-chained-meta.txt b/tests/ref/fate/ogg-vorbis-chained-meta.txt index b7a97c90e2..1206f86c1f 100644 --- a/tests/ref/fate/ogg-vorbis-chained-meta.txt +++ b/tests/ref/fate/ogg-vorbis-chained-meta.txt @@ -6,10 +6,7 @@ Stream ID: 0, frame PTS: 128, metadata: N/A Stream ID: 0, packet PTS: 704, packet DTS: 704 Stream ID: 0, frame PTS: 704, metadata: N/A Stream ID: 0, packet PTS: 0, packet DTS: 0 -Stream ID: 0, packet PTS: 0, packet DTS: 0 Stream ID: 0, new metadata: encoder=Lavc61.19.100 libvorbis:title=Second Stream -Stream ID: 0, packet PTS: 0, packet DTS: 0 -Stream ID: 0, packet PTS: 0, packet DTS: 0 Stream ID: 0, frame PTS: 0, metadata: N/A Stream ID: 0, packet PTS: 128, packet DTS: 128 Stream ID: 0, frame PTS: 128, metadata: N/A -- 2.39.5 (Apple Git-154) _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".