avio: add a destructor for AVIOContext
[ffmpeg.git] / libavformat / oggparsetheora.c
1 /**
2  *    Copyright (C) 2005  Matthieu CASTET, Alex Beregszaszi
3  *
4  *    Permission is hereby granted, free of charge, to any person
5  *    obtaining a copy of this software and associated documentation
6  *    files (the "Software"), to deal in the Software without
7  *    restriction, including without limitation the rights to use, copy,
8  *    modify, merge, publish, distribute, sublicense, and/or sell copies
9  *    of the Software, and to permit persons to whom the Software is
10  *    furnished to do so, subject to the following conditions:
11  *
12  *    The above copyright notice and this permission notice shall be
13  *    included in all copies or substantial portions of the Software.
14  *
15  *    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  *    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  *    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  *    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19  *    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20  *    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  *    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  *    DEALINGS IN THE SOFTWARE.
23  **/
24
25 #include <stdlib.h>
26
27 #include "libavutil/bswap.h"
28
29 #include "libavcodec/bitstream.h"
30
31 #include "avformat.h"
32 #include "internal.h"
33 #include "oggdec.h"
34
35 typedef struct TheoraParams {
36     int gpshift;
37     int gpmask;
38     unsigned version;
39 } TheoraParams;
40
41 static int theora_header(AVFormatContext *s, int idx)
42 {
43     struct ogg *ogg       = s->priv_data;
44     struct ogg_stream *os = ogg->streams + idx;
45     AVStream *st          = s->streams[idx];
46     TheoraParams *thp     = os->private;
47     int cds               = st->codecpar->extradata_size + os->psize + 2;
48     int err;
49     uint8_t *cdp;
50
51     if (!(os->buf[os->pstart] & 0x80))
52         return 0;
53
54     if (!thp) {
55         thp = av_mallocz(sizeof(*thp));
56         if (!thp)
57             return AVERROR(ENOMEM);
58         os->private = thp;
59     }
60
61     switch (os->buf[os->pstart]) {
62     case 0x80: {
63         BitstreamContext bc;
64         AVRational timebase;
65
66         bitstream_init8(&bc, os->buf + os->pstart, os->psize);
67
68         /* 0x80"theora" */
69         bitstream_skip(&bc, 7 * 8);
70
71         thp->version = bitstream_read(&bc, 24);
72         if (thp->version < 0x030100) {
73             av_log(s, AV_LOG_ERROR,
74                    "Too old or unsupported Theora (%x)\n", thp->version);
75             return AVERROR(ENOSYS);
76         }
77
78         st->codecpar->width  = bitstream_read(&bc, 16) << 4;
79         st->codecpar->height = bitstream_read(&bc, 16) << 4;
80
81         if (thp->version >= 0x030400)
82             bitstream_skip(&bc, 100);
83
84         if (thp->version >= 0x030200) {
85             int width  = bitstream_read(&bc, 24);
86             int height = bitstream_read(&bc, 24);
87             if (width  <= st->codecpar->width  && width  > st->codecpar->width  - 16 &&
88                 height <= st->codecpar->height && height > st->codecpar->height - 16) {
89                 st->codecpar->width  = width;
90                 st->codecpar->height = height;
91             }
92
93             bitstream_skip(&bc, 16);
94         }
95
96         timebase.den = bitstream_read(&bc, 32);
97         timebase.num = bitstream_read(&bc, 32);
98         if (!(timebase.num > 0 && timebase.den > 0)) {
99             av_log(s, AV_LOG_WARNING, "Invalid time base in theora stream, assuming 25 FPS\n");
100             timebase.num = 1;
101             timebase.den = 25;
102         }
103         avpriv_set_pts_info(st, 64, timebase.num, timebase.den);
104
105         st->sample_aspect_ratio.num = bitstream_read(&bc, 24);
106         st->sample_aspect_ratio.den = bitstream_read(&bc, 24);
107
108         if (thp->version >= 0x030200)
109             bitstream_skip(&bc, 38);
110         if (thp->version >= 0x304000)
111             bitstream_skip(&bc, 2);
112
113         thp->gpshift = bitstream_read(&bc, 5);
114         thp->gpmask  = (1 << thp->gpshift) - 1;
115
116         st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
117         st->codecpar->codec_id   = AV_CODEC_ID_THEORA;
118         st->need_parsing      = AVSTREAM_PARSE_HEADERS;
119     }
120     break;
121     case 0x81:
122         ff_vorbis_stream_comment(s, st, os->buf + os->pstart + 7, os->psize - 7);
123     case 0x82:
124         if (!thp->version)
125             return AVERROR_INVALIDDATA;
126         break;
127     default:
128         return AVERROR_INVALIDDATA;
129     }
130
131     if ((err = av_reallocp(&st->codecpar->extradata,
132                            cds + AV_INPUT_BUFFER_PADDING_SIZE)) < 0) {
133         st->codecpar->extradata_size = 0;
134         return err;
135     }
136     cdp    = st->codecpar->extradata + st->codecpar->extradata_size;
137     *cdp++ = os->psize >> 8;
138     *cdp++ = os->psize & 0xff;
139     memcpy(cdp, os->buf + os->pstart, os->psize);
140     st->codecpar->extradata_size = cds;
141
142     return 1;
143 }
144
145 static uint64_t theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp,
146                                int64_t *dts)
147 {
148     struct ogg *ogg       = ctx->priv_data;
149     struct ogg_stream *os = ogg->streams + idx;
150     TheoraParams *thp     = os->private;
151     uint64_t iframe, pframe;
152
153     if (!thp)
154         return AV_NOPTS_VALUE;
155
156     iframe = gp >> thp->gpshift;
157     pframe = gp & thp->gpmask;
158
159     if (thp->version < 0x030201)
160         iframe++;
161
162     if (!pframe)
163         os->pflags |= AV_PKT_FLAG_KEY;
164
165     if (dts)
166         *dts = iframe + pframe;
167
168     return iframe + pframe;
169 }
170
171 const struct ogg_codec ff_theora_codec = {
172     .magic     = "\200theora",
173     .magicsize = 7,
174     .header    = theora_header,
175     .gptopts   = theora_gptopts,
176     .nb_header = 3,
177 };