gsttheoradec.c 46.6 KB
Newer Older
Benjamin Otte's avatar
Benjamin Otte committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/* 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_setcaps (GstTheoraDec * dec, GstCaps * caps);
93 94
static gboolean theora_dec_sink_event (GstPad * pad, GstEvent * event);
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);
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);
Benjamin Otte's avatar
Benjamin Otte committed
196 197 198
  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
199
  dec->srcpad =
200
      gst_pad_new_from_static_template (&theora_dec_src_factory, "src");
Benjamin Otte's avatar
Benjamin Otte committed
201
  gst_pad_set_event_function (dec->srcpad, theora_dec_src_event);
202
  gst_pad_set_query_type_function (dec->srcpad, theora_get_query_types);
203
  gst_pad_set_query_function (dec->srcpad, theora_dec_src_query);
204
  gst_pad_use_fixed_caps (dec->srcpad);
205

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

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

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

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

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

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

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

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

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

  return theora_src_query_types;
}


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

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

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

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

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

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

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

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

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

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

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

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

static gboolean
449
theora_dec_src_query (GstPad * pad, GstQuery * query)
450
{
451 452
  GstTheoraDec *dec;

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

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

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

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

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

470
      GST_LOG_OBJECT (dec,
471
          "query %p: our time: %" GST_TIME_FORMAT, query, GST_TIME_ARGS (time));
472

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

478
      gst_query_set_position (query, format, value);
Wim Taymans's avatar
Wim Taymans committed
479 480

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

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

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

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

515
  return res;
516

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

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

531
  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
Benjamin Otte's avatar
Benjamin Otte committed
532 533

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

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

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

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

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

Wim Taymans's avatar
Wim Taymans committed
576
      gst_event_parse_qos (event, NULL, &proportion, &diff, &timestamp);
577 578 579

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

587 588 589
      GST_DEBUG_OBJECT (dec, "got QoS %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
          GST_TIME_ARGS (timestamp), diff);

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

  return res;
601

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

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

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

Benjamin Otte's avatar
Benjamin Otte committed
618 619
  GST_LOG_OBJECT (dec, "handling event");
  switch (GST_EVENT_TYPE (event)) {
620 621 622 623 624 625 626
    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
627 628 629
    case GST_EVENT_EOS:
      ret = gst_pad_push_event (dec->srcpad, event);
      break;
Wim Taymans's avatar
Wim Taymans committed
630
    case GST_EVENT_SEGMENT:
631
    {
632
      const GstSegment *segment;
633

Wim Taymans's avatar
Wim Taymans committed
634
      gst_event_parse_segment (event, &segment);
635

636
      /* we need TIME format */
637
      if (segment->format != GST_FORMAT_TIME)
638 639
        goto newseg_wrong_format;

640
      GST_DEBUG_OBJECT (dec, "segment: %" GST_SEGMENT_FORMAT, segment);
641

642
      /* now configure the values */
643
      gst_segment_copy_into (segment, &dec->segment);
Wim Taymans's avatar
Wim Taymans committed
644
      dec->seqnum = gst_event_get_seqnum (event);
645

Wim Taymans's avatar
Wim Taymans committed
646
      /* We don't forward this unless/until the decoder is initialised */
647 648 649
      if (dec->have_header) {
        ret = gst_pad_push_event (dec->srcpad, event);
      } else {
Wim Taymans's avatar
Wim Taymans committed
650
        dec->pendingevents = g_list_append (dec->pendingevents, event);
651 652
        ret = TRUE;
      }
Benjamin Otte's avatar
Benjamin Otte committed
653
      break;
654
    }
655 656 657 658 659 660
    case GST_EVENT_CAPS:
    {
      GstCaps *caps;

      gst_event_parse_caps (event, &caps);
      ret = theora_dec_setcaps (dec, caps);
Wim Taymans's avatar
Wim Taymans committed
661
      gst_event_unref (event);
662 663
      break;
    }
664 665 666 667 668 669 670 671 672 673 674 675
    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
676
    default:
677
      ret = gst_pad_event_default (pad, event);
Benjamin Otte's avatar
Benjamin Otte committed
678 679
      break;
  }
680
done:
Wim Taymans's avatar
Wim Taymans committed
681 682
  gst_object_unref (dec);

683
  return ret;
684 685 686 687

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

694
static gboolean
695
theora_dec_setcaps (GstTheoraDec * dec, GstCaps * caps)
696 697
{
  GstStructure *s;
698
  const GValue *codec_data;
699 700 701 702 703 704 705

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

706 707 708
  if ((codec_data = gst_structure_get_value (s, "codec_data"))) {
    if (G_VALUE_TYPE (codec_data) == GST_TYPE_BUFFER) {
      GstBuffer *buffer;
709 710
      guint8 *data, *ptr;
      gsize size, left;
711 712 713 714 715
      guint offset;

      buffer = gst_value_get_buffer (codec_data);

      offset = 0;
716
      data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
717

718 719 720 721
      ptr = data;
      left = size;

      while (left > 2) {
722 723 724
        guint psize;
        GstBuffer *buf;

725
        psize = (ptr[0] << 8) | ptr[1];
726
        /* skip header */
727 728
        ptr += 2;
        left -= 2;
729 730 731
        offset += 2;

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

Wim Taymans's avatar
Wim Taymans committed
734 735
        buf =
            gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset, psize);
736 737 738 739 740 741

        /* 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 */
742
        theora_dec_chain (dec->sinkpad, buf);
743 744

        /* skip the data */
745 746
        left -= psize;
        ptr += psize;
747 748
        offset += psize;
      }
749
      gst_buffer_unmap (buffer, data, size);
750 751 752
    }
  }

753 754 755
  return TRUE;
}

756
static GstFlowReturn
757
theora_handle_comment_packet (GstTheoraDec * dec, ogg_packet * packet)
Benjamin Otte's avatar
Benjamin Otte committed
758
{
759 760 761
  gchar *encoder = NULL;
  GstTagList *list;

762
  GST_DEBUG_OBJECT (dec, "parsing comment packet");
763

764
  list =
765 766
      gst_tag_list_from_vorbiscomment (packet->packet, packet->bytes,
      (guint8 *) "\201theora", 7, &encoder);
767 768 769 770 771 772 773 774 775 776 777 778 779 780

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

781 782 783 784 785 786
  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);
  }

787
  dec->tags = list;
788 789 790 791

  return GST_FLOW_OK;
}

Wim Taymans's avatar
Wim Taymans committed
792 793 794 795 796
static GstFlowReturn
theora_negotiate_pool (GstTheoraDec * dec, GstCaps * caps)
{
  GstQuery *query;
  GstBufferPool *pool = NULL;
797
  guint size, min, max, prefix, alignment;
Wim Taymans's avatar
Wim Taymans committed
798 799 800 801

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

802
  if (gst_pad_peer_query (dec->srcpad, query)) {
Wim Taymans's avatar
Wim Taymans committed
803 804
    GST_DEBUG_OBJECT (dec, "got downstream ALLOCATION hints");
    /* we got configuration from our peer, parse them */
805 806
    gst_query_parse_allocation_params (query, &size, &min, &max, &prefix,
        &alignment, &pool);
Wim Taymans's avatar
Wim Taymans committed
807 808 809
  } else {
    GST_DEBUG_OBJECT (dec, "didn't get downstream ALLOCATION hints");
    size = gst_video_format_get_size (dec->format, dec->width, dec->height);
810 811
    min = max = 0;
    prefix = 0;
Wim Taymans's avatar
Wim Taymans committed
812
    alignment = 0;
Wim Taymans's avatar
Wim Taymans committed
813 814 815 816 817 818 819 820 821
  }

  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);
Wim Taymans's avatar
Wim Taymans committed
822
    gst_buffer_pool_config_set (config, caps, size, min, max, prefix,
823
        alignment);
Wim Taymans's avatar
Wim Taymans committed
824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839
    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;
}

840 841 842 843 844
static GstFlowReturn
theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet)
{
  GstCaps *caps;
  gint par_num, par_den;
845
  GstFlowReturn ret = GST_FLOW_OK;
Wim Taymans's avatar
Wim Taymans committed
846
  GList *walk;
847
  guint32 fourcc;
848 849 850 851 852 853 854

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

Wim Taymans's avatar
Wim Taymans committed
882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899
  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;
900
  }
901 902

  if (dec->crop) {
903 904
    dec->width = dec->info.pic_width;
    dec->height = dec->info.pic_height;
905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
    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;
922 923 924 925 926 927 928 929
    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 */
930
  dec->decoder = th_decode_alloc (&dec->info, dec->setup);
931

932
  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_MV,
933
          &dec->telemetry_mv, sizeof (dec->telemetry_mv)) != TH_EIMPL) {
934
    GST_WARNING_OBJECT (dec, "Could not enable MV visualisation");
935
  }
936
  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_MBMODE,
937
          &dec->telemetry_mbmode, sizeof (dec->telemetry_mbmode)) != TH_EIMPL) {
938
    GST_WARNING_OBJECT (dec, "Could not enable MB mode visualisation");
939
  }