libavformat/oggparsetheora.c
1ed923ea
 /**
d4c12b8b
  *    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
  *    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.
  **/
1ed923ea
 
 #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
 
d4c12b8b
 typedef struct TheoraParams {
1ed923ea
     int gpshift;
     int gpmask;
e3b07e1a
     unsigned version;
d4c12b8b
 } TheoraParams;
1ed923ea
 
d4c12b8b
 static int theora_header(AVFormatContext *s, int idx)
1ed923ea
 {
d4c12b8b
     struct ogg *ogg       = s->priv_data;
77be08ee
     struct ogg_stream *os = ogg->streams + idx;
d4c12b8b
     AVStream *st          = s->streams[idx];
     TheoraParams *thp     = os->private;
     int cds               = st->codec->extradata_size + os->psize + 2;
     int err;
1ed923ea
     uint8_t *cdp;
 
d4c12b8b
     if (!(os->buf[os->pstart] & 0x80))
1ed923ea
         return 0;
 
d4c12b8b
     if (!thp) {
bb270c08
         thp = av_mallocz(sizeof(*thp));
4f2d8968
         if (!thp)
             return AVERROR(ENOMEM);
bb270c08
         os->private = thp;
1ed923ea
     }
 
0336dea2
     switch (os->buf[os->pstart]) {
     case 0x80: {
1ed923ea
         GetBitContext gb;
1bb3990b
         AVRational timebase;
571fa531
 
d4c12b8b
         init_get_bits(&gb, os->buf + os->pstart, os->psize * 8);
1ed923ea
 
d4c12b8b
         /* 0x80"theora" */
         skip_bits_long(&gb, 7 * 8);
571fa531
 
e3b07e1a
         thp->version = get_bits_long(&gb, 24);
d4c12b8b
         if (thp->version < 0x030100) {
571fa531
             av_log(s, AV_LOG_ERROR,
d4c12b8b
                    "Too old or unsupported Theora (%x)\n", thp->version);
5e5fb218
             return AVERROR(ENOSYS);
571fa531
         }
5b558574
 
ce6949d3
         st->codec->width  = get_bits(&gb, 16) << 4;
         st->codec->height = get_bits(&gb, 16) << 4;
1ed923ea
 
e3b07e1a
         if (thp->version >= 0x030400)
c0f716b8
             skip_bits(&gb, 100);
 
e3b07e1a
         if (thp->version >= 0x030200) {
ce6949d3
             int width  = get_bits_long(&gb, 24);
             int height = get_bits_long(&gb, 24);
d4c12b8b
             if (width  <= st->codec->width  && width  > st->codec->width  - 16 &&
ce6949d3
                 height <= st->codec->height && height > st->codec->height - 16) {
                 st->codec->width  = width;
                 st->codec->height = height;
             }
c0f716b8
 
             skip_bits(&gb, 16);
277e3e53
         }
d4c12b8b
 
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);
d4c12b8b
         thp->gpmask  = (1 << thp->gpshift) - 1;
1ed923ea
 
72415b2a
         st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
d4c12b8b
         st->codec->codec_id   = AV_CODEC_ID_THEORA;
         st->need_parsing      = AVSTREAM_PARSE_HEADERS;
0336dea2
     }
     break;
     case 0x81:
db68ef89
         ff_vorbis_stream_comment(s, st, os->buf + os->pstart + 7, os->psize - 7);
0336dea2
     case 0x82:
         if (!thp->version)
5e5fb218
             return AVERROR_INVALIDDATA;
0336dea2
         break;
     default:
d9d56712
         av_log(s, AV_LOG_ERROR, "Unknown header type %X\n", os->buf[os->pstart]);
5e5fb218
         return AVERROR_INVALIDDATA;
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
     }
45115315
     memset(st->codec->extradata + cds, 0, FF_INPUT_BUFFER_PADDING_SIZE);
 
d4c12b8b
     cdp    = st->codec->extradata + st->codec->extradata_size;
1ed923ea
     *cdp++ = os->psize >> 8;
     *cdp++ = os->psize & 0xff;
d4c12b8b
     memcpy(cdp, os->buf + os->pstart, os->psize);
01f4895c
     st->codec->extradata_size = cds;
1ed923ea
 
5b558574
     return 1;
1ed923ea
 }
 
d4c12b8b
 static uint64_t theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp,
                                int64_t *dts)
1ed923ea
 {
d4c12b8b
     struct ogg *ogg       = ctx->priv_data;
77be08ee
     struct ogg_stream *os = ogg->streams + idx;
d4c12b8b
     TheoraParams *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++;
 
d4c12b8b
     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 = {
d4c12b8b
     .magic     = "\200theora",
1ed923ea
     .magicsize = 7,
d4c12b8b
     .header    = theora_header,
70737b83
     .packet    = theora_packet,
d4c12b8b
     .gptopts   = theora_gptopts,
7751e469
     .nb_header = 3,
1ed923ea
 };