theoradec.c 25.5 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
    case GST_FORMAT_TIME:
    {
      switch (*dest_format) {
        case GST_FORMAT_DEFAULT:
        {
          guint ilog = _theora_ilog (dec->info.keyframe_frequency_force - 1);
348
          guint rest;
349

350
          /* framecount */
351 352
          *dest_value = src_value * dec->info.fps_numerator /
              (GST_SECOND * dec->info.fps_denominator);
353 354 355 356

          /* funny way of calculating granulepos in theora */
          rest = *dest_value / dec->info.keyframe_frequency_force;
          *dest_value -= rest;
357
          *dest_value <<= ilog;
358
          *dest_value += rest;
359 360 361 362 363 364 365 366
          break;
        }
        default:
          res = FALSE;
          break;
      }
      break;
    }
Benjamin Otte's avatar
Benjamin Otte committed
367
    default:
368
      res = FALSE;
Benjamin Otte's avatar
Benjamin Otte committed
369
  }
370 371

  return res;
Benjamin Otte's avatar
Benjamin Otte committed
372
}
373 374

static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
375 376
theora_dec_src_query (GstPad * pad, GstQueryType query, GstFormat * format,
    gint64 * value)
377 378 379 380
{
  gint64 granulepos;
  GstTheoraDec *dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
  GstFormat my_format = GST_FORMAT_DEFAULT;
381
  guint64 time;
382

383
  if (query == GST_QUERY_POSITION) {
384
    /* this is easy, we can convert a granule position to everything */
385 386
    granulepos = dec->granulepos;
  } else {
387
    /* for the total, we just forward the query to the peer */
388 389 390 391
    if (!gst_pad_query (GST_PAD_PEER (dec->sinkpad), query, &my_format,
            &granulepos))
      return FALSE;
  }
392

393 394 395
  /* and convert to the final format in two steps with time as the 
   * intermediate step */
  my_format = GST_FORMAT_TIME;
396
  if (!theora_dec_sink_convert (dec->sinkpad, GST_FORMAT_DEFAULT, granulepos,
397 398
          &my_format, &time))
    return FALSE;
399
  if (!gst_pad_convert (pad, my_format, time, format, value))
400 401
    return FALSE;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
402
  GST_LOG_OBJECT (dec,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
403
      "query %u: peer returned granulepos: %llu - we return %llu (format %u)",
404 405 406 407
      query, granulepos, *value, *format);
  return TRUE;
}

Benjamin Otte's avatar
Benjamin Otte committed
408
static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
409
theora_dec_src_event (GstPad * pad, GstEvent * event)
Benjamin Otte's avatar
Benjamin Otte committed
410 411 412
{
  gboolean res = TRUE;
  GstTheoraDec *dec;
413
  GstFormat format;
Benjamin Otte's avatar
Benjamin Otte committed
414 415 416 417

  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));

  switch (GST_EVENT_TYPE (event)) {
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
418
    case GST_EVENT_SEEK:{
Benjamin Otte's avatar
Benjamin Otte committed
419
      guint64 value;
Scott Wheeler Wheeler's avatar
Scott Wheeler Wheeler committed
420
      GstEvent *real_seek;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
421

422 423 424 425 426 427 428 429
      /* 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),
430
          GST_EVENT_SEEK_OFFSET (event), &format, &value);
431 432
      if (!res)
        goto error;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
433

434
      /* then seek with time on the peer */
Scott Wheeler Wheeler's avatar
Scott Wheeler Wheeler committed
435
      real_seek = gst_event_new_seek (
436 437 438 439 440 441 442 443 444 445 446
          (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
447 448 449 450 451 452 453 454 455 456 457 458
      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
459
theora_dec_event (GstTheoraDec * dec, GstEvent * event)
Benjamin Otte's avatar
Benjamin Otte committed
460
{
461
  guint64 value, time, bytes;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
462

Benjamin Otte's avatar
Benjamin Otte committed
463 464 465 466
  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)) {
467 468
        dec->granulepos = value;
        GST_DEBUG_OBJECT (dec,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
469
            "setting granuleposition to %" G_GUINT64_FORMAT " after discont",
470
            value);
Benjamin Otte's avatar
Benjamin Otte committed
471
      } else {
472 473
        GST_WARNING_OBJECT (dec,
            "discont event didn't include offset, we might set it wrong now");
Benjamin Otte's avatar
Benjamin Otte committed
474
      }
475
      if (dec->packetno < 3) {
476 477 478 479 480 481 482
        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)));
483
      } else {
484 485 486 487 488 489
        GstFormat time_format, default_format, bytes_format;

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

490
        /* if one of them works, all of them work */
491 492 493 494 495 496
        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)) {
497 498 499 500
          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)));
501 502
          /* store new framenumber */
          dec->packetno = value + 3;
503 504 505 506
        } else {
          GST_ERROR_OBJECT (dec,
              "failed to parse data for DISCONT event, not sending any");
        }
507 508
        /* sync to keyframe */
        dec->need_keyframe = TRUE;
509
      }
Benjamin Otte's avatar
Benjamin Otte committed
510 511 512 513 514 515 516
      break;
    default:
      break;
  }
  gst_pad_event_default (dec->sinkpad, event);
}

517 518 519 520
#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
521
static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
522
theora_dec_chain (GstPad * pad, GstData * data)
Benjamin Otte's avatar
Benjamin Otte committed
523 524 525 526
{
  GstBuffer *buf;
  GstTheoraDec *dec;
  ogg_packet packet;
527
  guint64 offset_end;
528
  GstClockTime outtime;
Benjamin Otte's avatar
Benjamin Otte committed
529 530 531 532 533 534 535 536

  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);
537

538 539 540 541 542
  if (dec->packetno >= 3) {
    offset_end = GST_BUFFER_OFFSET_END (buf);
    if (offset_end != -1) {
      dec->granulepos = offset_end;
    }
543 544 545

    /* granulepos to time */
    outtime = GST_SECOND * theora_granule_time (&dec->state, dec->granulepos);
546 547 548
  } else {
    /* we don't know yet */
    outtime = -1;
549 550
  }

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

559 560 561 562
  GST_DEBUG_OBJECT (dec, "outtime=%" GST_TIME_FORMAT " (%"
      G_GUINT64_FORMAT ") header=0x%02x packetno=%d",
      GST_TIME_ARGS (outtime), outtime,
      (gint) packet.packet[0], packet.packetno);
563

Benjamin Otte's avatar
Benjamin Otte committed
564 565
  /* switch depending on packet type */
  if (packet.packet[0] & 0x80) {
566 567
    if (packet.packetno > 3) {
      GST_WARNING_OBJECT (GST_OBJECT (dec), "Ignoring header");
568
      goto done;
569
    }
Benjamin Otte's avatar
Benjamin Otte committed
570 571
    /* header packet */
    if (theora_decode_header (&dec->info, &dec->comment, &packet)) {
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
572
      GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
573
          (NULL), ("couldn't read header packet"));
574
      goto done;
Benjamin Otte's avatar
Benjamin Otte committed
575
    }
576

577 578 579
    if (packet.packetno == 0) {
      dec->packetno++;
    } else if (packet.packetno == 1) {
580
      gchar *encoder = NULL;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
581
      GstTagList *list =
582 583
          gst_tag_list_from_vorbiscomment_buffer (buf, "\201theora", 7,
          &encoder);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
584

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

      dec->packetno++;
Benjamin Otte's avatar
Benjamin Otte committed
601 602
    } else if (packet.packetno == 2) {
      GstCaps *caps;
603 604 605 606 607 608 609 610 611 612 613 614 615
      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;
616

617
      }
618 619 620 621 622 623 624
      /* 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,
625
          dec->info.height, par_num, par_den);
626 627 628
      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
629

630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
      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;
      }
646 647 648 649

      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
650 651
      /* done */
      theora_decode_init (&dec->state, &dec->info);
652

Benjamin Otte's avatar
Benjamin Otte committed
653
      caps = gst_caps_new_simple ("video/x-raw-yuv",
654 655 656
          "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
          "framerate", G_TYPE_DOUBLE,
          ((gdouble) dec->info.fps_numerator) / dec->info.fps_denominator,
657
          "pixel-aspect-ratio", GST_TYPE_FRACTION, par_num, par_den,
658 659
          "width", G_TYPE_INT, dec->width, "height", G_TYPE_INT,
          dec->height, NULL);
Benjamin Otte's avatar
Benjamin Otte committed
660 661
      gst_pad_set_explicit_caps (dec->srcpad, caps);
      gst_caps_free (caps);
662 663 664

      dec->initialized = TRUE;
      dec->packetno++;
Benjamin Otte's avatar
Benjamin Otte committed
665 666
    }
  } else {
667
    /* normal data packet */
Benjamin Otte's avatar
Benjamin Otte committed
668 669 670
    yuv_buffer yuv;
    GstBuffer *out;
    guint i;
671
    gboolean keyframe;
672 673 674 675
    gint out_size;
    gint stride_y, stride_uv;
    gint width, height;
    gint cwidth, cheight;
676

677 678 679
    dec->packetno++;

    if (!dec->initialized) {
680
      goto done;
681 682
    }

683 684 685 686
    /* the second most significant bit of the first data byte is cleared 
     * for keyframes */
    keyframe = (packet.packet[0] & 0x40) == 0;
    if (keyframe) {
687 688 689 690
      guint ilog;
      guint64 framecount;
      gboolean add_one = FALSE;

691
      dec->need_keyframe = FALSE;
692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
      ilog = _theora_ilog (dec->info.keyframe_frequency_force - 1);
      if (dec->granulepos % (1 << ilog) == 0 &&
          dec->granulepos > 0 && GST_BUFFER_OFFSET_END (buf) == -1) {
        dec->granulepos--;
        add_one = TRUE;
      }
      framecount = dec->granulepos >> ilog;
      framecount += dec->granulepos - (framecount << ilog);
      if (add_one) {
        framecount++;
      }
      dec->granulepos = framecount << ilog;
      if (add_one) {
        outtime = GST_SECOND * theora_granule_time (&dec->state,
            dec->granulepos);
707 708 709
        GST_DEBUG_OBJECT (dec,
            "Correcting output time to %" GST_TIME_FORMAT,
            GST_TIME_ARGS (outtime));
710
      }
711
    } else if (dec->need_keyframe) {
712
      GST_WARNING_OBJECT (dec, "dropping frame because we need a keyframe");
713
      /* drop frames if we're looking for a keyframe */
714
      goto done;
715
    }
716 717 718
    if (theora_decode_packetin (&dec->state, &packet)) {
      GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
          (NULL), ("theora decoder did not read data packet"));
719
      goto done;
720
    }
721 722 723
    if (theora_decode_YUVout (&dec->state, &yuv) < 0) {
      GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
          (NULL), ("couldn't read out YUV image"));
724
      goto done;
725
    }
726

727 728
    g_return_if_fail (yuv.y_width == dec->info.width);
    g_return_if_fail (yuv.y_height == dec->info.height);
729

730 731 732 733
    width = dec->width;
    height = dec->height;
    cwidth = width / 2;
    cheight = height / 2;
734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750

    /* 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. 
751 752
     * We compensate for this by adding a block border around the image when the
     * offset of size is odd (see above).
753 754 755 756 757 758 759 760
     */
    {
      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;
761
      dest_v = dest_u + stride_uv * cheight;
762

763
      src_y = yuv.y + dec->offset_x + dec->offset_y * yuv.y_stride;
764 765 766 767 768 769 770 771

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

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

772 773
      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;
774 775 776 777 778 779 780 781 782 783

      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;
      }
784
    }
785

786 787 788 789 790 791 792
    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
793 794
    gst_pad_push (dec->srcpad, GST_DATA (out));
  }
795
done:
Benjamin Otte's avatar
Benjamin Otte committed
796
  gst_data_unref (data);
797
  dec->granulepos++;
Benjamin Otte's avatar
Benjamin Otte committed
798 799 800
}

static GstElementStateReturn
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
801
theora_dec_change_state (GstElement * element)
Benjamin Otte's avatar
Benjamin Otte committed
802 803 804 805 806 807 808 809 810
{
  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);
811
      dec->need_keyframe = TRUE;
812
      dec->initialized = FALSE;
Benjamin Otte's avatar
Benjamin Otte committed
813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832
      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);
}
833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864

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;
  }
}