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;
5626f994
     int cds = st->codec->extradata_size + os->psize + 2, err;
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
     }
 
0336dea2
     switch (os->buf[os->pstart]) {
     case 0x80: {
1ed923ea
         GetBitContext gb;
c0f716b8
         int width, height;
1bb3990b
         AVRational timebase;
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
         }
1bb3990b
         timebase.den = get_bits_long(&gb, 32);
         timebase.num = get_bits_long(&gb, 32);
         if (!(timebase.num > 0 && timebase.den > 0)) {
11d058b7
             av_log(s, AV_LOG_WARNING, "Invalid time base in theora stream, assuming 25 FPS\n");
1bb3990b
             timebase.num = 1;
             timebase.den = 25;
11d058b7
         }
1bb3990b
         avpriv_set_pts_info(st, 64, timebase.num, timebase.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;
36ef5369
         st->codec->codec_id = AV_CODEC_ID_THEORA;
8b6bdb6c
         st->need_parsing = AVSTREAM_PARSE_HEADERS;
0336dea2
     }
     break;
     case 0x81:
db4bb4c9
         ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, os->psize - 7);
0336dea2
     case 0x82:
         if (!thp->version)
             return -1;
         break;
     default:
d9d56712
         av_log(s, AV_LOG_ERROR, "Unknown header type %X\n", os->buf[os->pstart]);
0336dea2
         return -1;
1ed923ea
     }
 
5626f994
     if ((err = av_reallocp(&st->codec->extradata,
d872fb0f
                            cds + FF_INPUT_BUFFER_PADDING_SIZE)) < 0) {
         st->codec->extradata_size = 0;
5626f994
         return err;
d872fb0f
     }
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;
f927c5b7
     uint64_t iframe, pframe;
 
     if (!thp)
         return AV_NOPTS_VALUE;
 
     iframe = gp >> thp->gpshift;
     pframe = gp & thp->gpmask;
1ed923ea
 
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
 }
 
231d32c8
 static int theora_packet(AVFormatContext *s, int idx)
 {
     struct ogg *ogg = s->priv_data;
     struct ogg_stream *os = ogg->streams + idx;
     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 */
 
b18c9f1e
     if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) {
231d32c8
         int seg;
b18c9f1e
 
         duration = 1;
         for (seg = os->segp; seg < os->nsegs; seg++) {
             if (os->segments[seg] < 255)
                 duration ++;
231d32c8
         }
b18c9f1e
 
231d32c8
         os->lastpts = os->lastdts   = theora_gptopts(s, idx, os->granule, NULL) - duration;
b18c9f1e
         if(s->streams[idx]->start_time == AV_NOPTS_VALUE) {
             s->streams[idx]->start_time = os->lastpts;
             if (s->streams[idx]->duration)
                 s->streams[idx]->duration -= s->streams[idx]->start_time;
         }
231d32c8
     }
 
     /* parse packet duration */
     if (os->psize > 0) {
         os->pduration = 1;
     }
 
     return 0;
 }
 
77be08ee
 const struct ogg_codec ff_theora_codec = {
1ed923ea
     .magic = "\200theora",
     .magicsize = 7,
     .header = theora_header,
231d32c8
     .packet = theora_packet,
7751e469
     .gptopts = theora_gptopts,
     .nb_header = 3,
1ed923ea
 };