gsttheoradec.c 44 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
/* 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.
 */

Wim Taymans's avatar
Wim Taymans committed
20 21 22 23 24 25 26 27
/**
 * SECTION:element-theoradec
 * @see_also: theoraenc, oggdemux
 *
 * This element decodes theora streams into raw video
 * <ulink url="http://www.theora.org/">Theora</ulink> is a royalty-free
 * video codec maintained by the <ulink url="http://www.xiph.org/">Xiph.org
 * Foundation</ulink>, based on the VP3 codec.
28 29
 *
 * <refsect2>
Wim Taymans's avatar
Wim Taymans committed
30
 * <title>Example pipeline</title>
31
 * |[
Wim Taymans's avatar
Wim Taymans committed
32
 * gst-launch -v filesrc location=videotestsrc.ogg ! oggdemux ! theoradec ! xvimagesink
33
 * ]| This example pipeline will decode an ogg stream and decodes the theora video. Refer to
Wim Taymans's avatar
Wim Taymans committed
34 35 36 37 38 39
 * the theoraenc example to create the ogg file.
 * </refsect2>
 *
 * Last reviewed on 2006-03-01 (0.10.4)
 */

Benjamin Otte's avatar
Benjamin Otte committed
40 41 42 43
#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

Wim Taymans's avatar
Wim Taymans committed
44
#include "gsttheoradec.h"
Benjamin Otte's avatar
Benjamin Otte committed
45
#include <gst/tag/tag.h>
46
#include <gst/video/video.h>
Benjamin Otte's avatar
Benjamin Otte committed
47

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
48
#define GST_CAT_DEFAULT theoradec_debug
49
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
Benjamin Otte's avatar
Benjamin Otte committed
50

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
51
#define THEORA_DEF_CROP         TRUE
52 53 54 55 56
#define THEORA_DEF_TELEMETRY_MV 0
#define THEORA_DEF_TELEMETRY_MBMODE 0
#define THEORA_DEF_TELEMETRY_QI 0
#define THEORA_DEF_TELEMETRY_BITS 0

57 58
enum
{
59
  PROP_0,
60 61 62 63 64
  PROP_CROP,
  PROP_TELEMETRY_MV,
  PROP_TELEMETRY_MBMODE,
  PROP_TELEMETRY_QI,
  PROP_TELEMETRY_BITS
65 66
};

Benjamin Otte's avatar
Benjamin Otte committed
67
static GstStaticPadTemplate theora_dec_src_factory =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
68 69 70 71
GST_STATIC_PAD_TEMPLATE ("src",
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("video/x-raw-yuv, "
72
        "format = (fourcc) { I420, Y42B, Y444 }, "
73
        "framerate = (fraction) [0/1, MAX], "
74
        "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
75
    );
Benjamin Otte's avatar
Benjamin Otte committed
76 77

static GstStaticPadTemplate theora_dec_sink_factory =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
78 79 80 81 82
GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("video/x-theora")
    );
Benjamin Otte's avatar
Benjamin Otte committed
83 84

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

86 87 88 89 90
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);

91
static gboolean theora_dec_sink_event (GstPad * pad, GstEvent * event);
92
static gboolean theora_dec_setcaps (GstPad * pad, GstCaps * caps);
93
static GstFlowReturn theora_dec_chain (GstPad * pad, GstBuffer * buffer);
94 95
static GstStateChangeReturn theora_dec_change_state (GstElement * element,
    GstStateChange transition);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
96
static gboolean theora_dec_src_event (GstPad * pad, GstEvent * event);
Wim Taymans's avatar
Wim Taymans committed
97
static gboolean theora_dec_src_query (GstPad * pad, GstQuery * query);
98 99 100
static gboolean theora_dec_src_convert (GstPad * pad,
    GstFormat src_format, gint64 src_value,
    GstFormat * dest_format, gint64 * dest_value);
Wim Taymans's avatar
Wim Taymans committed
101 102

#if 0
103
static const GstFormat *theora_get_formats (GstPad * pad);
Wim Taymans's avatar
Wim Taymans committed
104 105
#endif
#if 0
106
static const GstEventMask *theora_get_event_masks (GstPad * pad);
Wim Taymans's avatar
Wim Taymans committed
107
#endif
108
static const GstQueryType *theora_get_query_types (GstPad * pad);
Benjamin Otte's avatar
Benjamin Otte committed
109 110 111 112 113 114


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
115 116

  gst_element_class_add_pad_template (element_class,
Benjamin Otte's avatar
Benjamin Otte committed
117 118 119
      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));
120 121 122 123
  gst_element_class_set_details_simple (element_class,
      "Theora video decoder", "Codec/Decoder/Video",
      "decode raw theora streams to raw YUV video",
      "Benjamin Otte <otte@gnome.org>, Wim Taymans <wim@fluendo.com>");
Benjamin Otte's avatar
Benjamin Otte committed
124 125 126
}

static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
127
gst_theora_dec_class_init (GstTheoraDecClass * klass)
Benjamin Otte's avatar
Benjamin Otte committed
128
{
129
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Benjamin Otte's avatar
Benjamin Otte committed
130 131
  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);

132 133 134
  gobject_class->set_property = theora_dec_set_property;
  gobject_class->get_property = theora_dec_get_property;

135
  g_object_class_install_property (gobject_class, PROP_CROP,
136 137
      g_param_spec_boolean ("crop", "Crop",
          "Crop the image to the visible region", THEORA_DEF_CROP,
138
          (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
139

140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
  g_object_class_install_property (gobject_class, PROP_TELEMETRY_MV,
      g_param_spec_int ("vis-mv", "Visualise motion vectors",
          "Show motion vector selection overlaid on image. "
          "Value gives a mask for MV modes to show.",
          0, 0xffff, THEORA_DEF_TELEMETRY_MV, (GParamFlags) G_PARAM_READWRITE));

  g_object_class_install_property (gobject_class, PROP_TELEMETRY_MBMODE,
      g_param_spec_int ("vis-mbmode",
          "Visualise macroblock modes",
          "Show macroblock mode selection overlaid on image. "
          "Value gives a mask for MB modes to show.",
          0, 0xffff, THEORA_DEF_TELEMETRY_MBMODE,
          (GParamFlags) G_PARAM_READWRITE));

  g_object_class_install_property (gobject_class, PROP_TELEMETRY_QI,
      g_param_spec_int ("vis-qi",
          "Visualise adaptive quantization modes",
          "Show adaptive quantization mode selection overlaid on image. "
          "Value gives a mask for QI modes to show.",
          0, 0xffff, THEORA_DEF_TELEMETRY_QI, (GParamFlags) G_PARAM_READWRITE));

  g_object_class_install_property (gobject_class, PROP_TELEMETRY_BITS,
      g_param_spec_int ("vis-bits",
          "Visualise bitstream breakdown modes",
          "Show bitstream breakdown mode selection overlaid on image. "
          "Value gives a mask for BITS modes to show.",
          0, 0xffff, THEORA_DEF_TELEMETRY_BITS,
          (GParamFlags) G_PARAM_READWRITE));

Benjamin Otte's avatar
Benjamin Otte committed
169
  gstelement_class->change_state = theora_dec_change_state;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
170 171

  GST_DEBUG_CATEGORY_INIT (theoradec_debug, "theoradec", 0, "Theora decoder");
Benjamin Otte's avatar
Benjamin Otte committed
172 173 174
}

static void
175
gst_theora_dec_init (GstTheoraDec * dec, GstTheoraDecClass * g_class)
Benjamin Otte's avatar
Benjamin Otte committed
176
{
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
177
  dec->sinkpad =
178
      gst_pad_new_from_static_template (&theora_dec_sink_factory, "sink");
179
  gst_pad_set_event_function (dec->sinkpad, theora_dec_sink_event);
180
  gst_pad_set_setcaps_function (dec->sinkpad, theora_dec_setcaps);
Benjamin Otte's avatar
Benjamin Otte committed
181 182 183
  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
184
  dec->srcpad =
185
      gst_pad_new_from_static_template (&theora_dec_src_factory, "src");
Benjamin Otte's avatar
Benjamin Otte committed
186
  gst_pad_set_event_function (dec->srcpad, theora_dec_src_event);
187
  gst_pad_set_query_type_function (dec->srcpad, theora_get_query_types);
188
  gst_pad_set_query_function (dec->srcpad, theora_dec_src_query);
189
  gst_pad_use_fixed_caps (dec->srcpad);
190

Benjamin Otte's avatar
Benjamin Otte committed
191 192
  gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);

193
  dec->crop = THEORA_DEF_CROP;
194 195 196 197
  dec->telemetry_mv = THEORA_DEF_TELEMETRY_MV;
  dec->telemetry_mbmode = THEORA_DEF_TELEMETRY_MBMODE;
  dec->telemetry_qi = THEORA_DEF_TELEMETRY_QI;
  dec->telemetry_bits = THEORA_DEF_TELEMETRY_BITS;
198 199
  dec->gather = NULL;
  dec->decode = NULL;
200
  dec->queued = NULL;
Wim Taymans's avatar
Wim Taymans committed
201
  dec->pendingevents = NULL;
Benjamin Otte's avatar
Benjamin Otte committed
202
}
203

204 205 206 207 208
static void
gst_theora_dec_reset (GstTheoraDec * dec)
{
  dec->need_keyframe = TRUE;
  dec->last_timestamp = -1;
209 210
  dec->discont = TRUE;
  dec->frame_nr = -1;
Wim Taymans's avatar
Wim Taymans committed
211
  dec->seqnum = gst_util_seqnum_next ();
212 213
  dec->dropped = 0;
  dec->processed = 0;
214 215 216 217 218 219
  gst_segment_init (&dec->segment, GST_FORMAT_TIME);

  GST_OBJECT_LOCK (dec);
  dec->proportion = 1.0;
  dec->earliest_time = -1;
  GST_OBJECT_UNLOCK (dec);
220

221
  g_list_foreach (dec->queued, (GFunc) gst_mini_object_unref, NULL);
222 223
  g_list_free (dec->queued);
  dec->queued = NULL;
224 225 226 227 228 229
  g_list_foreach (dec->gather, (GFunc) gst_mini_object_unref, NULL);
  g_list_free (dec->gather);
  dec->gather = NULL;
  g_list_foreach (dec->decode, (GFunc) gst_mini_object_unref, NULL);
  g_list_free (dec->decode);
  dec->decode = NULL;
Wim Taymans's avatar
Wim Taymans committed
230 231 232
  g_list_foreach (dec->pendingevents, (GFunc) gst_mini_object_unref, NULL);
  g_list_free (dec->pendingevents);
  dec->pendingevents = NULL;
233 234 235 236 237

  if (dec->tags) {
    gst_tag_list_free (dec->tags);
    dec->tags = NULL;
  }
238 239
}

Wim Taymans's avatar
Wim Taymans committed
240
#if 0
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
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);
}
Wim Taymans's avatar
Wim Taymans committed
258
#endif
259

Wim Taymans's avatar
Wim Taymans committed
260
#if 0
261 262 263 264 265 266 267 268 269 270
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;
}
Wim Taymans's avatar
Wim Taymans committed
271
#endif
272 273 274 275 276 277

static const GstQueryType *
theora_get_query_types (GstPad * pad)
{
  static const GstQueryType theora_src_query_types[] = {
    GST_QUERY_POSITION,
278 279
    GST_QUERY_DURATION,
    GST_QUERY_CONVERT,
280 281 282 283 284 285 286
    0
  };

  return theora_src_query_types;
}


287
static gboolean
288 289 290
theora_dec_src_convert (GstPad * pad,
    GstFormat src_format, gint64 src_value,
    GstFormat * dest_format, gint64 * dest_value)
291
{
292 293 294 295
  gboolean res = TRUE;
  GstTheoraDec *dec;
  guint64 scale = 1;

Wim Taymans's avatar
Wim Taymans committed
296 297 298 299 300
  if (src_format == *dest_format) {
    *dest_value = src_value;
    return TRUE;
  }

301 302 303 304 305 306
  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));

  /* we need the info part before we can done something */
  if (!dec->have_header)
    goto no_header;

307 308 309 310
  switch (src_format) {
    case GST_FORMAT_BYTES:
      switch (*dest_format) {
        case GST_FORMAT_DEFAULT:
311
          *dest_value = gst_util_uint64_scale_int (src_value, 8,
312
              dec->info.pic_height * dec->info.pic_width * dec->output_bpp);
313 314 315 316 317 318 319
          break;
        case GST_FORMAT_TIME:
          /* seems like a rather silly conversion, implement me if you like */
        default:
          res = FALSE;
      }
      break;
320
    case GST_FORMAT_TIME:
321 322
      switch (*dest_format) {
        case GST_FORMAT_BYTES:
323 324 325
          scale =
              dec->output_bpp * (dec->info.pic_width * dec->info.pic_height) /
              8;
326
        case GST_FORMAT_DEFAULT:
327
          *dest_value = scale * gst_util_uint64_scale (src_value,
328
              dec->info.fps_numerator, dec->info.fps_denominator * GST_SECOND);
329 330 331 332
          break;
        default:
          res = FALSE;
      }
333 334
      break;
    case GST_FORMAT_DEFAULT:
335 336
      switch (*dest_format) {
        case GST_FORMAT_TIME:
337
          *dest_value = gst_util_uint64_scale (src_value,
338
              GST_SECOND * dec->info.fps_denominator, dec->info.fps_numerator);
339 340
          break;
        case GST_FORMAT_BYTES:
341
          *dest_value = gst_util_uint64_scale_int (src_value,
342
              dec->output_bpp * dec->info.pic_width * dec->info.pic_height, 8);
343 344 345 346
          break;
        default:
          res = FALSE;
      }
347 348
      break;
    default:
349
      res = FALSE;
350
  }
351 352
done:
  gst_object_unref (dec);
353
  return res;
354 355 356 357 358 359 360 361

  /* ERRORS */
no_header:
  {
    GST_DEBUG_OBJECT (dec, "no header yet, cannot convert");
    res = FALSE;
    goto done;
  }
362 363
}

Wim Taymans's avatar
Wim Taymans committed
364
#if 0
Benjamin Otte's avatar
Benjamin Otte committed
365
static gboolean
366 367 368
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
369
{
370 371
  gboolean res = TRUE;
  GstTheoraDec *dec;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
372

Wim Taymans's avatar
Wim Taymans committed
373 374 375 376 377
  if (src_format == *dest_format) {
    *dest_value = src_value;
    return TRUE;
  }

378 379 380 381 382 383
  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));

  /* we need the info part before we can done something */
  if (!dec->have_header)
    goto no_header;

384
  switch (src_format) {
Benjamin Otte's avatar
Benjamin Otte committed
385
    case GST_FORMAT_DEFAULT:
386 387
      switch (*dest_format) {
        case GST_FORMAT_TIME:
388
          *dest_value = _theora_granule_start_time (dec, src_value);
389 390 391 392
          break;
        default:
          res = FALSE;
      }
393
      break;
394 395 396 397
    case GST_FORMAT_TIME:
      switch (*dest_format) {
        case GST_FORMAT_DEFAULT:
        {
398
          guint rest;
399

400
          /* framecount */
401
          *dest_value = gst_util_uint64_scale (src_value,
402
              dec->info.fps_numerator, GST_SECOND * dec->info.fps_denominator);
403 404

          /* funny way of calculating granulepos in theora */
405
          rest = *dest_value / dec->info.keyframe_granule_shift;
406
          *dest_value -= rest;
407
          *dest_value <<= dec->granule_shift;
408
          *dest_value += rest;
409 410 411 412 413 414 415
          break;
        }
        default:
          res = FALSE;
          break;
      }
      break;
Benjamin Otte's avatar
Benjamin Otte committed
416
    default:
417
      res = FALSE;
Benjamin Otte's avatar
Benjamin Otte committed
418
  }
419 420
done:
  gst_object_unref (dec);
421
  return res;
422 423 424 425 426 427 428 429

  /* ERRORS */
no_header:
  {
    GST_DEBUG_OBJECT (dec, "no header yet, cannot convert");
    res = FALSE;
    goto done;
  }
Benjamin Otte's avatar
Benjamin Otte committed
430
}
Wim Taymans's avatar
Wim Taymans committed
431
#endif
432 433

static gboolean
Wim Taymans's avatar
Wim Taymans committed
434
theora_dec_src_query (GstPad * pad, GstQuery * query)
435
{
436 437
  GstTheoraDec *dec;

Wim Taymans's avatar
Wim Taymans committed
438 439
  gboolean res = FALSE;

440 441
  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));

Wim Taymans's avatar
Wim Taymans committed
442 443 444
  switch (GST_QUERY_TYPE (query)) {
    case GST_QUERY_POSITION:
    {
Wim Taymans's avatar
Wim Taymans committed
445
      gint64 value;
Wim Taymans's avatar
Wim Taymans committed
446
      GstFormat format;
Wim Taymans's avatar
Wim Taymans committed
447 448
      gint64 time;

Wim Taymans's avatar
Wim Taymans committed
449 450
      /* parse format */
      gst_query_parse_position (query, &format, NULL);
451

Wim Taymans's avatar
Wim Taymans committed
452
      time = dec->last_timestamp;
453
      time = gst_segment_to_stream_time (&dec->segment, GST_FORMAT_TIME, time);
454

455 456 457
      GST_LOG_OBJECT (dec,
          "query %p: our time: %" GST_TIME_FORMAT, query, GST_TIME_ARGS (time));

Wim Taymans's avatar
Wim Taymans committed
458
      if (!(res =
Wim Taymans's avatar
Wim Taymans committed
459 460
              theora_dec_src_convert (pad, GST_FORMAT_TIME, time, &format,
                  &value)))
Wim Taymans's avatar
Wim Taymans committed
461 462
        goto error;

Wim Taymans's avatar
Wim Taymans committed
463
      gst_query_set_position (query, format, value);
Wim Taymans's avatar
Wim Taymans committed
464 465

      GST_LOG_OBJECT (dec,
466 467
          "query %p: we return %" G_GINT64_FORMAT " (format %u)", query, value,
          format);
Wim Taymans's avatar
Wim Taymans committed
468 469
      break;
    }
Wim Taymans's avatar
Wim Taymans committed
470
    case GST_QUERY_DURATION:
471
    {
Wim Taymans's avatar
Wim Taymans committed
472
      /* forward to peer for total */
Wim Taymans's avatar
Wim Taymans committed
473
      res = gst_pad_peer_query (dec->sinkpad, query);
474
      if (!res)
Wim Taymans's avatar
Wim Taymans committed
475
        goto error;
476

Wim Taymans's avatar
Wim Taymans committed
477
      break;
478
    }
Wim Taymans's avatar
Wim Taymans committed
479 480 481 482 483 484
    case GST_QUERY_CONVERT:
    {
      GstFormat src_fmt, dest_fmt;
      gint64 src_val, dest_val;

      gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
485
      if (!(res =
Wim Taymans's avatar
Wim Taymans committed
486 487
              theora_dec_src_convert (pad, src_fmt, src_val, &dest_fmt,
                  &dest_val)))
488 489 490
        goto error;

      gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
Wim Taymans's avatar
Wim Taymans committed
491 492 493
      break;
    }
    default:
494
      res = gst_pad_query_default (pad, query);
Wim Taymans's avatar
Wim Taymans committed
495
      break;
496
  }
497 498 499
done:
  gst_object_unref (dec);

500
  return res;
501

502
  /* ERRORS */
Wim Taymans's avatar
Wim Taymans committed
503
error:
504 505 506 507
  {
    GST_DEBUG_OBJECT (dec, "query failed");
    goto done;
  }
Wim Taymans's avatar
Wim Taymans committed
508 509
}

Benjamin Otte's avatar
Benjamin Otte committed
510
static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
511
theora_dec_src_event (GstPad * pad, GstEvent * event)
Benjamin Otte's avatar
Benjamin Otte committed
512 513 514 515
{
  gboolean res = TRUE;
  GstTheoraDec *dec;

516
  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
Benjamin Otte's avatar
Benjamin Otte committed
517 518

  switch (GST_EVENT_TYPE (event)) {
519 520
    case GST_EVENT_SEEK:
    {
521 522
      GstFormat format, tformat;
      gdouble rate;
Scott Wheeler Wheeler's avatar
Scott Wheeler Wheeler committed
523
      GstEvent *real_seek;
524 525 526 527
      GstSeekFlags flags;
      GstSeekType cur_type, stop_type;
      gint64 cur, stop;
      gint64 tcur, tstop;
Wim Taymans's avatar
Wim Taymans committed
528
      guint32 seqnum;
529 530 531

      gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
          &stop_type, &stop);
Wim Taymans's avatar
Wim Taymans committed
532
      seqnum = gst_event_get_seqnum (event);
533
      gst_event_unref (event);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
534

535 536 537 538 539 540
      /* 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 
       */
541 542
      tformat = GST_FORMAT_TIME;
      if (!(res = theora_dec_src_convert (pad, format, cur, &tformat, &tcur)))
543
        goto convert_error;
544
      if (!(res = theora_dec_src_convert (pad, format, stop, &tformat, &tstop)))
545
        goto convert_error;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
546

547
      /* then seek with time on the peer */
548 549
      real_seek = gst_event_new_seek (rate, GST_FORMAT_TIME,
          flags, cur_type, tcur, stop_type, tstop);
Wim Taymans's avatar
Wim Taymans committed
550
      gst_event_set_seqnum (real_seek, seqnum);
551

552
      res = gst_pad_push_event (dec->sinkpad, real_seek);
Benjamin Otte's avatar
Benjamin Otte committed
553 554
      break;
    }
555 556 557 558 559 560 561 562 563 564
    case GST_EVENT_QOS:
    {
      gdouble proportion;
      GstClockTimeDiff diff;
      GstClockTime timestamp;

      gst_event_parse_qos (event, &proportion, &diff, &timestamp);

      /* we cannot randomly skip frame decoding since we don't have
       * B frames. we can however use the timestamp and diff to not
565 566
       * push late frames. This would at least save us the time to
       * crop/memcpy the data. */
567 568 569 570 571
      GST_OBJECT_LOCK (dec);
      dec->proportion = proportion;
      dec->earliest_time = timestamp + diff;
      GST_OBJECT_UNLOCK (dec);

572 573 574
      GST_DEBUG_OBJECT (dec, "got QoS %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
          GST_TIME_ARGS (timestamp), diff);

575
      res = gst_pad_push_event (dec->sinkpad, event);
576 577
      break;
    }
Benjamin Otte's avatar
Benjamin Otte committed
578
    default:
579
      res = gst_pad_push_event (dec->sinkpad, event);
Benjamin Otte's avatar
Benjamin Otte committed
580 581
      break;
  }
582 583
done:
  gst_object_unref (dec);
Benjamin Otte's avatar
Benjamin Otte committed
584 585

  return res;
586

587 588 589 590 591 592
  /* ERRORS */
convert_error:
  {
    GST_DEBUG_OBJECT (dec, "could not convert format");
    goto done;
  }
593 594
}

595 596
static gboolean
theora_dec_sink_event (GstPad * pad, GstEvent * event)
Benjamin Otte's avatar
Benjamin Otte committed
597
{
598
  gboolean ret = FALSE;
599 600
  GstTheoraDec *dec;

Wim Taymans's avatar
Wim Taymans committed
601
  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
602

Benjamin Otte's avatar
Benjamin Otte committed
603 604
  GST_LOG_OBJECT (dec, "handling event");
  switch (GST_EVENT_TYPE (event)) {
605 606 607 608 609 610 611
    case GST_EVENT_FLUSH_START:
      ret = gst_pad_push_event (dec->srcpad, event);
      break;
    case GST_EVENT_FLUSH_STOP:
      gst_theora_dec_reset (dec);
      ret = gst_pad_push_event (dec->srcpad, event);
      break;
Wim Taymans's avatar
Wim Taymans committed
612 613 614
    case GST_EVENT_EOS:
      ret = gst_pad_push_event (dec->srcpad, event);
      break;
615
    case GST_EVENT_NEWSEGMENT:
616
    {
617
      gboolean update;
618
      GstFormat format;
619
      gdouble rate, arate;
Wim Taymans's avatar
Wim Taymans committed
620
      gint64 start, stop, time;
621

622 623
      gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
          &start, &stop, &time);
624

625
      /* we need TIME format */
626 627 628
      if (format != GST_FORMAT_TIME)
        goto newseg_wrong_format;

629 630 631 632 633 634
      GST_DEBUG_OBJECT (dec,
          "newsegment: update %d, rate %g, arate %g, start %" GST_TIME_FORMAT
          ", stop %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT,
          update, rate, arate, GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
          GST_TIME_ARGS (time));

635
      /* now configure the values */
636 637
      gst_segment_set_newsegment_full (&dec->segment, update,
          rate, arate, format, start, stop, time);
Wim Taymans's avatar
Wim Taymans committed
638
      dec->seqnum = gst_event_get_seqnum (event);
639

Wim Taymans's avatar
Wim Taymans committed
640
      /* We don't forward this unless/until the decoder is initialised */
641 642 643
      if (dec->have_header) {
        ret = gst_pad_push_event (dec->srcpad, event);
      } else {
Wim Taymans's avatar
Wim Taymans committed
644
        dec->pendingevents = g_list_append (dec->pendingevents, event);
645 646
        ret = TRUE;
      }
Benjamin Otte's avatar
Benjamin Otte committed
647
      break;
648
    }
649 650 651 652 653 654 655 656 657 658 659 660
    case GST_EVENT_TAG:
    {
      if (dec->have_header)
        /* and forward */
        ret = gst_pad_push_event (dec->srcpad, event);
      else {
        /* store it to send once we're initialized */
        dec->pendingevents = g_list_append (dec->pendingevents, event);
        ret = TRUE;
      }
      break;
    }
Benjamin Otte's avatar
Benjamin Otte committed
661
    default:
Wim Taymans's avatar
Wim Taymans committed
662
      ret = gst_pad_push_event (dec->srcpad, event);
Benjamin Otte's avatar
Benjamin Otte committed
663 664
      break;
  }
665
done:
Wim Taymans's avatar
Wim Taymans committed
666 667
  gst_object_unref (dec);

668
  return ret;
669 670 671 672

  /* ERRORS */
newseg_wrong_format:
  {
673
    GST_DEBUG_OBJECT (dec, "received non TIME newsegment");
674
    gst_event_unref (event);
675 676
    goto done;
  }
Benjamin Otte's avatar
Benjamin Otte committed
677 678
}

679 680 681 682 683
static gboolean
theora_dec_setcaps (GstPad * pad, GstCaps * caps)
{
  GstTheoraDec *dec;
  GstStructure *s;
684
  const GValue *codec_data;
685 686 687 688 689 690 691 692 693

  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));

  s = gst_caps_get_structure (caps, 0);

  /* parse the par, this overrides the encoded par */
  dec->have_par = gst_structure_get_fraction (s, "pixel-aspect-ratio",
      &dec->par_num, &dec->par_den);

694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736
  if ((codec_data = gst_structure_get_value (s, "codec_data"))) {
    if (G_VALUE_TYPE (codec_data) == GST_TYPE_BUFFER) {
      GstBuffer *buffer;
      guint8 *data;
      guint size;
      guint offset;

      buffer = gst_value_get_buffer (codec_data);

      offset = 0;
      size = GST_BUFFER_SIZE (buffer);
      data = GST_BUFFER_DATA (buffer);

      while (size > 2) {
        guint psize;
        GstBuffer *buf;

        psize = (data[0] << 8) | data[1];
        /* skip header */
        data += 2;
        size -= 2;
        offset += 2;

        /* make sure we don't read too much */
        psize = MIN (psize, size);

        buf = gst_buffer_create_sub (buffer, offset, psize);

        /* first buffer is a discont buffer */
        if (offset == 2)
          GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);

        /* now feed it to the decoder we can ignore the error */
        theora_dec_chain (pad, buf);

        /* skip the data */
        size -= psize;
        data += psize;
        offset += psize;
      }
    }
  }

737 738 739 740 741
  gst_object_unref (dec);

  return TRUE;
}

742
static GstFlowReturn
743
theora_handle_comment_packet (GstTheoraDec * dec, ogg_packet * packet)
Benjamin Otte's avatar
Benjamin Otte committed
744
{
745
  gchar *encoder = NULL;
Benjamin Otte's avatar
Benjamin Otte committed
746
  GstBuffer *buf;
747 748
  GstTagList *list;

749
  GST_DEBUG_OBJECT (dec, "parsing comment packet");
750

751 752 753
  buf = gst_buffer_new ();
  GST_BUFFER_SIZE (buf) = packet->bytes;
  GST_BUFFER_DATA (buf) = packet->packet;
754

755 756
  list =
      gst_tag_list_from_vorbiscomment_buffer (buf, (guint8 *) "\201theora", 7,
757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773
      &encoder);

  gst_buffer_unref (buf);

  if (!list) {
    GST_ERROR_OBJECT (dec, "couldn't decode comments");
    list = gst_tag_list_new ();
  }
  if (encoder) {
    gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
        GST_TAG_ENCODER, encoder, NULL);
    g_free (encoder);
  }
  gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
      GST_TAG_ENCODER_VERSION, dec->info.version_major,
      GST_TAG_VIDEO_CODEC, "Theora", NULL);

774 775 776 777 778 779
  if (dec->info.target_bitrate > 0) {
    gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
        GST_TAG_BITRATE, dec->info.target_bitrate,
        GST_TAG_NOMINAL_BITRATE, dec->info.target_bitrate, NULL);
  }

780
  dec->tags = list;
781 782 783 784 785 786 787 788 789

  return GST_FLOW_OK;
}

static GstFlowReturn
theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet)
{
  GstCaps *caps;
  gint par_num, par_den;
790
  GstFlowReturn ret = GST_FLOW_OK;
Wim Taymans's avatar
Wim Taymans committed
791
  GList *walk;
792
  guint32 fourcc;
793 794 795 796 797 798 799

  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;
800
   * 0:x and x:0 are allowed and can be interpreted as 1:1.
801
   */
802 803 804 805 806 807 808 809 810 811
  if (dec->have_par) {
    /* we had a par on the sink caps, override the encoded par */
    GST_DEBUG_OBJECT (dec, "overriding with input PAR");
    par_num = dec->par_num;
    par_den = dec->par_den;
  } else {
    /* take encoded par */
    par_num = dec->info.aspect_numerator;
    par_den = dec->info.aspect_denominator;
  }
812
  if (par_num == 0 || par_den == 0) {
813 814 815 816 817
    par_num = par_den = 1;
  }
  /* theora has:
   *
   *  width/height : dimension of the encoded frame 
818 819
   *  pic_width/pic_height : dimension of the visible part
   *  pic_x/pic_y : offset in encoded frame where visible part starts
820
   */
821 822
  GST_DEBUG_OBJECT (dec, "dimension %dx%d, PAR %d/%d", dec->info.pic_width,
      dec->info.pic_height, par_num, par_den);
823
  GST_DEBUG_OBJECT (dec, "frame dimension %dx%d, offset %d:%d",
824 825
      dec->info.pic_width, dec->info.pic_height,
      dec->info.pic_x, dec->info.pic_y);
826

827
  if (dec->info.pixel_fmt == TH_PF_420) {
828 829
    dec->output_bpp = 12;       /* Average bits per pixel. */
    fourcc = GST_MAKE_FOURCC ('I', '4', '2', '0');
830
  } else if (dec->info.pixel_fmt == TH_PF_422) {
831
    dec->output_bpp = 16;
832
    fourcc = GST_MAKE_FOURCC ('Y', '4', '2', 'B');
833
  } else if (dec->info.pixel_fmt == TH_PF_444) {
834 835 836
    dec->output_bpp = 24;
    fourcc = GST_MAKE_FOURCC ('Y', '4', '4', '4');
  } else {
837
    GST_ERROR_OBJECT (dec, "Invalid pixel format %d", dec->info.pixel_fmt);
838 839
    return GST_FLOW_ERROR;
  }
840 841

  if (dec->crop) {
842 843
    dec->width = dec->info.pic_width;
    dec->height = dec->info.pic_height;
844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860
    dec->offset_x = dec->info.pic_x;
    dec->offset_y = dec->info.pic_y;
    /* Ensure correct offsets in chroma for formats that need it
     * by rounding the offset. libtheora will add proper pixels,
     * so no need to handle them ourselves. */
    if (dec->offset_x & 1 && dec->info.pixel_fmt != TH_PF_444) {
      dec->offset_x--;
      dec->width++;
    }
    if (dec->offset_y & 1 && dec->info.pixel_fmt == TH_PF_420) {
      dec->offset_y--;
      dec->height++;
    }
  } else {
    /* no cropping, use the encoded dimensions */
    dec->width = dec->info.frame_width;
    dec->height = dec->info.frame_height;
861 862 863 864 865 866 867 868
    dec->offset_x = 0;
    dec->offset_y = 0;
  }

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

  /* done */
869
  dec->decoder = th_decode_alloc (&dec->info, dec->setup);
870

871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886
  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_MV,
          &dec->telemetry_mv, sizeof (dec->telemetry_mv)))
    GST_WARNING_OBJECT (dec, "Could not enable MV visualisation");

  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_MBMODE,
          &dec->telemetry_mbmode, sizeof (dec->telemetry_mbmode)))
    GST_WARNING_OBJECT (dec, "Could not enable MB mode visualisation");

  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_QI,
          &dec->telemetry_qi, sizeof (dec->telemetry_qi)))
    GST_WARNING_OBJECT (dec, "Could not enable QI mode visualisation");

  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_BITS,
          &dec->telemetry_bits, sizeof (dec->telemetry_bits)))
    GST_WARNING_OBJECT (dec, "Could not enable BITS mode visualisation");

887
  caps = gst_caps_new_simple ("video/x-raw-yuv",
888
      "format", GST_TYPE_FOURCC, fourcc,
889 890
      "framerate", GST_TYPE_FRACTION,
      dec->info.fps_numerator, dec->info.fps_denominator,
891
      "pixel-aspect-ratio", GST_TYPE_FRACTION, par_num, par_den,
892
      "width", G_TYPE_INT, dec->width, "height", G_TYPE_INT, dec->height,
893 894
      "color-matrix", G_TYPE_STRING, "sdtv",
      "chroma-site", G_TYPE_STRING, "jpeg", NULL);
895 896 897
  gst_pad_set_caps (dec->srcpad, caps);
  gst_caps_unref (caps);

Wim Taymans's avatar
Wim Taymans committed
898
  dec->have_header = TRUE;
Wim Taymans's avatar
Wim Taymans committed
899 900 901 902 903 904

  if (dec->pendingevents) {
    for (walk = dec->pendingevents; walk; walk = g_list_next (walk))
      gst_pad_push_event (dec->srcpad, GST_EVENT_CAST (walk->data));
    g_list_free (dec->pendingevents);
    dec->pendingevents = NULL;
905
  }
906

907 908 909 910 911 912 913
  if (dec->tags) {
    gst_element_found_tags_for_pad (GST_ELEMENT_CAST (dec), dec->srcpad,
        dec->tags);
    dec->tags = NULL;
  }

  return ret;
914 915 916 917 918 919
}

static GstFlowReturn
theora_handle_header_packet (GstTheoraDec * dec, ogg_packet * packet)
{
  GstFlowReturn res;
920
  int ret;
921

922
  GST_DEBUG_OBJECT (dec, "parsing header packet");
923

924 925
  ret = th_decode_headerin (&dec->info, &dec->comment, &dec->setup, packet);
  if (ret < 0)
926 927
    goto header_read_error;

Wim Taymans's avatar
Wim Taymans committed
928 929
  switch (packet->packet[0]) {
    case 0x81:
930 931
      res = theora_handle_comment_packet (dec, packet);
      break;
Wim Taymans's avatar
Wim Taymans committed
932
    case 0x82:
933 934 935 936
      res = theora_handle_type_packet (dec, packet);
      break;
    default:
      /* ignore */
Wim Taymans's avatar
Wim Taymans committed
937 938 939
      g_warning ("unknown theora header packet found");
    case 0x80:
      /* nothing special, this is the identification header */
940 941 942 943 944 945 946 947 948 949 950 951 952 953
      res = GST_FLOW_OK;
      break;
  }
  return res;

  /* ERRORS */
header_read_error:
  {
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
        (NULL), ("couldn't read header packet"));
    return GST_FLOW_ERROR;
  }
}

954 955 956 957 958
/* returns TRUE if buffer is within segment, else FALSE.
 * if Buffer is on segment border, it's timestamp and duration will be clipped */
static gboolean
clip_buffer (GstTheoraDec * dec, GstBuffer * buf)
{
959 960
  gboolean res = TRUE;
  GstClockTime in_ts, in_dur, stop;
961 962
  gint64 cstart, cstop;

963 964 965
  in_ts = GST_BUFFER_TIMESTAMP (buf);
  in_dur = GST_BUFFER_DURATION (buf);

966 967
  GST_LOG_OBJECT (dec,
      "timestamp:%" GST_TIME_FORMAT " , duration:%" GST_TIME_FORMAT,
968
      GST_TIME_ARGS (in_ts), GST_TIME_ARGS (in_dur));
969

970 971
  /* can't clip without TIME segment */
  if (dec->segment.format != GST_FORMAT_TIME)
972 973
    goto beach;

974 975 976 977 978 979 980 981 982 983 984
  /* we need a start time */
  if (!GST_CLOCK_TIME_IS_VALID (in_ts))
    goto beach;

  /* generate valid stop, if duration unknown, we have unknown stop */
  stop =
      GST_CLOCK_TIME_IS_VALID (in_dur) ? (in_ts + in_dur) : GST_CLOCK_TIME_NONE;

  /* now clip */
  if (!(res = gst_segment_clip (&dec->segment, GST_FORMAT_TIME,
              in_ts, stop, &cstart, &cstop)))
985 986
    goto beach;

987 988
  /* update timestamp and possibly duration if the clipped stop time is
   * valid */
989
  GST_BUFFER_TIMESTAMP (buf) = cstart;
990 991
  if (GST_CLOCK_TIME_IS_VALID (cstop))
    GST_BUFFER_DURATION (buf) = cstop - cstart;
992 993

beach:
994
  GST_LOG_OBJECT (dec, "%sdropping", (res ? "not " : ""));
995 996 997
  return res;
}

998
static GstFlowReturn
999
theora_dec_push_forward (GstTheoraDec * dec, GstBuffer * buf)
1000
{
1001
  GstFlowReturn result = GST_FLOW_OK;
1002

Wim Taymans's avatar
Wim Taymans committed
1003