00001
00025 #include <stdlib.h>
00026 #include "libavutil/bswap.h"
00027 #include "libavcodec/get_bits.h"
00028 #include "avformat.h"
00029 #include "internal.h"
00030 #include "oggdec.h"
00031
00032 struct theora_params {
00033 int gpshift;
00034 int gpmask;
00035 unsigned version;
00036 };
00037
00038 static int
00039 theora_header (AVFormatContext * s, int idx)
00040 {
00041 struct ogg *ogg = s->priv_data;
00042 struct ogg_stream *os = ogg->streams + idx;
00043 AVStream *st = s->streams[idx];
00044 struct theora_params *thp = os->private;
00045 int cds = st->codec->extradata_size + os->psize + 2;
00046 uint8_t *cdp;
00047
00048 if(!(os->buf[os->pstart] & 0x80))
00049 return 0;
00050
00051 if(!thp){
00052 thp = av_mallocz(sizeof(*thp));
00053 os->private = thp;
00054 }
00055
00056 switch (os->buf[os->pstart]) {
00057 case 0x80: {
00058 GetBitContext gb;
00059 int width, height;
00060 AVRational timebase;
00061
00062 init_get_bits(&gb, os->buf + os->pstart, os->psize*8);
00063
00064 skip_bits_long(&gb, 7*8);
00065
00066 thp->version = get_bits_long(&gb, 24);
00067 if (thp->version < 0x030100)
00068 {
00069 av_log(s, AV_LOG_ERROR,
00070 "Too old or unsupported Theora (%x)\n", thp->version);
00071 return -1;
00072 }
00073
00074 width = get_bits(&gb, 16) << 4;
00075 height = get_bits(&gb, 16) << 4;
00076 avcodec_set_dimensions(st->codec, width, height);
00077
00078 if (thp->version >= 0x030400)
00079 skip_bits(&gb, 100);
00080
00081 if (thp->version >= 0x030200) {
00082 width = get_bits_long(&gb, 24);
00083 height = get_bits_long(&gb, 24);
00084 if ( width <= st->codec->width && width > st->codec->width-16
00085 && height <= st->codec->height && height > st->codec->height-16)
00086 avcodec_set_dimensions(st->codec, width, height);
00087
00088 skip_bits(&gb, 16);
00089 }
00090 timebase.den = get_bits_long(&gb, 32);
00091 timebase.num = get_bits_long(&gb, 32);
00092 if (!(timebase.num > 0 && timebase.den > 0)) {
00093 av_log(s, AV_LOG_WARNING, "Invalid time base in theora stream, assuming 25 FPS\n");
00094 timebase.num = 1;
00095 timebase.den = 25;
00096 }
00097 avpriv_set_pts_info(st, 64, timebase.num, timebase.den);
00098
00099 st->sample_aspect_ratio.num = get_bits_long(&gb, 24);
00100 st->sample_aspect_ratio.den = get_bits_long(&gb, 24);
00101
00102 if (thp->version >= 0x030200)
00103 skip_bits_long(&gb, 38);
00104 if (thp->version >= 0x304000)
00105 skip_bits(&gb, 2);
00106
00107 thp->gpshift = get_bits(&gb, 5);
00108 thp->gpmask = (1 << thp->gpshift) - 1;
00109
00110 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00111 st->codec->codec_id = AV_CODEC_ID_THEORA;
00112 st->need_parsing = AVSTREAM_PARSE_HEADERS;
00113 }
00114 break;
00115 case 0x81:
00116 ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, os->psize - 8);
00117 case 0x82:
00118 if (!thp->version)
00119 return -1;
00120 break;
00121 default:
00122 av_log(s, AV_LOG_ERROR, "Unknown header type %X\n", os->buf[os->pstart]);
00123 return -1;
00124 }
00125
00126 st->codec->extradata = av_realloc (st->codec->extradata,
00127 cds + FF_INPUT_BUFFER_PADDING_SIZE);
00128 cdp = st->codec->extradata + st->codec->extradata_size;
00129 *cdp++ = os->psize >> 8;
00130 *cdp++ = os->psize & 0xff;
00131 memcpy (cdp, os->buf + os->pstart, os->psize);
00132 st->codec->extradata_size = cds;
00133
00134 return 1;
00135 }
00136
00137 static uint64_t
00138 theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp, int64_t *dts)
00139 {
00140 struct ogg *ogg = ctx->priv_data;
00141 struct ogg_stream *os = ogg->streams + idx;
00142 struct theora_params *thp = os->private;
00143 uint64_t iframe, pframe;
00144
00145 if (!thp)
00146 return AV_NOPTS_VALUE;
00147
00148 iframe = gp >> thp->gpshift;
00149 pframe = gp & thp->gpmask;
00150
00151 if (thp->version < 0x030201)
00152 iframe++;
00153
00154 if(!pframe)
00155 os->pflags |= AV_PKT_FLAG_KEY;
00156
00157 if (dts)
00158 *dts = iframe + pframe;
00159
00160 return iframe + pframe;
00161 }
00162
00163 static int theora_packet(AVFormatContext *s, int idx)
00164 {
00165 struct ogg *ogg = s->priv_data;
00166 struct ogg_stream *os = ogg->streams + idx;
00167 int duration;
00168
00169
00170
00171
00172
00173
00174 if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) {
00175 int seg;
00176
00177 duration = 1;
00178 for (seg = os->segp; seg < os->nsegs; seg++) {
00179 if (os->segments[seg] < 255)
00180 duration ++;
00181 }
00182
00183 os->lastpts = os->lastdts = theora_gptopts(s, idx, os->granule, NULL) - duration;
00184 if(s->streams[idx]->start_time == AV_NOPTS_VALUE) {
00185 s->streams[idx]->start_time = os->lastpts;
00186 if (s->streams[idx]->duration)
00187 s->streams[idx]->duration -= s->streams[idx]->start_time;
00188 }
00189 }
00190
00191
00192 if (os->psize > 0) {
00193 os->pduration = 1;
00194 }
00195
00196 return 0;
00197 }
00198
00199 const struct ogg_codec ff_theora_codec = {
00200 .magic = "\200theora",
00201 .magicsize = 7,
00202 .header = theora_header,
00203 .packet = theora_packet,
00204 .gptopts = theora_gptopts,
00205 .nb_header = 3,
00206 };