libavformat/oggparsetheora.c
1ed923ea
 /**
571fa531
       Copyright (C) 2005  Matthieu CASTET, Alex Beregszaszi
1ed923ea
 
       Permission is hereby granted, free of charge, to any person
       obtaining a copy of this software and associated documentation
       files (the "Software"), to deal in the Software without
       restriction, including without limitation the rights to use, copy,
       modify, merge, publish, distribute, sublicense, and/or sell copies
       of the Software, and to permit persons to whom the Software is
       furnished to do so, subject to the following conditions:
 
       The above copyright notice and this permission notice shall be
       included in all copies or substantial portions of the Software.
 
       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
       NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
       WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
       DEALINGS IN THE SOFTWARE.
 **/
 
 #include <stdlib.h>
245976da
 #include "libavutil/bswap.h"
9106a698
 #include "libavcodec/get_bits.h"
1ed923ea
 #include "avformat.h"
c3f9ebf7
 #include "internal.h"
a0ddef24
 #include "oggdec.h"
1ed923ea
 
77be08ee
 struct theora_params {
1ed923ea
     int gpshift;
     int gpmask;
e3b07e1a
     unsigned version;
77be08ee
 };
1ed923ea
 
 static int
 theora_header (AVFormatContext * s, int idx)
 {
77be08ee
     struct ogg *ogg = s->priv_data;
     struct ogg_stream *os = ogg->streams + idx;
1ed923ea
     AVStream *st = s->streams[idx];
77be08ee
     struct theora_params *thp = os->private;
01f4895c
     int cds = st->codec->extradata_size + os->psize + 2;
1ed923ea
     uint8_t *cdp;
 
5b558574
     if(!(os->buf[os->pstart] & 0x80))
1ed923ea
         return 0;
 
     if(!thp){
bb270c08
         thp = av_mallocz(sizeof(*thp));
         os->private = thp;
1ed923ea
     }
 
     if (os->buf[os->pstart] == 0x80) {
         GetBitContext gb;
c0f716b8
         int width, height;
571fa531
 
1ed923ea
         init_get_bits(&gb, os->buf + os->pstart, os->psize*8);
 
0a8dedc9
         skip_bits_long(&gb, 7*8); /* 0x80"theora" */
571fa531
 
e3b07e1a
         thp->version = get_bits_long(&gb, 24);
         if (thp->version < 0x030100)
571fa531
         {
             av_log(s, AV_LOG_ERROR,
e3b07e1a
                 "Too old or unsupported Theora (%x)\n", thp->version);
5b558574
             return -1;
571fa531
         }
5b558574
 
c0f716b8
         width  = get_bits(&gb, 16) << 4;
         height = get_bits(&gb, 16) << 4;
         avcodec_set_dimensions(st->codec, width, height);
1ed923ea
 
e3b07e1a
         if (thp->version >= 0x030400)
c0f716b8
             skip_bits(&gb, 100);
 
e3b07e1a
         if (thp->version >= 0x030200) {
a0ce2d1b
             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);
c0f716b8
 
             skip_bits(&gb, 16);
277e3e53
         }
b997b67c
         st->codec->time_base.den = get_bits_long(&gb, 32);
         st->codec->time_base.num = get_bits_long(&gb, 32);
11d058b7
         if (!(st->codec->time_base.num > 0 && st->codec->time_base.den > 0)) {
             av_log(s, AV_LOG_WARNING, "Invalid time base in theora stream, assuming 25 FPS\n");
             st->codec->time_base.num = 1;
             st->codec->time_base.den = 25;
         }
c3f9ebf7
         avpriv_set_pts_info(st, 64, st->codec->time_base.num, st->codec->time_base.den);
115329f1
 
59729451
         st->sample_aspect_ratio.num = get_bits_long(&gb, 24);
         st->sample_aspect_ratio.den = get_bits_long(&gb, 24);
1ed923ea
 
e3b07e1a
         if (thp->version >= 0x030200)
0a8dedc9
             skip_bits_long(&gb, 38);
e3b07e1a
         if (thp->version >= 0x304000)
571fa531
             skip_bits(&gb, 2);
 
1ed923ea
         thp->gpshift = get_bits(&gb, 5);
bb270c08
         thp->gpmask = (1 << thp->gpshift) - 1;
1ed923ea
 
72415b2a
         st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
01f4895c
         st->codec->codec_id = CODEC_ID_THEORA;
8b6bdb6c
         st->need_parsing = AVSTREAM_PARSE_HEADERS;
1ed923ea
 
     } else if (os->buf[os->pstart] == 0x83) {
b53cde48
         ff_vorbis_comment (s, &st->metadata, os->buf + os->pstart + 7, os->psize - 8);
1ed923ea
     }
 
12d7c079
     st->codec->extradata = av_realloc (st->codec->extradata,
                                        cds + FF_INPUT_BUFFER_PADDING_SIZE);
01f4895c
     cdp = st->codec->extradata + st->codec->extradata_size;
1ed923ea
     *cdp++ = os->psize >> 8;
     *cdp++ = os->psize & 0xff;
     memcpy (cdp, os->buf + os->pstart, os->psize);
01f4895c
     st->codec->extradata_size = cds;
1ed923ea
 
5b558574
     return 1;
1ed923ea
 }
 
 static uint64_t
2d4970d8
 theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp, int64_t *dts)
1ed923ea
 {
77be08ee
     struct ogg *ogg = ctx->priv_data;
     struct ogg_stream *os = ogg->streams + idx;
     struct theora_params *thp = os->private;
1ed923ea
     uint64_t iframe = gp >> thp->gpshift;
     uint64_t pframe = gp & thp->gpmask;
 
e3b07e1a
     if (thp->version < 0x030201)
         iframe++;
 
e1a794b2
     if(!pframe)
cc947f04
         os->pflags |= AV_PKT_FLAG_KEY;
e1a794b2
 
2d4970d8
     if (dts)
         *dts = iframe + pframe;
 
3644cb8f
     return iframe + pframe;
1ed923ea
 }
 
77be08ee
 const struct ogg_codec ff_theora_codec = {
1ed923ea
     .magic = "\200theora",
     .magicsize = 7,
     .header = theora_header,
     .gptopts = theora_gptopts
 };