X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Foggparsetheora.c;h=d1559f4632da8ada7972b1a96ebedba5a26297ca;hb=6c071a2b389578b0607b4d4356520a43fac4b3bc;hp=f1820e8b637d376f5119b5881c98e94d23669aef;hpb=bb270c0896b39e1ae9277355e3c120ed3feb64a3;p=ffmpeg diff --git a/libavformat/oggparsetheora.c b/libavformat/oggparsetheora.c index f1820e8b637..d1559f4632d 100644 --- a/libavformat/oggparsetheora.c +++ b/libavformat/oggparsetheora.c @@ -1,5 +1,5 @@ /** - Copyright (C) 2005 Matthieu CASTET + Copyright (C) 2005 Matthieu CASTET, Alex Beregszaszi Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation @@ -23,23 +23,25 @@ **/ #include +#include "libavutil/bswap.h" +#include "libavcodec/get_bits.h" #include "avformat.h" -#include "bitstream.h" -#include "bswap.h" -#include "ogg2.h" +#include "internal.h" +#include "oggdec.h" -typedef struct theora_params { +struct theora_params { int gpshift; int gpmask; -} theora_params_t; + unsigned version; +}; static int theora_header (AVFormatContext * s, int idx) { - ogg_t *ogg = s->priv_data; - ogg_stream_t *os = ogg->streams + idx; + struct ogg *ogg = s->priv_data; + struct ogg_stream *os = ogg->streams + idx; AVStream *st = s->streams[idx]; - theora_params_t *thp = os->private; + struct theora_params *thp = os->private; int cds = st->codec->extradata_size + os->psize + 2; uint8_t *cdp; @@ -53,37 +55,67 @@ theora_header (AVFormatContext * s, int idx) if (os->buf[os->pstart] == 0x80) { GetBitContext gb; - init_get_bits(&gb, os->buf + os->pstart, os->psize*8); - - skip_bits(&gb, 7*8); /* 0x80"theora" */ - if(get_bits(&gb, 8) != 3) /* major version */ - return -1; - if(get_bits(&gb, 8) != 2) /* minor version */ - return -1; - skip_bits(&gb, 8); /* revision */ + int width, height; + AVRational timebase; - st->codec->width = get_bits(&gb, 16) << 4; - st->codec->height = get_bits(&gb, 16) << 4; + init_get_bits(&gb, os->buf + os->pstart, os->psize*8); - skip_bits(&gb, 64); - st->codec->time_base.den = get_bits(&gb, 32); - st->codec->time_base.num = get_bits(&gb, 32); + skip_bits_long(&gb, 7*8); /* 0x80"theora" */ - st->codec->sample_aspect_ratio.num = get_bits(&gb, 24); - st->codec->sample_aspect_ratio.den = get_bits(&gb, 24); + thp->version = get_bits_long(&gb, 24); + if (thp->version < 0x030100) + { + av_log(s, AV_LOG_ERROR, + "Too old or unsupported Theora (%x)\n", thp->version); + return -1; + } + + width = get_bits(&gb, 16) << 4; + height = get_bits(&gb, 16) << 4; + avcodec_set_dimensions(st->codec, width, height); + + if (thp->version >= 0x030400) + skip_bits(&gb, 100); + + if (thp->version >= 0x030200) { + width = get_bits_long(&gb, 24); + height = get_bits_long(&gb, 24); + if ( width <= st->codec->width && width > st->codec->width-16 + && height <= st->codec->height && height > st->codec->height-16) + avcodec_set_dimensions(st->codec, width, height); + + skip_bits(&gb, 16); + } + timebase.den = get_bits_long(&gb, 32); + timebase.num = get_bits_long(&gb, 32); + if (!(timebase.num > 0 && timebase.den > 0)) { + av_log(s, AV_LOG_WARNING, "Invalid time base in theora stream, assuming 25 FPS\n"); + timebase.num = 1; + timebase.den = 25; + } + avpriv_set_pts_info(st, 64, timebase.num, timebase.den); + + st->sample_aspect_ratio.num = get_bits_long(&gb, 24); + st->sample_aspect_ratio.den = get_bits_long(&gb, 24); + + if (thp->version >= 0x030200) + skip_bits_long(&gb, 38); + if (thp->version >= 0x304000) + skip_bits(&gb, 2); - skip_bits(&gb, 38); thp->gpshift = get_bits(&gb, 5); thp->gpmask = (1 << thp->gpshift) - 1; - st->codec->codec_type = CODEC_TYPE_VIDEO; + st->codec->codec_type = AVMEDIA_TYPE_VIDEO; st->codec->codec_id = CODEC_ID_THEORA; + st->need_parsing = AVSTREAM_PARSE_HEADERS; } else if (os->buf[os->pstart] == 0x83) { - vorbis_comment (s, os->buf + os->pstart + 7, os->psize - 8); + ff_vorbis_comment (s, &st->metadata, os->buf + os->pstart + 7, os->psize - 8); } - st->codec->extradata = av_realloc (st->codec->extradata, cds); + st->codec->extradata = av_realloc (st->codec->extradata, + cds + FF_INPUT_BUFFER_PADDING_SIZE); cdp = st->codec->extradata + st->codec->extradata_size; *cdp++ = os->psize >> 8; *cdp++ = os->psize & 0xff; @@ -94,20 +126,27 @@ theora_header (AVFormatContext * s, int idx) } static uint64_t -theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp) +theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp, int64_t *dts) { - AVStream *st = ctx->streams[idx]; - ogg_t *ogg = ctx->priv_data; - ogg_stream_t *os = ogg->streams + idx; - theora_params_t *thp = os->private; + struct ogg *ogg = ctx->priv_data; + struct ogg_stream *os = ogg->streams + idx; + struct theora_params *thp = os->private; uint64_t iframe = gp >> thp->gpshift; uint64_t pframe = gp & thp->gpmask; - return (iframe + pframe) * AV_TIME_BASE * st->codec->time_base.num / - st->codec->time_base.den; + if (thp->version < 0x030201) + iframe++; + + if(!pframe) + os->pflags |= AV_PKT_FLAG_KEY; + + if (dts) + *dts = iframe + pframe; + + return iframe + pframe; } -ogg_codec_t theora_codec = { +const struct ogg_codec ff_theora_codec = { .magic = "\200theora", .magicsize = 7, .header = theora_header,