X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Foggparsevorbis.c;h=396a3e3ea758bdcbf8c004c38a06f5b974bf97bd;hb=41540b36a19d326e778268e910aff4217b20eb97;hp=8a406976b56fec617023a06560796e19de69cb81;hpb=1fa395e471d563166f3fe3071fce8148e27679a8;p=ffmpeg diff --git a/libavformat/oggparsevorbis.c b/libavformat/oggparsevorbis.c index 8a406976b56..396a3e3ea75 100644 --- a/libavformat/oggparsevorbis.c +++ b/libavformat/oggparsevorbis.c @@ -28,6 +28,7 @@ #include "libavutil/dict.h" #include "libavcodec/get_bits.h" #include "libavcodec/bytestream.h" +#include "libavcodec/vorbis_parser.h" #include "avformat.h" #include "internal.h" #include "oggdec.h" @@ -162,6 +163,9 @@ ff_vorbis_comment(AVFormatContext * as, AVDictionary **m, const uint8_t *buf, in struct oggvorbis_private { unsigned int len[3]; unsigned char *packet[3]; + VorbisParseContext vp; + int64_t final_pts; + int final_duration; }; @@ -250,11 +254,11 @@ vorbis_header (AVFormatContext * s, int idx) return -1; st->codec->codec_type = AVMEDIA_TYPE_AUDIO; - st->codec->codec_id = CODEC_ID_VORBIS; + st->codec->codec_id = AV_CODEC_ID_VORBIS; if (srate > 0) { st->codec->sample_rate = srate; - av_set_pts_info(st, 64, 1, srate); + avpriv_set_pts_info(st, 64, 1, srate); } } else if (os->buf[os->pstart] == 3) { if (os->psize > 8 && @@ -268,15 +272,92 @@ vorbis_header (AVFormatContext * s, int idx) } } } else { + int ret; st->codec->extradata_size = fixup_vorbis_headers(s, priv, &st->codec->extradata); + if ((ret = avpriv_vorbis_parse_extradata(st->codec, &priv->vp))) { + av_freep(&st->codec->extradata); + st->codec->extradata_size = 0; + return ret; + } } return 1; } +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; + + /* first packet handling + 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; + 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++) { + 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; + priv->final_pts = AV_NOPTS_VALUE; + avpriv_vorbis_parse_reset(&priv->vp); + } + + /* parse packet duration */ + if (os->psize > 0) { + duration = avpriv_vorbis_parse_frame(&priv->vp, os->buf + os->pstart, 1); + if (duration <= 0) { + os->pflags |= AV_PKT_FLAG_CORRUPT; + return 0; + } + os->pduration = duration; + } + + /* final packet handling + here we save the pts of the first packet in the final page, sum up all + packet durations in the final page except for the last one, and compare + to the page granule to find the duration of the final packet */ + if (os->flags & OGG_FLAG_EOS) { + if (os->lastpts != AV_NOPTS_VALUE) { + priv->final_pts = os->lastpts; + priv->final_duration = 0; + } + if (os->segp == os->nsegs) + os->pduration = os->granule - priv->final_pts - priv->final_duration; + priv->final_duration += os->pduration; + } + + return 0; +} + const struct ogg_codec ff_vorbis_codec = { .magic = "\001vorbis", .magicsize = 7, - .header = vorbis_header + .header = vorbis_header, + .packet = vorbis_packet, + .nb_header = 3, };