theoradec.c 13.8 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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
/* 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>


#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
44 45 46 47 48 49 50 51 52 53 54 55 56
struct _GstTheoraDec
{
  GstElement element;

  GstPad *sinkpad;
  GstPad *srcpad;

  theora_state state;
  theora_info info;
  theora_comment comment;

  guint packetno;
  guint64 granulepos;
Benjamin Otte's avatar
Benjamin Otte committed
57 58
};

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
59 60
struct _GstTheoraDecClass
{
Benjamin Otte's avatar
Benjamin Otte committed
61 62 63 64 65 66 67 68 69 70 71
  GstElementClass parent_class;
};

static GstElementDetails theora_dec_details = {
  "TheoraDec",
  "Filter/Decoder/Video",
  "decode raw theora streams to raw YUV video",
  "Benjamin Otte <in7y118@public.uni-hamburg.de>",
};

static GstStaticPadTemplate theora_dec_src_factory =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
72 73 74 75 76 77 78 79
GST_STATIC_PAD_TEMPLATE ("src",
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("video/x-raw-yuv, "
	"format = (fourcc) I420, "
	"framerate = (double) [0, MAX], "
	"width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
    );
Benjamin Otte's avatar
Benjamin Otte committed
80 81

static GstStaticPadTemplate theora_dec_sink_factory =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
82 83 84 85 86
GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("video/x-theora")
    );
Benjamin Otte's avatar
Benjamin Otte committed
87 88

GST_BOILERPLATE (GstTheoraDec, gst_theora_dec, GstElement, GST_TYPE_ELEMENT);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
89 90 91 92 93 94

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);
Benjamin Otte's avatar
Benjamin Otte committed
95 96 97 98 99 100


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
101 102

  gst_element_class_add_pad_template (element_class,
Benjamin Otte's avatar
Benjamin Otte committed
103 104 105 106 107 108 109
      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
110
gst_theora_dec_class_init (GstTheoraDecClass * klass)
Benjamin Otte's avatar
Benjamin Otte committed
111 112 113 114 115 116 117
{
  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);

  gstelement_class->change_state = theora_dec_change_state;
}

static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
118
gst_theora_dec_init (GstTheoraDec * dec)
Benjamin Otte's avatar
Benjamin Otte committed
119
{
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
120 121 122
  dec->sinkpad =
      gst_pad_new_from_template (gst_static_pad_template_get
      (&theora_dec_sink_factory), "sink");
Benjamin Otte's avatar
Benjamin Otte committed
123 124 125
  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
126 127 128
  dec->srcpad =
      gst_pad_new_from_template (gst_static_pad_template_get
      (&theora_dec_src_factory), "src");
Benjamin Otte's avatar
Benjamin Otte committed
129 130
  gst_pad_use_explicit_caps (dec->srcpad);
  gst_pad_set_event_function (dec->srcpad, theora_dec_src_event);
131
  gst_pad_set_query_function (dec->srcpad, theora_dec_src_query);
Benjamin Otte's avatar
Benjamin Otte committed
132 133 134 135
  gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);

  GST_FLAG_SET (dec, GST_ELEMENT_EVENT_AWARE);
}
136 137

/* FIXME: copy from libtheora, theora should somehow make this available for seeking */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
138 139 140 141 142 143
static int
_theora_ilog (unsigned int v)
{
  int ret = 0;

  while (v) {
144
    ret++;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
145
    v >>= 1;
146
  }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
147
  return (ret);
148 149 150
}

static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
151 152
theora_dec_from_granulepos (GstTheoraDec * dec, GstFormat format, guint64 from,
    guint64 * to)
153 154 155
{
  guint64 framecount;
  guint ilog = _theora_ilog (dec->info.keyframe_frequency_force);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
156 157 158 159

  if (dec->packetno < 1)
    return FALSE;

160 161 162 163 164 165 166
  /* 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 = from >> ilog;
  framecount += from - (framecount << ilog);

  switch (format) {
    case GST_FORMAT_TIME:
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
167 168 169
      *to = framecount =
	  from * GST_SECOND * dec->info.fps_denominator /
	  dec->info.fps_numerator;
170 171 172 173 174 175 176 177 178 179 180 181 182 183
      break;
    case GST_FORMAT_DEFAULT:
      *to = framecount;
      break;
    case GST_FORMAT_BYTES:
      *to = framecount * dec->info.height * dec->info.width * 12 / 8;
      break;
    default:
      return FALSE;
  }
  return TRUE;
}

/* FIXME: we can only seek to keyframes... */
Benjamin Otte's avatar
Benjamin Otte committed
184
static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
185 186
theora_dec_to_granulepos (GstTheoraDec * dec, GstFormat format, guint64 from,
    guint64 * to)
Benjamin Otte's avatar
Benjamin Otte committed
187 188
{
  guint64 framecount;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
189 190 191 192

  if (dec->packetno < 1)
    return FALSE;

Benjamin Otte's avatar
Benjamin Otte committed
193 194
  switch (format) {
    case GST_FORMAT_TIME:
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
195 196 197
      framecount =
	  from * dec->info.fps_numerator / (GST_SECOND *
	  dec->info.fps_denominator);
198
      break;
Benjamin Otte's avatar
Benjamin Otte committed
199 200
    case GST_FORMAT_DEFAULT:
      framecount = from;
201
      break;
Benjamin Otte's avatar
Benjamin Otte committed
202
    case GST_FORMAT_BYTES:
203 204
      framecount = from * 8 / (dec->info.height * dec->info.width * 12);
      break;
Benjamin Otte's avatar
Benjamin Otte committed
205 206 207
    default:
      return FALSE;
  }
208 209
  *to = framecount << _theora_ilog (dec->info.keyframe_frequency_force - 1);
  return TRUE;
Benjamin Otte's avatar
Benjamin Otte committed
210
}
211 212

static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
213 214
theora_dec_src_query (GstPad * pad, GstQueryType query, GstFormat * format,
    gint64 * value)
215 216 217 218 219
{
  gint64 granulepos;
  GstTheoraDec *dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
  GstFormat my_format = GST_FORMAT_DEFAULT;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
220 221
  if (!gst_pad_query (GST_PAD_PEER (dec->sinkpad), query, &my_format,
	  &granulepos))
222 223 224 225 226
    return FALSE;

  if (!theora_dec_from_granulepos (dec, *format, granulepos, value))
    return FALSE;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
227 228
  GST_LOG_OBJECT (dec,
      "query %u: peer returned granulepos: %llu - we return %llu (format %u)\n",
229 230 231 232
      query, granulepos, *value, *format);
  return TRUE;
}

Benjamin Otte's avatar
Benjamin Otte committed
233
static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
234
theora_dec_src_event (GstPad * pad, GstEvent * event)
Benjamin Otte's avatar
Benjamin Otte committed
235 236 237 238 239 240 241
{
  gboolean res = TRUE;
  GstTheoraDec *dec;

  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));

  switch (GST_EVENT_TYPE (event)) {
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
242
    case GST_EVENT_SEEK:{
Benjamin Otte's avatar
Benjamin Otte committed
243
      guint64 value;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
244 245 246

      res = theora_dec_to_granulepos (dec, GST_EVENT_SEEK_FORMAT (event),
	  GST_EVENT_SEEK_OFFSET (event), &value);
Benjamin Otte's avatar
Benjamin Otte committed
247 248
      if (res) {
	GstEvent *real_seek = gst_event_new_seek (
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
249 250
	    (GST_EVENT_SEEK_TYPE (event) & ~GST_SEEK_FORMAT_MASK) |
	    GST_FORMAT_DEFAULT,
Benjamin Otte's avatar
Benjamin Otte committed
251
	    value);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
252

Benjamin Otte's avatar
Benjamin Otte committed
253 254 255 256 257 258 259 260 261 262 263 264 265 266
	res = gst_pad_send_event (GST_PAD_PEER (dec->sinkpad), real_seek);
      }
      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
267
theora_dec_event (GstTheoraDec * dec, GstEvent * event)
Benjamin Otte's avatar
Benjamin Otte committed
268
{
269
  guint64 value, time, bytes;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
270

Benjamin Otte's avatar
Benjamin Otte committed
271 272 273 274 275
  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)) {
	dec->granulepos = value;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
276 277 278
	GST_DEBUG_OBJECT (dec,
	    "setting granuleposition to %" G_GUINT64_FORMAT " after discont\n",
	    value);
Benjamin Otte's avatar
Benjamin Otte committed
279
      } else {
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
280
	GST_WARNING_OBJECT (dec,
Benjamin Otte's avatar
Benjamin Otte committed
281 282
	    "discont event didn't include offset, we might set it wrong now");
      }
283 284
      if (dec->packetno < 3) {
	if (dec->granulepos != 0)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
285 286
	  GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL),
	      ("can't handle discont before parsing first 3 packets"));
287
	dec->packetno = 0;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
288 289 290
	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)));
291 292 293
      } else {
	dec->packetno = 3;
	/* if one of them works, all of them work */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
294 295 296 297 298 299 300 301 302 303
	if (theora_dec_from_granulepos (dec, GST_FORMAT_TIME, dec->granulepos,
		&time)
	    && theora_dec_from_granulepos (dec, GST_FORMAT_DEFAULT,
		dec->granulepos, &value)
	    && theora_dec_from_granulepos (dec, GST_FORMAT_BYTES,
		dec->granulepos, &bytes)) {
	  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)));
304
	} else {
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
305 306
	  GST_ERROR_OBJECT (dec,
	      "failed to parse data for DISCONT event, not sending any");
307 308
	}
      }
Benjamin Otte's avatar
Benjamin Otte committed
309 310 311 312 313 314 315 316
      break;
    default:
      break;
  }
  gst_pad_event_default (dec->sinkpad, event);
}

static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
317
theora_dec_chain (GstPad * pad, GstData * data)
Benjamin Otte's avatar
Benjamin Otte committed
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
{
  GstBuffer *buf;
  GstTheoraDec *dec;
  ogg_packet packet;

  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);
  /* make ogg_packet out of the buffer */
  packet.packet = GST_BUFFER_DATA (buf);
  packet.bytes = GST_BUFFER_SIZE (buf);
  packet.granulepos = GST_BUFFER_OFFSET_END (buf);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
334
  packet.packetno = dec->packetno++;
335 336
  packet.b_o_s = (packet.packetno == 0) ? 1 : 0;
  packet.e_o_s = 0;
Benjamin Otte's avatar
Benjamin Otte committed
337 338 339 340
  /* switch depending on packet type */
  if (packet.packet[0] & 0x80) {
    /* header packet */
    if (theora_decode_header (&dec->info, &dec->comment, &packet)) {
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
341
      GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
Benjamin Otte's avatar
Benjamin Otte committed
342 343 344 345 346
	  (NULL), ("couldn't read header packet"));
      gst_data_unref (data);
      return;
    }
    if (packet.packetno == 1) {
347
      gchar *encoder = NULL;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
348 349 350 351
      GstTagList *list =
	  gst_tag_list_from_vorbiscomment_buffer (buf, "\201theora", 7,
	  &encoder);

352 353 354 355 356 357 358 359 360
      if (!list) {
	GST_ERROR_OBJECT (dec, "failed to parse tags");
	list = gst_tag_list_new ();
      }
      if (encoder) {
	gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
	    GST_TAG_ENCODER, encoder, NULL);
	g_free (encoder);
      }
Benjamin Otte's avatar
Benjamin Otte committed
361 362 363 364 365
      gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
	  GST_TAG_ENCODER_VERSION, dec->info.version_major, NULL);
      gst_element_found_tags_for_pad (GST_ELEMENT (dec), dec->srcpad, 0, list);
    } else if (packet.packetno == 2) {
      GstCaps *caps;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
366

Benjamin Otte's avatar
Benjamin Otte committed
367 368 369
      /* done */
      theora_decode_init (&dec->state, &dec->info);
      caps = gst_caps_new_simple ("video/x-raw-yuv",
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
370 371 372 373 374
	  "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
	  "framerate", G_TYPE_DOUBLE,
	  ((gdouble) dec->info.fps_numerator) / dec->info.fps_denominator,
	  "width", G_TYPE_INT, dec->info.width, "height", G_TYPE_INT,
	  dec->info.height, NULL);
Benjamin Otte's avatar
Benjamin Otte committed
375 376 377 378 379 380 381 382
      gst_pad_set_explicit_caps (dec->srcpad, caps);
      gst_caps_free (caps);
    }
  } else {
    yuv_buffer yuv;
    GstBuffer *out;
    guint8 *y, *v, *u;
    guint i;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
383

Benjamin Otte's avatar
Benjamin Otte committed
384
    /* normal data packet */
385 386 387 388
#if 0
    {
      GTimeVal tv;
      guint64 time;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
389

390 391 392
      g_get_current_time (&tv);
      time = GST_TIMEVAL_TO_TIME (tv);
#endif
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
      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;
      }
      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;
      }
      g_return_if_fail (yuv.y_width == dec->info.width);
      g_return_if_fail (yuv.y_height == dec->info.height);
      out = gst_pad_alloc_buffer (dec->srcpad, GST_BUFFER_OFFSET_NONE,
	  yuv.y_width * yuv.y_height * 12 / 8);
      y = GST_BUFFER_DATA (out);
      u = y + yuv.y_width * yuv.y_height;
      v = u + yuv.y_width * yuv.y_height / 4;
      for (i = 0; i < yuv.y_height; i++) {
	memcpy (y + i * yuv.y_width, yuv.y + i * yuv.y_stride, yuv.y_width);
      }
      for (i = 0; i < yuv.y_height / 2; i++) {
	memcpy (u + i * yuv.uv_width, yuv.u + i * yuv.uv_stride, yuv.uv_width);
	memcpy (v + i * yuv.uv_width, yuv.v + i * yuv.uv_stride, yuv.uv_width);
      }
      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) =
	  GST_BUFFER_OFFSET (out) * GST_BUFFER_DURATION (out);
426 427 428 429 430 431 432
#if 0
      g_get_current_time (&tv);
      time = GST_TIMEVAL_TO_TIME (tv) - time;
      if (time > 10000000)
	g_print ("w00t, you're sl0000w!! - %llu\n", time);
    }
#endif
Benjamin Otte's avatar
Benjamin Otte committed
433 434 435 436 437 438
    gst_pad_push (dec->srcpad, GST_DATA (out));
  }
  gst_data_unref (data);
}

static GstElementStateReturn
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
439
theora_dec_change_state (GstElement * element)
Benjamin Otte's avatar
Benjamin Otte committed
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
{
  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);
      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:
      g_assert_not_reached ();
      break;
  }

  return parent_class->change_state (element);
}

static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
472
plugin_init (GstPlugin * plugin)
Benjamin Otte's avatar
Benjamin Otte committed
473 474 475 476
{
  if (!gst_library_load ("gsttags"))
    return FALSE;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
477 478
  if (!gst_element_register (plugin, "theoradec", GST_RANK_SECONDARY,
	  gst_theora_dec_get_type ()))
Benjamin Otte's avatar
Benjamin Otte committed
479 480 481 482 483
    return FALSE;

  return TRUE;
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
484 485 486 487 488
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
    GST_VERSION_MINOR,
    "gsttheora",
    "Theora plugin library",
    plugin_init, VERSION, "LGPL", GST_PACKAGE, GST_ORIGIN)