gsttheoradec.c 46.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
/* 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 85
#define gst_theora_dec_parent_class parent_class
G_DEFINE_TYPE (GstTheoraDec, gst_theora_dec, GST_TYPE_ELEMENT);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
86

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

92
static gboolean theora_dec_sink_event (GstPad * pad, GstEvent * event);
93
static gboolean theora_dec_setcaps (GstPad * pad, GstCaps * caps);
94
static GstFlowReturn theora_dec_chain (GstPad * pad, GstBuffer * buffer);
95 96
static GstStateChangeReturn theora_dec_change_state (GstElement * element,
    GstStateChange transition);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
97
static gboolean theora_dec_src_event (GstPad * pad, GstEvent * event);
Wim Taymans's avatar
Wim Taymans committed
98
static gboolean theora_dec_src_query (GstPad * pad, GstQuery ** query);
99 100 101
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
102 103

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

111 112 113 114 115 116 117
static gboolean
gst_theora_dec_ctl_is_supported (int req)
{
  /* should return TH_EFAULT or TH_EINVAL if supported, and TH_EIMPL if not */
  return (th_decode_ctl (NULL, req, NULL, 0) != TH_EIMPL);
}

Benjamin Otte's avatar
Benjamin Otte committed
118
static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
119
gst_theora_dec_class_init (GstTheoraDecClass * klass)
Benjamin Otte's avatar
Benjamin Otte committed
120
{
121
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Benjamin Otte's avatar
Benjamin Otte committed
122 123
  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);

124 125 126
  gobject_class->set_property = theora_dec_set_property;
  gobject_class->get_property = theora_dec_get_property;

127
  g_object_class_install_property (gobject_class, PROP_CROP,
128 129
      g_param_spec_boolean ("crop", "Crop",
          "Crop the image to the visible region", THEORA_DEF_CROP,
130
          (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
131

132 133 134 135 136 137 138 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 169 170 171 172 173 174
  if (gst_theora_dec_ctl_is_supported (TH_DECCTL_SET_TELEMETRY_MV)) {
    g_object_class_install_property (gobject_class, PROP_TELEMETRY_MV,
        g_param_spec_int ("visualize-motion-vectors",
            "Visualize motion vectors",
            "Show motion vector selection overlaid on image. "
            "Value gives a mask for motion vector (MV) modes to show",
            0, 0xffff, THEORA_DEF_TELEMETRY_MV,
            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  }

  if (gst_theora_dec_ctl_is_supported (TH_DECCTL_SET_TELEMETRY_MBMODE)) {
    g_object_class_install_property (gobject_class, PROP_TELEMETRY_MBMODE,
        g_param_spec_int ("visualize-macroblock-modes",
            "Visualize macroblock modes",
            "Show macroblock mode selection overlaid on image. "
            "Value gives a mask for macroblock (MB) modes to show",
            0, 0xffff, THEORA_DEF_TELEMETRY_MBMODE,
            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  }

  if (gst_theora_dec_ctl_is_supported (TH_DECCTL_SET_TELEMETRY_QI)) {
    g_object_class_install_property (gobject_class, PROP_TELEMETRY_QI,
        g_param_spec_int ("visualize-quantization-modes",
            "Visualize adaptive quantization modes",
            "Show adaptive quantization mode selection overlaid on image. "
            "Value gives a mask for quantization (QI) modes to show",
            0, 0xffff, THEORA_DEF_TELEMETRY_QI,
            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  }

  if (gst_theora_dec_ctl_is_supported (TH_DECCTL_SET_TELEMETRY_BITS)) {
    /* FIXME: make this a boolean instead? The value scales the bars so
     * they're less wide. Default is to use full width, and anything else
     * doesn't seem particularly useful, since the smaller bars just disappear
     * then (they almost disappear for a value of 2 already). */
    g_object_class_install_property (gobject_class, PROP_TELEMETRY_BITS,
        g_param_spec_int ("visualize-bit-usage",
            "Visualize bitstream usage breakdown",
            "Sets the bitstream breakdown visualization mode. "
            "Values influence the width of the bit usage bars to show",
            0, 0xff, THEORA_DEF_TELEMETRY_BITS,
            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  }
175

176 177 178 179 180 181 182 183 184
  gst_element_class_add_pad_template (gstelement_class,
      gst_static_pad_template_get (&theora_dec_src_factory));
  gst_element_class_add_pad_template (gstelement_class,
      gst_static_pad_template_get (&theora_dec_sink_factory));
  gst_element_class_set_details_simple (gstelement_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
185
  gstelement_class->change_state = theora_dec_change_state;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
186 187

  GST_DEBUG_CATEGORY_INIT (theoradec_debug, "theoradec", 0, "Theora decoder");
Benjamin Otte's avatar
Benjamin Otte committed
188 189 190
}

static void
191
gst_theora_dec_init (GstTheoraDec * dec)
Benjamin Otte's avatar
Benjamin Otte committed
192
{
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
193
  dec->sinkpad =
194
      gst_pad_new_from_static_template (&theora_dec_sink_factory, "sink");
195
  gst_pad_set_event_function (dec->sinkpad, theora_dec_sink_event);
196
  gst_pad_set_setcaps_function (dec->sinkpad, theora_dec_setcaps);
Benjamin Otte's avatar
Benjamin Otte committed
197 198 199
  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
200
  dec->srcpad =
201
      gst_pad_new_from_static_template (&theora_dec_src_factory, "src");
Benjamin Otte's avatar
Benjamin Otte committed
202
  gst_pad_set_event_function (dec->srcpad, theora_dec_src_event);
203
  gst_pad_set_query_type_function (dec->srcpad, theora_get_query_types);
204
  gst_pad_set_query_function (dec->srcpad, theora_dec_src_query);
205
  gst_pad_use_fixed_caps (dec->srcpad);
206

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

209
  dec->crop = THEORA_DEF_CROP;
210 211 212 213
  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;
214 215
  dec->gather = NULL;
  dec->decode = NULL;
216
  dec->queued = NULL;
Wim Taymans's avatar
Wim Taymans committed
217
  dec->pendingevents = NULL;
Benjamin Otte's avatar
Benjamin Otte committed
218
}
219

220 221 222 223 224
static void
gst_theora_dec_reset (GstTheoraDec * dec)
{
  dec->need_keyframe = TRUE;
  dec->last_timestamp = -1;
225 226
  dec->discont = TRUE;
  dec->frame_nr = -1;
Wim Taymans's avatar
Wim Taymans committed
227
  dec->seqnum = gst_util_seqnum_next ();
228 229
  dec->dropped = 0;
  dec->processed = 0;
230 231 232 233 234 235
  gst_segment_init (&dec->segment, GST_FORMAT_TIME);

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

237
  g_list_foreach (dec->queued, (GFunc) gst_mini_object_unref, NULL);
238 239
  g_list_free (dec->queued);
  dec->queued = NULL;
240 241 242 243 244 245
  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
246 247 248
  g_list_foreach (dec->pendingevents, (GFunc) gst_mini_object_unref, NULL);
  g_list_free (dec->pendingevents);
  dec->pendingevents = NULL;
249 250 251 252 253

  if (dec->tags) {
    gst_tag_list_free (dec->tags);
    dec->tags = NULL;
  }
254 255
}

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

Wim Taymans's avatar
Wim Taymans committed
276
#if 0
277 278 279 280 281 282 283 284 285 286
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
287
#endif
288 289 290 291 292 293

static const GstQueryType *
theora_get_query_types (GstPad * pad)
{
  static const GstQueryType theora_src_query_types[] = {
    GST_QUERY_POSITION,
294 295
    GST_QUERY_DURATION,
    GST_QUERY_CONVERT,
296 297 298 299 300 301 302
    0
  };

  return theora_src_query_types;
}


303
static gboolean
304 305 306
theora_dec_src_convert (GstPad * pad,
    GstFormat src_format, gint64 src_value,
    GstFormat * dest_format, gint64 * dest_value)
307
{
308 309 310 311
  gboolean res = TRUE;
  GstTheoraDec *dec;
  guint64 scale = 1;

Wim Taymans's avatar
Wim Taymans committed
312 313 314 315 316
  if (src_format == *dest_format) {
    *dest_value = src_value;
    return TRUE;
  }

317 318 319 320 321 322
  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;

323 324 325 326
  switch (src_format) {
    case GST_FORMAT_BYTES:
      switch (*dest_format) {
        case GST_FORMAT_DEFAULT:
327
          *dest_value = gst_util_uint64_scale_int (src_value, 8,
328
              dec->info.pic_height * dec->info.pic_width * dec->output_bpp);
329 330 331 332 333 334 335
          break;
        case GST_FORMAT_TIME:
          /* seems like a rather silly conversion, implement me if you like */
        default:
          res = FALSE;
      }
      break;
336
    case GST_FORMAT_TIME:
337 338
      switch (*dest_format) {
        case GST_FORMAT_BYTES:
339 340 341
          scale =
              dec->output_bpp * (dec->info.pic_width * dec->info.pic_height) /
              8;
342
        case GST_FORMAT_DEFAULT:
343
          *dest_value = scale * gst_util_uint64_scale (src_value,
344
              dec->info.fps_numerator, dec->info.fps_denominator * GST_SECOND);
345 346 347 348
          break;
        default:
          res = FALSE;
      }
349 350
      break;
    case GST_FORMAT_DEFAULT:
351 352
      switch (*dest_format) {
        case GST_FORMAT_TIME:
353
          *dest_value = gst_util_uint64_scale (src_value,
354
              GST_SECOND * dec->info.fps_denominator, dec->info.fps_numerator);
355 356
          break;
        case GST_FORMAT_BYTES:
357
          *dest_value = gst_util_uint64_scale_int (src_value,
358
              dec->output_bpp * dec->info.pic_width * dec->info.pic_height, 8);
359 360 361 362
          break;
        default:
          res = FALSE;
      }
363 364
      break;
    default:
365
      res = FALSE;
366
  }
367 368
done:
  gst_object_unref (dec);
369
  return res;
370 371 372 373 374 375 376 377

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

Wim Taymans's avatar
Wim Taymans committed
380
#if 0
Benjamin Otte's avatar
Benjamin Otte committed
381
static gboolean
382 383 384
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
385
{
386 387
  gboolean res = TRUE;
  GstTheoraDec *dec;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
388

Wim Taymans's avatar
Wim Taymans committed
389 390 391 392 393
  if (src_format == *dest_format) {
    *dest_value = src_value;
    return TRUE;
  }

394 395 396 397 398 399
  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;

400
  switch (src_format) {
Benjamin Otte's avatar
Benjamin Otte committed
401
    case GST_FORMAT_DEFAULT:
402 403
      switch (*dest_format) {
        case GST_FORMAT_TIME:
404
          *dest_value = _theora_granule_start_time (dec, src_value);
405 406 407 408
          break;
        default:
          res = FALSE;
      }
409
      break;
410 411 412 413
    case GST_FORMAT_TIME:
      switch (*dest_format) {
        case GST_FORMAT_DEFAULT:
        {
414
          guint rest;
415

416
          /* framecount */
417
          *dest_value = gst_util_uint64_scale (src_value,
418
              dec->info.fps_numerator, GST_SECOND * dec->info.fps_denominator);
419 420

          /* funny way of calculating granulepos in theora */
421
          rest = *dest_value / dec->info.keyframe_granule_shift;
422
          *dest_value -= rest;
423
          *dest_value <<= dec->granule_shift;
424
          *dest_value += rest;
425 426 427 428 429 430 431
          break;
        }
        default:
          res = FALSE;
          break;
      }
      break;
Benjamin Otte's avatar
Benjamin Otte committed
432
    default:
433
      res = FALSE;
Benjamin Otte's avatar
Benjamin Otte committed
434
  }
435 436
done:
  gst_object_unref (dec);
437
  return res;
438 439 440 441 442 443 444 445

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

static gboolean
Wim Taymans's avatar
Wim Taymans committed
450
theora_dec_src_query (GstPad * pad, GstQuery ** query)
451
{
452 453
  GstTheoraDec *dec;

Wim Taymans's avatar
Wim Taymans committed
454 455
  gboolean res = FALSE;

456 457
  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));

Wim Taymans's avatar
Wim Taymans committed
458
  switch (GST_QUERY_TYPE (*query)) {
Wim Taymans's avatar
Wim Taymans committed
459 460
    case GST_QUERY_POSITION:
    {
Wim Taymans's avatar
Wim Taymans committed
461
      gint64 value;
Wim Taymans's avatar
Wim Taymans committed
462
      GstFormat format;
Wim Taymans's avatar
Wim Taymans committed
463 464
      gint64 time;

Wim Taymans's avatar
Wim Taymans committed
465
      /* parse format */
Wim Taymans's avatar
Wim Taymans committed
466
      gst_query_parse_position (*query, &format, NULL);
467

Wim Taymans's avatar
Wim Taymans committed
468
      time = dec->last_timestamp;
469
      time = gst_segment_to_stream_time (&dec->segment, GST_FORMAT_TIME, time);
470

471
      GST_LOG_OBJECT (dec,
Wim Taymans's avatar
Wim Taymans committed
472 473
          "query %p: our time: %" GST_TIME_FORMAT, *query,
          GST_TIME_ARGS (time));
474

Wim Taymans's avatar
Wim Taymans committed
475
      if (!(res =
Wim Taymans's avatar
Wim Taymans committed
476 477
              theora_dec_src_convert (pad, GST_FORMAT_TIME, time, &format,
                  &value)))
Wim Taymans's avatar
Wim Taymans committed
478 479
        goto error;

Wim Taymans's avatar
Wim Taymans committed
480
      gst_query_set_position (*query, format, value);
Wim Taymans's avatar
Wim Taymans committed
481 482

      GST_LOG_OBJECT (dec,
Wim Taymans's avatar
Wim Taymans committed
483
          "query %p: we return %" G_GINT64_FORMAT " (format %u)", *query, value,
484
          format);
Wim Taymans's avatar
Wim Taymans committed
485 486
      break;
    }
Wim Taymans's avatar
Wim Taymans committed
487
    case GST_QUERY_DURATION:
488
    {
Wim Taymans's avatar
Wim Taymans committed
489
      /* forward to peer for total */
Wim Taymans's avatar
Wim Taymans committed
490
      res = gst_pad_peer_query (dec->sinkpad, query);
491
      if (!res)
Wim Taymans's avatar
Wim Taymans committed
492
        goto error;
493

Wim Taymans's avatar
Wim Taymans committed
494
      break;
495
    }
Wim Taymans's avatar
Wim Taymans committed
496 497 498 499 500
    case GST_QUERY_CONVERT:
    {
      GstFormat src_fmt, dest_fmt;
      gint64 src_val, dest_val;

Wim Taymans's avatar
Wim Taymans committed
501 502
      gst_query_parse_convert (*query, &src_fmt, &src_val, &dest_fmt,
          &dest_val);
503
      if (!(res =
Wim Taymans's avatar
Wim Taymans committed
504 505
              theora_dec_src_convert (pad, src_fmt, src_val, &dest_fmt,
                  &dest_val)))
506 507
        goto error;

Wim Taymans's avatar
Wim Taymans committed
508
      gst_query_set_convert (*query, src_fmt, src_val, dest_fmt, dest_val);
Wim Taymans's avatar
Wim Taymans committed
509 510 511
      break;
    }
    default:
512
      res = gst_pad_query_default (pad, query);
Wim Taymans's avatar
Wim Taymans committed
513
      break;
514
  }
515 516 517
done:
  gst_object_unref (dec);

518
  return res;
519

520
  /* ERRORS */
Wim Taymans's avatar
Wim Taymans committed
521
error:
522 523 524 525
  {
    GST_DEBUG_OBJECT (dec, "query failed");
    goto done;
  }
Wim Taymans's avatar
Wim Taymans committed
526 527
}

Benjamin Otte's avatar
Benjamin Otte committed
528
static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
529
theora_dec_src_event (GstPad * pad, GstEvent * event)
Benjamin Otte's avatar
Benjamin Otte committed
530 531 532 533
{
  gboolean res = TRUE;
  GstTheoraDec *dec;

534
  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
Benjamin Otte's avatar
Benjamin Otte committed
535 536

  switch (GST_EVENT_TYPE (event)) {
537 538
    case GST_EVENT_SEEK:
    {
539 540
      GstFormat format, tformat;
      gdouble rate;
Scott Wheeler Wheeler's avatar
Scott Wheeler Wheeler committed
541
      GstEvent *real_seek;
542 543 544 545
      GstSeekFlags flags;
      GstSeekType cur_type, stop_type;
      gint64 cur, stop;
      gint64 tcur, tstop;
Wim Taymans's avatar
Wim Taymans committed
546
      guint32 seqnum;
547 548 549

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

553 554 555 556 557 558
      /* 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 
       */
559 560
      tformat = GST_FORMAT_TIME;
      if (!(res = theora_dec_src_convert (pad, format, cur, &tformat, &tcur)))
561
        goto convert_error;
562
      if (!(res = theora_dec_src_convert (pad, format, stop, &tformat, &tstop)))
563
        goto convert_error;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
564

565
      /* then seek with time on the peer */
566 567
      real_seek = gst_event_new_seek (rate, GST_FORMAT_TIME,
          flags, cur_type, tcur, stop_type, tstop);
Wim Taymans's avatar
Wim Taymans committed
568
      gst_event_set_seqnum (real_seek, seqnum);
569

570
      res = gst_pad_push_event (dec->sinkpad, real_seek);
Benjamin Otte's avatar
Benjamin Otte committed
571 572
      break;
    }
573 574 575 576 577 578
    case GST_EVENT_QOS:
    {
      gdouble proportion;
      GstClockTimeDiff diff;
      GstClockTime timestamp;

Wim Taymans's avatar
Wim Taymans committed
579
      gst_event_parse_qos (event, NULL, &proportion, &diff, &timestamp);
580 581 582

      /* we cannot randomly skip frame decoding since we don't have
       * B frames. we can however use the timestamp and diff to not
583 584
       * push late frames. This would at least save us the time to
       * crop/memcpy the data. */
585 586 587 588 589
      GST_OBJECT_LOCK (dec);
      dec->proportion = proportion;
      dec->earliest_time = timestamp + diff;
      GST_OBJECT_UNLOCK (dec);

590 591 592
      GST_DEBUG_OBJECT (dec, "got QoS %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
          GST_TIME_ARGS (timestamp), diff);

593
      res = gst_pad_push_event (dec->sinkpad, event);
594 595
      break;
    }
Benjamin Otte's avatar
Benjamin Otte committed
596
    default:
597
      res = gst_pad_push_event (dec->sinkpad, event);
Benjamin Otte's avatar
Benjamin Otte committed
598 599
      break;
  }
600 601
done:
  gst_object_unref (dec);
Benjamin Otte's avatar
Benjamin Otte committed
602 603

  return res;
604

605 606 607 608 609 610
  /* ERRORS */
convert_error:
  {
    GST_DEBUG_OBJECT (dec, "could not convert format");
    goto done;
  }
611 612
}

613 614
static gboolean
theora_dec_sink_event (GstPad * pad, GstEvent * event)
Benjamin Otte's avatar
Benjamin Otte committed
615
{
616
  gboolean ret = FALSE;
617 618
  GstTheoraDec *dec;

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

Benjamin Otte's avatar
Benjamin Otte committed
621 622
  GST_LOG_OBJECT (dec, "handling event");
  switch (GST_EVENT_TYPE (event)) {
623 624 625 626 627 628 629
    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
630 631 632
    case GST_EVENT_EOS:
      ret = gst_pad_push_event (dec->srcpad, event);
      break;
633
    case GST_EVENT_NEWSEGMENT:
634
    {
635
      gboolean update;
636
      GstFormat format;
637
      gdouble rate, arate;
Wim Taymans's avatar
Wim Taymans committed
638
      gint64 start, stop, time;
639

Wim Taymans's avatar
Wim Taymans committed
640
      gst_event_parse_new_segment (event, &update, &rate, &arate, &format,
641
          &start, &stop, &time);
642

643
      /* we need TIME format */
644 645 646
      if (format != GST_FORMAT_TIME)
        goto newseg_wrong_format;

647 648 649 650 651 652
      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));

653
      /* now configure the values */
Wim Taymans's avatar
Wim Taymans committed
654
      gst_segment_set_newsegment (&dec->segment, update,
655
          rate, arate, format, start, stop, time);
Wim Taymans's avatar
Wim Taymans committed
656
      dec->seqnum = gst_event_get_seqnum (event);
657

Wim Taymans's avatar
Wim Taymans committed
658
      /* We don't forward this unless/until the decoder is initialised */
659 660 661
      if (dec->have_header) {
        ret = gst_pad_push_event (dec->srcpad, event);
      } else {
Wim Taymans's avatar
Wim Taymans committed
662
        dec->pendingevents = g_list_append (dec->pendingevents, event);
663 664
        ret = TRUE;
      }
Benjamin Otte's avatar
Benjamin Otte committed
665
      break;
666
    }
667 668 669 670 671 672 673 674 675 676 677 678
    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
679
    default:
680
      ret = gst_pad_event_default (pad, event);
Benjamin Otte's avatar
Benjamin Otte committed
681 682
      break;
  }
683
done:
Wim Taymans's avatar
Wim Taymans committed
684 685
  gst_object_unref (dec);

686
  return ret;
687 688 689 690

  /* ERRORS */
newseg_wrong_format:
  {
691
    GST_DEBUG_OBJECT (dec, "received non TIME newsegment");
692
    gst_event_unref (event);
693 694
    goto done;
  }
Benjamin Otte's avatar
Benjamin Otte committed
695 696
}

697 698 699 700 701
static gboolean
theora_dec_setcaps (GstPad * pad, GstCaps * caps)
{
  GstTheoraDec *dec;
  GstStructure *s;
702
  const GValue *codec_data;
703 704 705 706 707 708 709 710 711

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

712 713 714
  if ((codec_data = gst_structure_get_value (s, "codec_data"))) {
    if (G_VALUE_TYPE (codec_data) == GST_TYPE_BUFFER) {
      GstBuffer *buffer;
715 716
      guint8 *data, *ptr;
      gsize size, left;
717 718 719 720 721
      guint offset;

      buffer = gst_value_get_buffer (codec_data);

      offset = 0;
722
      data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
723

724 725 726 727
      ptr = data;
      left = size;

      while (left > 2) {
728 729 730
        guint psize;
        GstBuffer *buf;

731
        psize = (ptr[0] << 8) | ptr[1];
732
        /* skip header */
733 734
        ptr += 2;
        left -= 2;
735 736 737
        offset += 2;

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

Wim Taymans's avatar
Wim Taymans committed
740 741
        buf =
            gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset, psize);
742 743 744 745 746 747 748 749 750

        /* 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 */
751 752
        left -= psize;
        ptr += psize;
753 754
        offset += psize;
      }
755
      gst_buffer_unmap (buffer, data, size);
756 757 758
    }
  }

759 760 761 762 763
  gst_object_unref (dec);

  return TRUE;
}

764
static GstFlowReturn
765
theora_handle_comment_packet (GstTheoraDec * dec, ogg_packet * packet)
Benjamin Otte's avatar
Benjamin Otte committed
766
{
767 768 769
  gchar *encoder = NULL;
  GstTagList *list;

770
  GST_DEBUG_OBJECT (dec, "parsing comment packet");
771

772
  list =
773 774
      gst_tag_list_from_vorbiscomment (packet->packet, packet->bytes,
      (guint8 *) "\201theora", 7, &encoder);
775 776 777 778 779 780 781 782 783 784 785 786 787 788

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

789 790 791 792 793 794
  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);
  }

795
  dec->tags = list;
796 797 798 799

  return GST_FLOW_OK;
}

Wim Taymans's avatar
Wim Taymans committed
800 801 802 803 804
static GstFlowReturn
theora_negotiate_pool (GstTheoraDec * dec, GstCaps * caps)
{
  GstQuery *query;
  GstBufferPool *pool = NULL;
805
  guint size, min, max, prefix, alignment;
Wim Taymans's avatar
Wim Taymans committed
806 807 808 809

  /* find a pool for the negotiated caps now */
  query = gst_query_new_allocation (caps, TRUE);

Wim Taymans's avatar
Wim Taymans committed
810
  if (gst_pad_peer_query (dec->srcpad, &query)) {
Wim Taymans's avatar
Wim Taymans committed
811 812
    GST_DEBUG_OBJECT (dec, "got downstream ALLOCATION hints");
    /* we got configuration from our peer, parse them */
813 814
    gst_query_parse_allocation_params (query, &size, &min, &max, &prefix,
        &alignment, &pool);
Wim Taymans's avatar
Wim Taymans committed
815 816 817
  } else {
    GST_DEBUG_OBJECT (dec, "didn't get downstream ALLOCATION hints");
    size = gst_video_format_get_size (dec->format, dec->width, dec->height);
818 819 820
    min = max = 0;
    prefix = 0;
    alignment = 1;
Wim Taymans's avatar
Wim Taymans committed
821
  }
Wim Taymans's avatar
Wim Taymans committed
822
  gst_query_unref (query);
Wim Taymans's avatar
Wim Taymans committed
823 824 825 826 827 828 829 830

  if (pool == NULL) {
    GstStructure *config;

    /* we did not get a pool, make one ourselves then */
    pool = gst_buffer_pool_new ();

    config = gst_buffer_pool_get_config (pool);
831 832
    gst_buffer_pool_config_set (config, caps, size, min, max, prefix, 0,
        alignment);
Wim Taymans's avatar
Wim Taymans committed
833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848
    gst_buffer_pool_set_config (pool, config);
  }

  if (dec->pool)
    gst_object_unref (dec->pool);
  dec->pool = pool;

  /* FIXME, we can check if downstream supports clipping and/or video
   * metadata. */

  /* and activate */
  gst_buffer_pool_set_active (pool, TRUE);

  return GST_FLOW_OK;
}

849 850 851 852 853
static GstFlowReturn
theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet)
{
  GstCaps *caps;
  gint par_num, par_den;
854
  GstFlowReturn ret = GST_FLOW_OK;
Wim Taymans's avatar
Wim Taymans committed
855
  GList *walk;
856
  guint32 fourcc;
857 858 859 860 861 862 863

  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;
864
   * 0:x and x:0 are allowed and can be interpreted as 1:1.
865
   */
866 867 868 869 870 871 872 873 874 875
  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;
  }
876
  if (par_num == 0 || par_den == 0) {
877 878 879 880 881
    par_num = par_den = 1;
  }
  /* theora has:
   *
   *  width/height : dimension of the encoded frame 
882 883
   *  pic_width/pic_height : dimension of the visible part
   *  pic_x/pic_y : offset in encoded frame where visible part starts
884
   */
885 886
  GST_DEBUG_OBJECT (dec, "dimension %dx%d, PAR %d/%d", dec->info.pic_width,
      dec->info.pic_height, par_num, par_den);
887
  GST_DEBUG_OBJECT (dec, "frame dimension %dx%d, offset %d:%d",
888 889
      dec->info.pic_width, dec->info.pic_height,
      dec->info.pic_x, dec->info.pic_y);
890

Wim Taymans's avatar
Wim Taymans committed
891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908
  switch (dec->info.pixel_fmt) {
    case TH_PF_444:
      dec->output_bpp = 24;
      dec->format = GST_VIDEO_FORMAT_Y444;
      fourcc = GST_MAKE_FOURCC ('Y', '4', '4', '4');
      break;
    case TH_PF_420:
      dec->output_bpp = 12;     /* Average bits per pixel. */
      dec->format = GST_VIDEO_FORMAT_I420;
      fourcc = GST_MAKE_FOURCC ('I', '4', '2', '0');
      break;
    case TH_PF_422:
      dec->output_bpp = 16;
      dec->format = GST_VIDEO_FORMAT_Y42B;
      fourcc = GST_MAKE_FOURCC ('Y', '4', '2', 'B');
      break;
    default:
      goto invalid_format;
909
  }
910 911

  if (dec->crop) {
912 913
    dec->width = dec->info.pic_width;
    dec->height = dec->info.pic_height;
914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930
    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;
931 932 933 934 935 936 937 938
    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 */
939
  dec->decoder = th_decode_alloc (&dec->info, dec->setup);
940

941
  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_MV,
942
          &dec->telemetry_mv, sizeof (dec->telemetry_mv)) != TH_EIMPL) {
943
    GST_WARNING_OBJECT (dec, "Could not enable MV visualisation");
944
  }
945
  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_MBMODE,
946
          &dec->telemetry_mbmode, sizeof (dec->telemetry_mbmode)) != TH_EIMPL) {
947
    GST_WARNING_OBJECT (dec, "Could not enable MB mode visualisation");
948
  }
949
  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_QI,
950
          &dec->telemetry_qi, sizeof (dec->telemetry_qi)) != TH_EIMPL) {
951
    GST_WARNING_OBJECT (dec, "Could not enable QI mode visualisation");
952
  }
953
  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_BITS,
954
          &dec->telemetry_bits, sizeof (dec->telemetry_bits)) != TH_EIMPL) {
955
    GST_WARNING_OBJECT (dec, "Could not enable BITS mode visualisation");
956
  }
957

958
  caps = gst_caps_new_simple ("video/x-raw-yuv",
959
      "format", GST_TYPE_FOURCC, fourcc,
960 961
      "framerate", GST_TYPE_FRACTION,
      dec->info.fps_numerator, dec->info.fps_denominator,
962
      "pixel-aspect-ratio", GST_TYPE_FRACTION, par_num, par_den,
963
      "width", G_TYPE_INT, dec->width, "height", G_TYPE_INT, dec->height,
964 965
      "color-matrix", G_TYPE_STRING, "sdtv",
      "chroma-site", G_TYPE_STRING, "jpeg", NULL);
966