theoradec.c 24.6 KB
Newer Older
Benjamin Otte's avatar
Benjamin Otte committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/* GStreamer
 * Copyright (C) 2004 Benjamin Otte <in7y118@public.uni-hamburg.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#include <gst/gst.h>
#include <theora/theora.h>
#include <string.h>
#include <gst/tag/tag.h>

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
29 30
GST_DEBUG_CATEGORY (theoradec_debug);
#define GST_CAT_DEFAULT theoradec_debug
Benjamin Otte's avatar
Benjamin Otte committed
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45

#define GST_TYPE_THEORA_DEC \
  (gst_theora_dec_get_type())
#define GST_THEORA_DEC(obj) \
  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_THEORA_DEC,GstTheoraDec))
#define GST_THEORA_DEC_CLASS(klass) \
  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_THEORA_DEC,GstTheoraDec))
#define GST_IS_THEORA_DEC(obj) \
  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_THEORA_DEC))
#define GST_IS_THEORA_DEC_CLASS(obj) \
  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_THEORA_DEC))

typedef struct _GstTheoraDec GstTheoraDec;
typedef struct _GstTheoraDecClass GstTheoraDecClass;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
46 47 48 49 50 51 52 53 54 55 56 57 58
struct _GstTheoraDec
{
  GstElement element;

  GstPad *sinkpad;
  GstPad *srcpad;

  theora_state state;
  theora_info info;
  theora_comment comment;

  guint packetno;
  guint64 granulepos;
59

60
  gboolean initialized;
61
  gboolean need_keyframe;
62 63
  gint width, height;
  gint offset_x, offset_y;
64 65

  gboolean crop;
Benjamin Otte's avatar
Benjamin Otte committed
66 67
};

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
68 69
struct _GstTheoraDecClass
{
Benjamin Otte's avatar
Benjamin Otte committed
70 71 72
  GstElementClass parent_class;
};

73 74 75 76 77 78 79
#define THEORA_DEF_CROP		TRUE
enum
{
  ARG_0,
  ARG_CROP
};

Benjamin Otte's avatar
Benjamin Otte committed
80 81
static GstElementDetails theora_dec_details = {
  "TheoraDec",
82
  "Codec/Decoder/Video",
Benjamin Otte's avatar
Benjamin Otte committed
83
  "decode raw theora streams to raw YUV video",
84 85
  "Benjamin Otte <in7y118@public.uni-hamburg.de>, "
      "Wim Taymans <wim@fluendo.com>",
Benjamin Otte's avatar
Benjamin Otte committed
86 87 88
};

static GstStaticPadTemplate theora_dec_src_factory =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
89 90 91 92
GST_STATIC_PAD_TEMPLATE ("src",
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("video/x-raw-yuv, "
93 94 95
        "format = (fourcc) I420, "
        "framerate = (double) [0, MAX], "
        "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
96
    );
Benjamin Otte's avatar
Benjamin Otte committed
97 98

static GstStaticPadTemplate theora_dec_sink_factory =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
99 100 101 102 103
GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("video/x-theora")
    );
Benjamin Otte's avatar
Benjamin Otte committed
104 105

GST_BOILERPLATE (GstTheoraDec, gst_theora_dec, GstElement, GST_TYPE_ELEMENT);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
106

107 108 109 110 111
static void theora_dec_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec);
static void theora_dec_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec);

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
112 113 114 115 116
static void theora_dec_chain (GstPad * pad, GstData * data);
static GstElementStateReturn theora_dec_change_state (GstElement * element);
static gboolean theora_dec_src_event (GstPad * pad, GstEvent * event);
static gboolean theora_dec_src_query (GstPad * pad,
    GstQueryType query, GstFormat * format, gint64 * value);
117 118 119 120 121 122 123 124 125
static gboolean theora_dec_src_convert (GstPad * pad,
    GstFormat src_format, gint64 src_value,
    GstFormat * dest_format, gint64 * dest_value);
static gboolean theora_dec_sink_convert (GstPad * pad,
    GstFormat src_format, gint64 src_value,
    GstFormat * dest_format, gint64 * dest_value);
static const GstFormat *theora_get_formats (GstPad * pad);
static const GstEventMask *theora_get_event_masks (GstPad * pad);
static const GstQueryType *theora_get_query_types (GstPad * pad);
Benjamin Otte's avatar
Benjamin Otte committed
126 127 128 129 130 131


static void
gst_theora_dec_base_init (gpointer g_class)
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
132 133

  gst_element_class_add_pad_template (element_class,
Benjamin Otte's avatar
Benjamin Otte committed
134 135 136 137 138 139 140
      gst_static_pad_template_get (&theora_dec_src_factory));
  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&theora_dec_sink_factory));
  gst_element_class_set_details (element_class, &theora_dec_details);
}

static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
141
gst_theora_dec_class_init (GstTheoraDecClass * klass)
Benjamin Otte's avatar
Benjamin Otte committed
142
{
143
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Benjamin Otte's avatar
Benjamin Otte committed
144 145
  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);

146 147 148 149 150 151 152 153
  gobject_class->set_property = theora_dec_set_property;
  gobject_class->get_property = theora_dec_get_property;

  g_object_class_install_property (gobject_class, ARG_CROP,
      g_param_spec_boolean ("crop", "Crop",
          "Crop the image to the visible region", THEORA_DEF_CROP,
          (GParamFlags) G_PARAM_READWRITE));

Benjamin Otte's avatar
Benjamin Otte committed
154
  gstelement_class->change_state = theora_dec_change_state;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
155 156

  GST_DEBUG_CATEGORY_INIT (theoradec_debug, "theoradec", 0, "Theora decoder");
Benjamin Otte's avatar
Benjamin Otte committed
157 158 159
}

static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
160
gst_theora_dec_init (GstTheoraDec * dec)
Benjamin Otte's avatar
Benjamin Otte committed
161
{
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
162 163 164
  dec->sinkpad =
      gst_pad_new_from_template (gst_static_pad_template_get
      (&theora_dec_sink_factory), "sink");
165 166
  gst_pad_set_formats_function (dec->sinkpad, theora_get_formats);
  gst_pad_set_convert_function (dec->sinkpad, theora_dec_sink_convert);
Benjamin Otte's avatar
Benjamin Otte committed
167 168 169
  gst_pad_set_chain_function (dec->sinkpad, theora_dec_chain);
  gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
170 171 172
  dec->srcpad =
      gst_pad_new_from_template (gst_static_pad_template_get
      (&theora_dec_src_factory), "src");
Benjamin Otte's avatar
Benjamin Otte committed
173
  gst_pad_use_explicit_caps (dec->srcpad);
174
  gst_pad_set_event_mask_function (dec->srcpad, theora_get_event_masks);
Benjamin Otte's avatar
Benjamin Otte committed
175
  gst_pad_set_event_function (dec->srcpad, theora_dec_src_event);
176
  gst_pad_set_query_type_function (dec->srcpad, theora_get_query_types);
177
  gst_pad_set_query_function (dec->srcpad, theora_dec_src_query);
178 179 180
  gst_pad_set_formats_function (dec->srcpad, theora_get_formats);
  gst_pad_set_convert_function (dec->srcpad, theora_dec_src_convert);

Benjamin Otte's avatar
Benjamin Otte committed
181 182 183
  gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);

  GST_FLAG_SET (dec, GST_ELEMENT_EVENT_AWARE);
184 185

  dec->crop = THEORA_DEF_CROP;
Benjamin Otte's avatar
Benjamin Otte committed
186
}
187 188

/* FIXME: copy from libtheora, theora should somehow make this available for seeking */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
189 190 191 192 193 194
static int
_theora_ilog (unsigned int v)
{
  int ret = 0;

  while (v) {
195
    ret++;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
196
    v >>= 1;
197
  }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
198
  return (ret);
199 200
}

201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
static const GstFormat *
theora_get_formats (GstPad * pad)
{
  static GstFormat src_formats[] = {
    GST_FORMAT_DEFAULT,         /* frames in this case */
    GST_FORMAT_TIME,
    GST_FORMAT_BYTES,
    0
  };
  static GstFormat sink_formats[] = {
    GST_FORMAT_DEFAULT,
    GST_FORMAT_TIME,
    0
  };

  return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
}

static const GstEventMask *
theora_get_event_masks (GstPad * pad)
{
  static const GstEventMask theora_src_event_masks[] = {
    {GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH},
    {0,}
  };

  return theora_src_event_masks;
}

static const GstQueryType *
theora_get_query_types (GstPad * pad)
{
  static const GstQueryType theora_src_query_types[] = {
    GST_QUERY_TOTAL,
    GST_QUERY_POSITION,
    0
  };

  return theora_src_query_types;
}


243
static gboolean
244 245 246
theora_dec_src_convert (GstPad * pad,
    GstFormat src_format, gint64 src_value,
    GstFormat * dest_format, gint64 * dest_value)
247
{
248 249 250 251 252
  gboolean res = TRUE;
  GstTheoraDec *dec;
  guint64 scale = 1;

  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
253

254
  /* we need the info part before we can done something */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
255 256 257
  if (dec->packetno < 1)
    return FALSE;

258 259 260 261 262 263 264 265 266 267 268 269 270
  switch (src_format) {
    case GST_FORMAT_BYTES:
      switch (*dest_format) {
        case GST_FORMAT_DEFAULT:
          *dest_value =
              src_value * 2 / (dec->info.height * dec->info.width * 3);
          break;
        case GST_FORMAT_TIME:
          /* seems like a rather silly conversion, implement me if you like */
        default:
          res = FALSE;
      }
      break;
271
    case GST_FORMAT_TIME:
272 273
      switch (*dest_format) {
        case GST_FORMAT_BYTES:
274
          scale = 3 * (dec->info.width * dec->info.height) / 2;
275
        case GST_FORMAT_DEFAULT:
276 277 278
          *dest_value =
              scale * (((guint64) src_value * dec->info.fps_numerator) /
              (dec->info.fps_denominator * GST_SECOND));
279 280 281 282
          break;
        default:
          res = FALSE;
      }
283 284
      break;
    case GST_FORMAT_DEFAULT:
285 286 287 288 289 290 291 292 293 294 295 296
      switch (*dest_format) {
        case GST_FORMAT_TIME:
          *dest_value = src_value * (GST_SECOND * dec->info.fps_denominator /
              dec->info.fps_numerator);
          break;
        case GST_FORMAT_BYTES:
          *dest_value =
              src_value * 3 * (dec->info.width * dec->info.height) / 2;
          break;
        default:
          res = FALSE;
      }
297 298
      break;
    default:
299
      res = FALSE;
300
  }
301 302

  return res;
303 304
}

Benjamin Otte's avatar
Benjamin Otte committed
305
static gboolean
306 307 308
theora_dec_sink_convert (GstPad * pad,
    GstFormat src_format, gint64 src_value,
    GstFormat * dest_format, gint64 * dest_value)
Benjamin Otte's avatar
Benjamin Otte committed
309
{
310 311
  gboolean res = TRUE;
  GstTheoraDec *dec;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
312

313 314 315
  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));

  /* we need the info part before we can done something */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
316 317 318
  if (dec->packetno < 1)
    return FALSE;

319
  switch (src_format) {
Benjamin Otte's avatar
Benjamin Otte committed
320
    case GST_FORMAT_DEFAULT:
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
    {
      guint64 framecount;
      guint ilog;

      ilog = _theora_ilog (dec->info.keyframe_frequency_force - 1);

      /* granulepos is last ilog bits for counting pframes since last iframe and 
       * bits in front of that for the framenumber of the last iframe. */
      framecount = src_value >> ilog;
      framecount += src_value - (framecount << ilog);

      switch (*dest_format) {
        case GST_FORMAT_TIME:
          *dest_value = framecount * (GST_SECOND * dec->info.fps_denominator /
              dec->info.fps_numerator);
          break;
        default:
          res = FALSE;
      }
340
      break;
341
    }
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
    case GST_FORMAT_TIME:
    {
      switch (*dest_format) {
        case GST_FORMAT_DEFAULT:
        {
          guint ilog = _theora_ilog (dec->info.keyframe_frequency_force - 1);

          *dest_value = src_value * dec->info.fps_numerator /
              (GST_SECOND * dec->info.fps_denominator);
          *dest_value <<= ilog;
          break;
        }
        default:
          res = FALSE;
          break;
      }
      break;
    }
Benjamin Otte's avatar
Benjamin Otte committed
360
    default:
361
      res = FALSE;
Benjamin Otte's avatar
Benjamin Otte committed
362
  }
363 364

  return res;
Benjamin Otte's avatar
Benjamin Otte committed
365
}
366 367

static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
368 369
theora_dec_src_query (GstPad * pad, GstQueryType query, GstFormat * format,
    gint64 * value)
370 371 372 373
{
  gint64 granulepos;
  GstTheoraDec *dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
  GstFormat my_format = GST_FORMAT_DEFAULT;
374
  guint64 time;
375

376
  if (query == GST_QUERY_POSITION) {
377
    /* this is easy, we can convert a granule position to everything */
378 379
    granulepos = dec->granulepos;
  } else {
380
    /* for the total, we just forward the query to the peer */
381 382 383 384
    if (!gst_pad_query (GST_PAD_PEER (dec->sinkpad), query, &my_format,
            &granulepos))
      return FALSE;
  }
385

386 387 388
  /* and convert to the final format in two steps with time as the 
   * intermediate step */
  my_format = GST_FORMAT_TIME;
389
  if (!theora_dec_sink_convert (dec->sinkpad, GST_FORMAT_DEFAULT, granulepos,
390 391
          &my_format, &time))
    return FALSE;
392
  if (!gst_pad_convert (pad, my_format, time, format, value))
393 394
    return FALSE;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
395
  GST_LOG_OBJECT (dec,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
396
      "query %u: peer returned granulepos: %llu - we return %llu (format %u)",
397 398 399 400
      query, granulepos, *value, *format);
  return TRUE;
}

Benjamin Otte's avatar
Benjamin Otte committed
401
static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
402
theora_dec_src_event (GstPad * pad, GstEvent * event)
Benjamin Otte's avatar
Benjamin Otte committed
403 404 405
{
  gboolean res = TRUE;
  GstTheoraDec *dec;
406
  GstFormat format;
Benjamin Otte's avatar
Benjamin Otte committed
407 408 409 410

  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));

  switch (GST_EVENT_TYPE (event)) {
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
411
    case GST_EVENT_SEEK:{
Benjamin Otte's avatar
Benjamin Otte committed
412
      guint64 value;
Scott Wheeler Wheeler's avatar
Scott Wheeler Wheeler committed
413
      GstEvent *real_seek;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
414

415 416 417 418 419 420 421 422
      /* we have to ask our peer to seek to time here as we know
       * nothing about how to generate a granulepos from the src
       * formats or anything.
       * 
       * First bring the requested format to time 
       */
      format = GST_FORMAT_TIME;
      res = gst_pad_convert (pad, GST_EVENT_SEEK_FORMAT (event),
423
          GST_EVENT_SEEK_OFFSET (event), &format, &value);
424 425
      if (!res)
        goto error;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
426

427
      /* then seek with time on the peer */
Scott Wheeler Wheeler's avatar
Scott Wheeler Wheeler committed
428
      real_seek = gst_event_new_seek (
429 430 431 432 433 434 435 436 437 438 439
          (GST_EVENT_SEEK_TYPE (event) & ~GST_SEEK_FORMAT_MASK) |
          format, value);

      res = gst_pad_send_event (GST_PAD_PEER (dec->sinkpad), real_seek);
      if (!res)
        goto error;

      /* all worked, make sure we sync to keyframe */
      dec->need_keyframe = TRUE;

    error:
Benjamin Otte's avatar
Benjamin Otte committed
440 441 442 443 444 445 446 447 448 449 450 451
      gst_event_unref (event);
      break;
    }
    default:
      res = gst_pad_event_default (pad, event);
      break;
  }

  return res;
}

static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
452
theora_dec_event (GstTheoraDec * dec, GstEvent * event)
Benjamin Otte's avatar
Benjamin Otte committed
453
{
454
  guint64 value, time, bytes;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
455

Benjamin Otte's avatar
Benjamin Otte committed
456 457 458 459
  GST_LOG_OBJECT (dec, "handling event");
  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_DISCONTINUOUS:
      if (gst_event_discont_get_value (event, GST_FORMAT_DEFAULT, &value)) {
460 461
        dec->granulepos = value;
        GST_DEBUG_OBJECT (dec,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
462
            "setting granuleposition to %" G_GUINT64_FORMAT " after discont",
463
            value);
Benjamin Otte's avatar
Benjamin Otte committed
464
      } else {
465 466
        GST_WARNING_OBJECT (dec,
            "discont event didn't include offset, we might set it wrong now");
Benjamin Otte's avatar
Benjamin Otte committed
467
      }
468
      if (dec->packetno < 3) {
469 470 471 472 473 474 475
        if (dec->granulepos != 0)
          GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL),
              ("can't handle discont before parsing first 3 packets"));
        dec->packetno = 0;
        gst_pad_push (dec->srcpad, GST_DATA (gst_event_new_discontinuous (FALSE,
                    GST_FORMAT_TIME, (guint64) 0, GST_FORMAT_DEFAULT,
                    (guint64) 0, GST_FORMAT_BYTES, (guint64) 0, 0)));
476
      } else {
477 478 479 480 481 482
        GstFormat time_format, default_format, bytes_format;

        time_format = GST_FORMAT_TIME;
        default_format = GST_FORMAT_DEFAULT;
        bytes_format = GST_FORMAT_BYTES;

483
        /* if one of them works, all of them work */
484 485 486 487 488 489
        if (theora_dec_sink_convert (dec->sinkpad, GST_FORMAT_DEFAULT,
                dec->granulepos, &time_format, &time)
            && theora_dec_src_convert (dec->srcpad, GST_FORMAT_TIME, time,
                &default_format, &value)
            && theora_dec_src_convert (dec->srcpad, GST_FORMAT_TIME, time,
                &bytes_format, &bytes)) {
490 491 492 493
          gst_pad_push (dec->srcpad,
              GST_DATA (gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
                      time, GST_FORMAT_DEFAULT, value, GST_FORMAT_BYTES, bytes,
                      0)));
494 495
          /* store new framenumber */
          dec->packetno = value + 3;
496 497 498 499
        } else {
          GST_ERROR_OBJECT (dec,
              "failed to parse data for DISCONT event, not sending any");
        }
500 501
        /* sync to keyframe */
        dec->need_keyframe = TRUE;
502
      }
Benjamin Otte's avatar
Benjamin Otte committed
503 504 505 506 507 508 509
      break;
    default:
      break;
  }
  gst_pad_event_default (dec->sinkpad, event);
}

510 511 512 513
#define ROUND_UP_2(x) (((x) + 1) & ~1)
#define ROUND_UP_4(x) (((x) + 3) & ~3)
#define ROUND_UP_8(x) (((x) + 7) & ~7)

Benjamin Otte's avatar
Benjamin Otte committed
514
static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
515
theora_dec_chain (GstPad * pad, GstData * data)
Benjamin Otte's avatar
Benjamin Otte committed
516 517 518 519
{
  GstBuffer *buf;
  GstTheoraDec *dec;
  ogg_packet packet;
520
  guint64 offset_end;
521
  GstClockTime outtime;
Benjamin Otte's avatar
Benjamin Otte committed
522 523 524 525 526 527 528 529

  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
  if (GST_IS_EVENT (data)) {
    theora_dec_event (dec, GST_EVENT (data));
    return;
  }

  buf = GST_BUFFER (data);
530

531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
  if (dec->packetno >= 3) {
    offset_end = GST_BUFFER_OFFSET_END (buf);
    if (offset_end != -1) {
      dec->granulepos = offset_end;
      /* granulepos to time */
      outtime = GST_SECOND * theora_granule_time (&dec->state, dec->granulepos);
    } else {
      GstFormat time_format = GST_FORMAT_TIME;

      /* framenumber to time */
      theora_dec_src_convert (dec->srcpad, GST_FORMAT_DEFAULT,
          dec->packetno - 3, &time_format, &outtime);
    }
  } else {
    /* we don't know yet */
    outtime = -1;
547 548
  }

Benjamin Otte's avatar
Benjamin Otte committed
549 550 551
  /* make ogg_packet out of the buffer */
  packet.packet = GST_BUFFER_DATA (buf);
  packet.bytes = GST_BUFFER_SIZE (buf);
552
  packet.granulepos = dec->granulepos;
553
  packet.packetno = dec->packetno;
554 555
  packet.b_o_s = (packet.packetno == 0) ? 1 : 0;
  packet.e_o_s = 0;
556

557 558 559
  GST_DEBUG_OBJECT (dec, "header=%d packetno=%d", packet.packet[0],
      packet.packetno);

Benjamin Otte's avatar
Benjamin Otte committed
560 561
  /* switch depending on packet type */
  if (packet.packet[0] & 0x80) {
562 563 564 565 566
    if (packet.packetno > 3) {
      GST_WARNING_OBJECT (GST_OBJECT (dec), "Ignoring header");
      gst_data_unref (data);
      return;
    }
Benjamin Otte's avatar
Benjamin Otte committed
567 568
    /* header packet */
    if (theora_decode_header (&dec->info, &dec->comment, &packet)) {
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
569
      GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
570
          (NULL), ("couldn't read header packet"));
Benjamin Otte's avatar
Benjamin Otte committed
571 572 573
      gst_data_unref (data);
      return;
    }
574 575 576
    if (packet.packetno == 0) {
      dec->packetno++;
    } else if (packet.packetno == 1) {
577
      gchar *encoder = NULL;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
578
      GstTagList *list =
579 580
          gst_tag_list_from_vorbiscomment_buffer (buf, "\201theora", 7,
          &encoder);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
581

582
      if (!list) {
583 584
        GST_ERROR_OBJECT (dec, "failed to parse tags");
        list = gst_tag_list_new ();
585 586
      }
      if (encoder) {
587 588 589
        gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
            GST_TAG_ENCODER, encoder, NULL);
        g_free (encoder);
590
      }
Benjamin Otte's avatar
Benjamin Otte committed
591
      gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
592
          GST_TAG_ENCODER_VERSION, dec->info.version_major, NULL);
Benjamin Otte's avatar
Benjamin Otte committed
593
      gst_element_found_tags_for_pad (GST_ELEMENT (dec), dec->srcpad, 0, list);
594 595

      dec->packetno++;
Benjamin Otte's avatar
Benjamin Otte committed
596 597
    } else if (packet.packetno == 2) {
      GstCaps *caps;
598 599 600 601 602 603 604 605 606 607 608 609 610
      gint par_num, par_den;

      GST_DEBUG_OBJECT (dec, "fps %d/%d, PAR %d/%d",
          dec->info.fps_numerator, dec->info.fps_denominator,
          dec->info.aspect_numerator, dec->info.aspect_denominator);

      /* calculate par
       * the info.aspect_* values reflect PAR;
       * 0:0 is allowed and can be interpreted as 1:1, so correct for it */
      par_num = dec->info.aspect_numerator;
      par_den = dec->info.aspect_denominator;
      if (par_num == 0 && par_den == 0) {
        par_num = par_den = 1;
611

612
      }
613 614 615 616 617 618 619
      /* theora has:
       *
       *  width/height : dimension of the encoded frame 
       *  frame_width/frame_height : dimension of the visible part
       *  offset_x/offset_y : offset in encoded frame where visible part starts
       */
      GST_DEBUG_OBJECT (dec, "dimension %dx%d, PAR %d/%d", dec->info.width,
620
          dec->info.height, par_num, par_den);
621 622 623
      GST_DEBUG_OBJECT (dec, "frame dimension %dx%d, offset %d:%d",
          dec->info.frame_width, dec->info.frame_height,
          dec->info.offset_x, dec->info.offset_y);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
624

625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640
      if (dec->crop) {
        /* add black borders to make width/height/offsets even. we need this because
         * we cannot express an offset to the peer plugin. */
        dec->width =
            ROUND_UP_2 (dec->info.frame_width + (dec->info.offset_x & 1));
        dec->height =
            ROUND_UP_2 (dec->info.frame_height + (dec->info.offset_y & 1));
        dec->offset_x = dec->info.offset_x & ~1;
        dec->offset_y = dec->info.offset_y & ~1;
      } else {
        /* no cropping, use the encoded dimensions */
        dec->width = dec->info.width;
        dec->height = dec->info.height;
        dec->offset_x = 0;
        dec->offset_y = 0;
      }
641 642 643 644

      GST_DEBUG_OBJECT (dec, "after fixup frame dimension %dx%d, offset %d:%d",
          dec->width, dec->height, dec->offset_x, dec->offset_y);

Benjamin Otte's avatar
Benjamin Otte committed
645 646 647
      /* done */
      theora_decode_init (&dec->state, &dec->info);
      caps = gst_caps_new_simple ("video/x-raw-yuv",
648 649 650
          "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
          "framerate", G_TYPE_DOUBLE,
          ((gdouble) dec->info.fps_numerator) / dec->info.fps_denominator,
651
          "pixel-aspect-ratio", GST_TYPE_FRACTION, par_num, par_den,
652 653
          "width", G_TYPE_INT, dec->width, "height", G_TYPE_INT,
          dec->height, NULL);
Benjamin Otte's avatar
Benjamin Otte committed
654 655
      gst_pad_set_explicit_caps (dec->srcpad, caps);
      gst_caps_free (caps);
656 657 658

      dec->initialized = TRUE;
      dec->packetno++;
Benjamin Otte's avatar
Benjamin Otte committed
659 660
    }
  } else {
661
    /* normal data packet */
Benjamin Otte's avatar
Benjamin Otte committed
662 663 664
    yuv_buffer yuv;
    GstBuffer *out;
    guint i;
665
    gboolean keyframe;
666 667 668 669
    gint out_size;
    gint stride_y, stride_uv;
    gint width, height;
    gint cwidth, cheight;
670

671 672 673 674 675 676 677
    dec->packetno++;

    if (!dec->initialized) {
      gst_data_unref (data);
      return;
    }

678 679 680 681 682 683
    /* the second most significant bit of the first data byte is cleared 
     * for keyframes */
    keyframe = (packet.packet[0] & 0x40) == 0;
    if (keyframe) {
      dec->need_keyframe = FALSE;
    } else if (dec->need_keyframe) {
684
      GST_WARNING_OBJECT (dec, "dropping frame because we need a keyframe");
685 686 687 688
      /* drop frames if we're looking for a keyframe */
      gst_data_unref (data);
      return;
    }
689 690 691 692 693
    if (theora_decode_packetin (&dec->state, &packet)) {
      GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
          (NULL), ("theora decoder did not read data packet"));
      gst_data_unref (data);
      return;
694
    }
695 696 697 698 699 700
    if (theora_decode_YUVout (&dec->state, &yuv) < 0) {
      GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
          (NULL), ("couldn't read out YUV image"));
      gst_data_unref (data);
      return;
    }
701

702 703
    g_return_if_fail (yuv.y_width == dec->info.width);
    g_return_if_fail (yuv.y_height == dec->info.height);
704

705 706 707 708
    width = dec->width;
    height = dec->height;
    cwidth = width / 2;
    cheight = height / 2;
709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725

    /* should get the stride from the caps, for now we round up to the nearest
     * multiple of 4 because some element needs it. chroma needs special 
     * treatment, see videotestsrc. */
    stride_y = ROUND_UP_4 (width);
    stride_uv = ROUND_UP_8 (width) / 2;

    out_size = stride_y * height + stride_uv * cheight * 2;

    /* now copy over the area contained in offset_x,offset_y,
     * frame_width, frame_height */
    out = gst_pad_alloc_buffer (dec->srcpad, GST_BUFFER_OFFSET_NONE, out_size);

    /* copy the visible region to the destination. This is actually pretty
     * complicated and gstreamer doesn't support all the needed caps to do this
     * correctly. For example, when we have an odd offset, we should only combine
     * 1 row/column of luma samples with on chroma sample in colorspace conversion. 
726 727
     * We compensate for this by adding a block border around the image when the
     * offset of size is odd (see above).
728 729 730 731 732 733 734 735
     */
    {
      guint8 *dest_y, *src_y;
      guint8 *dest_u, *src_u;
      guint8 *dest_v, *src_v;

      dest_y = GST_BUFFER_DATA (out);
      dest_u = dest_y + stride_y * height;
736
      dest_v = dest_u + stride_uv * cheight;
737

738
      src_y = yuv.y + dec->offset_x + dec->offset_y * yuv.y_stride;
739 740 741 742 743 744 745 746

      for (i = 0; i < height; i++) {
        memcpy (dest_y, src_y, width);

        dest_y += stride_y;
        src_y += yuv.y_stride;
      }

747 748
      src_u = yuv.u + dec->offset_x / 2 + dec->offset_y / 2 * yuv.uv_stride;
      src_v = yuv.v + dec->offset_x / 2 + dec->offset_y / 2 * yuv.uv_stride;
749 750 751 752 753 754 755 756 757 758

      for (i = 0; i < cheight; i++) {
        memcpy (dest_u, src_u, cwidth);
        memcpy (dest_v, src_v, cwidth);

        dest_u += stride_uv;
        src_u += yuv.uv_stride;
        dest_v += stride_uv;
        src_v += yuv.uv_stride;
      }
759
    }
760

761 762 763 764 765 766 767
    GST_BUFFER_OFFSET (out) = dec->packetno - 4;
    GST_BUFFER_OFFSET_END (out) = dec->packetno - 3;
    GST_BUFFER_DURATION (out) =
        GST_SECOND * ((gdouble) dec->info.fps_denominator) /
        dec->info.fps_numerator;
    GST_BUFFER_TIMESTAMP (out) = outtime;

Benjamin Otte's avatar
Benjamin Otte committed
768 769 770 771 772 773
    gst_pad_push (dec->srcpad, GST_DATA (out));
  }
  gst_data_unref (data);
}

static GstElementStateReturn
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
774
theora_dec_change_state (GstElement * element)
Benjamin Otte's avatar
Benjamin Otte committed
775 776 777 778 779 780 781 782 783
{
  GstTheoraDec *dec = GST_THEORA_DEC (element);

  switch (GST_STATE_TRANSITION (element)) {
    case GST_STATE_NULL_TO_READY:
      break;
    case GST_STATE_READY_TO_PAUSED:
      theora_info_init (&dec->info);
      theora_comment_init (&dec->comment);
784
      dec->need_keyframe = TRUE;
785
      dec->initialized = FALSE;
Benjamin Otte's avatar
Benjamin Otte committed
786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805
      break;
    case GST_STATE_PAUSED_TO_PLAYING:
      break;
    case GST_STATE_PLAYING_TO_PAUSED:
      break;
    case GST_STATE_PAUSED_TO_READY:
      theora_clear (&dec->state);
      theora_comment_clear (&dec->comment);
      theora_info_clear (&dec->info);
      dec->packetno = 0;
      dec->granulepos = 0;
      break;
    case GST_STATE_READY_TO_NULL:
      break;
    default:
      break;
  }

  return parent_class->change_state (element);
}
806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837

static void
theora_dec_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
  GstTheoraDec *dec = GST_THEORA_DEC (object);

  switch (prop_id) {
    case ARG_CROP:
      dec->crop = g_value_get_boolean (value);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
theora_dec_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
{
  GstTheoraDec *dec = GST_THEORA_DEC (object);

  switch (prop_id) {
    case ARG_CROP:
      g_value_set_boolean (value, dec->crop);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}