gsttheoradec.c 48.3 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>
Wim Taymans's avatar
Wim Taymans committed
47
#include <gst/video/gstvideometa.h>
48
#include <gst/video/gstvideopool.h>
Benjamin Otte's avatar
Benjamin Otte committed
49

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
50
#define GST_CAT_DEFAULT theoradec_debug
51
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
Wim Taymans's avatar
Wim Taymans committed
52
GST_DEBUG_CATEGORY_EXTERN (GST_CAT_PERFORMANCE);
Benjamin Otte's avatar
Benjamin Otte committed
53

54 55 56 57 58
#define THEORA_DEF_TELEMETRY_MV 0
#define THEORA_DEF_TELEMETRY_MBMODE 0
#define THEORA_DEF_TELEMETRY_QI 0
#define THEORA_DEF_TELEMETRY_BITS 0

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

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

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

85 86
#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
87

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

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

#if 0
108
static const GstFormat *theora_get_formats (GstPad * pad);
Wim Taymans's avatar
Wim Taymans committed
109 110
#endif
#if 0
111
static const GstEventMask *theora_get_event_masks (GstPad * pad);
Wim Taymans's avatar
Wim Taymans committed
112
#endif
Benjamin Otte's avatar
Benjamin Otte committed
113

114 115 116 117 118 119 120
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
121
static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
122
gst_theora_dec_class_init (GstTheoraDecClass * klass)
Benjamin Otte's avatar
Benjamin Otte committed
123
{
124
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Benjamin Otte's avatar
Benjamin Otte committed
125 126
  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);

127 128 129
  gobject_class->set_property = theora_dec_set_property;
  gobject_class->get_property = theora_dec_get_property;

130 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
  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));
  }
173

174 175 176 177
  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));
178
  gst_element_class_set_static_metadata (gstelement_class,
179 180 181 182
      "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
183
  gstelement_class->change_state = theora_dec_change_state;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
184 185

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

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

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

205 206 207 208
  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;
209 210
  dec->gather = NULL;
  dec->decode = NULL;
211
  dec->queued = NULL;
Wim Taymans's avatar
Wim Taymans committed
212
  dec->pendingevents = NULL;
Benjamin Otte's avatar
Benjamin Otte committed
213
}
214

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

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

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

  if (dec->tags) {
    gst_tag_list_free (dec->tags);
    dec->tags = NULL;
  }
249 250
}

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

Wim Taymans's avatar
Wim Taymans committed
271
#if 0
272 273 274 275 276 277 278 279 280 281
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
282
#endif
283

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

Wim Taymans's avatar
Wim Taymans committed
293 294 295 296 297
  if (src_format == *dest_format) {
    *dest_value = src_value;
    return TRUE;
  }

298 299 300 301 302 303
  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;

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

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

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

Wim Taymans's avatar
Wim Taymans committed
370 371 372 373 374
  if (src_format == *dest_format) {
    *dest_value = src_value;
    return TRUE;
  }

375 376 377 378 379 380
  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;

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

397
          /* framecount */
398
          *dest_value = gst_util_uint64_scale (src_value,
399
              dec->info.fps_numerator, GST_SECOND * dec->info.fps_denominator);
400 401

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

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

static gboolean
Wim Taymans's avatar
Wim Taymans committed
431
theora_dec_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
432
{
433
  GstTheoraDec *dec;
Wim Taymans's avatar
Wim Taymans committed
434 435
  gboolean res = FALSE;

Wim Taymans's avatar
Wim Taymans committed
436
  dec = GST_THEORA_DEC (parent);
437

438
  switch (GST_QUERY_TYPE (query)) {
Wim Taymans's avatar
Wim Taymans committed
439 440
    case GST_QUERY_POSITION:
    {
Wim Taymans's avatar
Wim Taymans committed
441
      gint64 value;
Wim Taymans's avatar
Wim Taymans committed
442
      GstFormat format;
Wim Taymans's avatar
Wim Taymans committed
443 444
      gint64 time;

Wim Taymans's avatar
Wim Taymans committed
445
      /* parse format */
446
      gst_query_parse_position (query, &format, NULL);
447

Wim Taymans's avatar
Wim Taymans committed
448
      time = dec->last_timestamp;
449
      time = gst_segment_to_stream_time (&dec->segment, GST_FORMAT_TIME, time);
450

451
      GST_LOG_OBJECT (dec,
452
          "query %p: our time: %" GST_TIME_FORMAT, query, GST_TIME_ARGS (time));
453

Wim Taymans's avatar
Wim Taymans committed
454
      if (!(res =
Wim Taymans's avatar
Wim Taymans committed
455 456
              theora_dec_src_convert (pad, GST_FORMAT_TIME, time, &format,
                  &value)))
Wim Taymans's avatar
Wim Taymans committed
457 458
        goto error;

459
      gst_query_set_position (query, format, value);
Wim Taymans's avatar
Wim Taymans committed
460 461

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

Wim Taymans's avatar
Wim Taymans committed
473
      break;
474
    }
Wim Taymans's avatar
Wim Taymans committed
475 476 477 478 479
    case GST_QUERY_CONVERT:
    {
      GstFormat src_fmt, dest_fmt;
      gint64 src_val, dest_val;

480
      gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
481
      if (!(res =
Wim Taymans's avatar
Wim Taymans committed
482 483
              theora_dec_src_convert (pad, src_fmt, src_val, &dest_fmt,
                  &dest_val)))
484 485
        goto error;

486
      gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
Wim Taymans's avatar
Wim Taymans committed
487 488 489
      break;
    }
    default:
Wim Taymans's avatar
Wim Taymans committed
490
      res = gst_pad_query_default (pad, parent, query);
Wim Taymans's avatar
Wim Taymans committed
491
      break;
492
  }
493 494
done:

495
  return res;
496

497
  /* ERRORS */
Wim Taymans's avatar
Wim Taymans committed
498
error:
499 500 501 502
  {
    GST_DEBUG_OBJECT (dec, "query failed");
    goto done;
  }
Wim Taymans's avatar
Wim Taymans committed
503 504
}

Benjamin Otte's avatar
Benjamin Otte committed
505
static gboolean
Wim Taymans's avatar
Wim Taymans committed
506
theora_dec_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
Benjamin Otte's avatar
Benjamin Otte committed
507 508 509 510
{
  gboolean res = TRUE;
  GstTheoraDec *dec;

Wim Taymans's avatar
Wim Taymans committed
511
  dec = GST_THEORA_DEC (parent);
Benjamin Otte's avatar
Benjamin Otte committed
512 513

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

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

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

542
      /* then seek with time on the peer */
543 544
      real_seek = gst_event_new_seek (rate, GST_FORMAT_TIME,
          flags, cur_type, tcur, stop_type, tstop);
Wim Taymans's avatar
Wim Taymans committed
545
      gst_event_set_seqnum (real_seek, seqnum);
546

547
      res = gst_pad_push_event (dec->sinkpad, real_seek);
Benjamin Otte's avatar
Benjamin Otte committed
548 549
      break;
    }
550 551 552 553 554 555
    case GST_EVENT_QOS:
    {
      gdouble proportion;
      GstClockTimeDiff diff;
      GstClockTime timestamp;

Wim Taymans's avatar
Wim Taymans committed
556
      gst_event_parse_qos (event, NULL, &proportion, &diff, &timestamp);
557 558 559

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

567 568 569
      GST_DEBUG_OBJECT (dec, "got QoS %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
          GST_TIME_ARGS (timestamp), diff);

570
      res = gst_pad_push_event (dec->sinkpad, event);
571 572
      break;
    }
Benjamin Otte's avatar
Benjamin Otte committed
573
    default:
574
      res = gst_pad_push_event (dec->sinkpad, event);
Benjamin Otte's avatar
Benjamin Otte committed
575 576
      break;
  }
577
done:
Benjamin Otte's avatar
Benjamin Otte committed
578 579

  return res;
580

581 582 583 584 585 586
  /* ERRORS */
convert_error:
  {
    GST_DEBUG_OBJECT (dec, "could not convert format");
    goto done;
  }
587 588
}

589
static gboolean
Wim Taymans's avatar
Wim Taymans committed
590
theora_dec_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
Benjamin Otte's avatar
Benjamin Otte committed
591
{
592
  gboolean ret = FALSE;
593 594
  GstTheoraDec *dec;

Wim Taymans's avatar
Wim Taymans committed
595
  dec = GST_THEORA_DEC (parent);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
596

Benjamin Otte's avatar
Benjamin Otte committed
597 598
  GST_LOG_OBJECT (dec, "handling event");
  switch (GST_EVENT_TYPE (event)) {
599 600 601 602 603 604 605
    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
606 607 608
    case GST_EVENT_EOS:
      ret = gst_pad_push_event (dec->srcpad, event);
      break;
Wim Taymans's avatar
Wim Taymans committed
609
    case GST_EVENT_SEGMENT:
610
    {
611
      const GstSegment *segment;
612

Wim Taymans's avatar
Wim Taymans committed
613
      gst_event_parse_segment (event, &segment);
614

615
      /* we need TIME format */
616
      if (segment->format != GST_FORMAT_TIME)
617 618
        goto newseg_wrong_format;

619
      GST_DEBUG_OBJECT (dec, "segment: %" GST_SEGMENT_FORMAT, segment);
620

621
      /* now configure the values */
622
      gst_segment_copy_into (segment, &dec->segment);
Wim Taymans's avatar
Wim Taymans committed
623
      dec->seqnum = gst_event_get_seqnum (event);
624

Wim Taymans's avatar
Wim Taymans committed
625
      /* We don't forward this unless/until the decoder is initialised */
626 627 628
      if (dec->have_header) {
        ret = gst_pad_push_event (dec->srcpad, event);
      } else {
Wim Taymans's avatar
Wim Taymans committed
629
        dec->pendingevents = g_list_append (dec->pendingevents, event);
630 631
        ret = TRUE;
      }
Benjamin Otte's avatar
Benjamin Otte committed
632
      break;
633
    }
634 635 636 637 638 639
    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
640
      gst_event_unref (event);
641 642
      break;
    }
643 644 645 646 647 648 649 650 651 652 653 654
    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
655
    default:
Wim Taymans's avatar
Wim Taymans committed
656
      ret = gst_pad_event_default (pad, parent, event);
Benjamin Otte's avatar
Benjamin Otte committed
657 658
      break;
  }
659
done:
Wim Taymans's avatar
Wim Taymans committed
660

661
  return ret;
662 663 664 665

  /* ERRORS */
newseg_wrong_format:
  {
666
    GST_DEBUG_OBJECT (dec, "received non TIME newsegment");
667
    gst_event_unref (event);
668 669
    goto done;
  }
Benjamin Otte's avatar
Benjamin Otte committed
670 671
}

672
static gboolean
673
theora_dec_setcaps (GstTheoraDec * dec, GstCaps * caps)
674 675
{
  GstStructure *s;
676
  const GValue *codec_data;
677 678 679 680 681 682 683

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

684 685 686
  if ((codec_data = gst_structure_get_value (s, "codec_data"))) {
    if (G_VALUE_TYPE (codec_data) == GST_TYPE_BUFFER) {
      GstBuffer *buffer;
Wim Taymans's avatar
Wim Taymans committed
687 688 689
      GstMapInfo map;
      guint8 *ptr;
      gsize left;
690 691 692 693 694
      guint offset;

      buffer = gst_value_get_buffer (codec_data);

      offset = 0;
Wim Taymans's avatar
Wim Taymans committed
695
      gst_buffer_map (buffer, &map, GST_MAP_READ);
696

Wim Taymans's avatar
Wim Taymans committed
697 698
      ptr = map.data;
      left = map.size;
699 700

      while (left > 2) {
701 702 703
        guint psize;
        GstBuffer *buf;

704
        psize = (ptr[0] << 8) | ptr[1];
705
        /* skip header */
706 707
        ptr += 2;
        left -= 2;
708 709 710
        offset += 2;

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

Wim Taymans's avatar
Wim Taymans committed
713 714
        buf =
            gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset, psize);
715 716 717 718 719 720

        /* 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 */
Wim Taymans's avatar
Wim Taymans committed
721
        theora_dec_chain (dec->sinkpad, GST_OBJECT_CAST (dec), buf);
722 723

        /* skip the data */
724 725
        left -= psize;
        ptr += psize;
726 727
        offset += psize;
      }
Wim Taymans's avatar
Wim Taymans committed
728
      gst_buffer_unmap (buffer, &map);
729 730 731
    }
  }

732 733 734
  return TRUE;
}

735
static GstFlowReturn
736
theora_handle_comment_packet (GstTheoraDec * dec, ogg_packet * packet)
Benjamin Otte's avatar
Benjamin Otte committed
737
{
738 739 740
  gchar *encoder = NULL;
  GstTagList *list;

741
  GST_DEBUG_OBJECT (dec, "parsing comment packet");
742

743
  list =
744 745
      gst_tag_list_from_vorbiscomment (packet->packet, packet->bytes,
      (guint8 *) "\201theora", 7, &encoder);
746 747 748

  if (!list) {
    GST_ERROR_OBJECT (dec, "couldn't decode comments");
749
    list = gst_tag_list_new_empty ();
750 751 752 753 754 755 756 757 758 759
  }
  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);

760 761 762 763 764 765
  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);
  }

766
  dec->tags = list;
767 768 769 770

  return GST_FLOW_OK;
}

Wim Taymans's avatar
Wim Taymans committed
771
static GstFlowReturn
772
theora_negotiate (GstTheoraDec * dec)
Wim Taymans's avatar
Wim Taymans committed
773
{
774
  GstVideoFormat format;
Wim Taymans's avatar
Wim Taymans committed
775
  GstQuery *query;
776
  GstBufferPool *pool;
777
  guint size, min, max;
778
  GstStructure *config;
779
  GstCaps *caps;
780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823
  GstVideoInfo info, cinfo;

  /* theora has:
   *
   *  frame_width/frame_height : dimension of the encoded frame
   *  pic_width/pic_height : dimension of the visible part
   *  pic_x/pic_y : offset in encoded frame where visible part starts
   */
  GST_DEBUG_OBJECT (dec, "frame dimension %dx%d, PAR %d/%d, fps %d/%d",
      dec->info.frame_width, dec->info.frame_height,
      dec->info.aspect_numerator, dec->info.aspect_denominator,
      dec->info.fps_numerator, dec->info.fps_denominator);
  GST_DEBUG_OBJECT (dec, "picture dimension %dx%d, offset %d:%d",
      dec->info.pic_width, dec->info.pic_height, dec->info.pic_x,
      dec->info.pic_y);

  switch (dec->info.pixel_fmt) {
    case TH_PF_444:
      dec->output_bpp = 24;
      format = GST_VIDEO_FORMAT_Y444;
      break;
    case TH_PF_420:
      dec->output_bpp = 12;     /* Average bits per pixel. */
      format = GST_VIDEO_FORMAT_I420;
      break;
    case TH_PF_422:
      dec->output_bpp = 16;
      format = GST_VIDEO_FORMAT_Y42B;
      break;
    default:
      goto invalid_format;
  }

  if (dec->info.pic_width != dec->info.frame_width ||
      dec->info.pic_height != dec->info.frame_height ||
      dec->info.pic_x != 0 || dec->info.pic_y != 0) {
    GST_DEBUG_OBJECT (dec, "we need to crop");
    dec->need_cropping = TRUE;
  } else {
    GST_DEBUG_OBJECT (dec, "no cropping needed");
    dec->need_cropping = FALSE;
  }

  /* info contains the dimensions for the coded picture before cropping */
824
  gst_video_info_init (&info);
825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867
  gst_video_info_set_format (&info, format, dec->info.frame_width,
      dec->info.frame_height);
  info.fps_n = dec->info.fps_numerator;
  info.fps_d = dec->info.fps_denominator;
  /* calculate par
   * the info.aspect_* values reflect PAR;
   * 0:x and x:0 are allowed and can be interpreted as 1:1.
   */
  if (dec->have_par) {
    /* we had a par on the sink caps, override the encoded par */
    GST_DEBUG_OBJECT (dec, "overriding with input PAR %dx%d", dec->par_num,
        dec->par_den);
    info.par_n = dec->par_num;
    info.par_d = dec->par_den;
  } else {
    /* take encoded par */
    info.par_n = dec->info.aspect_numerator;
    info.par_d = dec->info.aspect_denominator;
  }
  if (info.par_n == 0 || info.par_d == 0) {
    info.par_n = info.par_d = 1;
  }

  /* these values are for all versions of the colorspace specified in the
   * theora info */
  info.chroma_site = GST_VIDEO_CHROMA_SITE_JPEG;
  info.colorimetry.range = GST_VIDEO_COLOR_RANGE_16_235;
  info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT601;
  info.colorimetry.transfer = GST_VIDEO_TRANSFER_BT709;
  switch (dec->info.colorspace) {
    case TH_CS_ITU_REC_470M:
      info.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT470M;
      break;
    case TH_CS_ITU_REC_470BG:
      info.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT470BG;
      break;
    default:
      info.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_UNKNOWN;
      break;
  }

  /* remove reconfigure flag now */
  gst_pad_check_reconfigure (dec->srcpad);
868

869
  /* for the output caps we always take the cropped dimensions */
870 871
  cinfo = info;
  gst_video_info_set_format (&cinfo, GST_VIDEO_INFO_FORMAT (&info),
872
      dec->info.pic_width, dec->info.pic_height);
873
  caps = gst_video_info_to_caps (&cinfo);
874
  gst_pad_set_caps (dec->srcpad, caps);
Wim Taymans's avatar
Wim Taymans committed
875 876 877 878

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

879
  if (gst_pad_peer_query (dec->srcpad, query)) {
880 881 882
    /* check if downstream supports cropping */
    dec->has_cropping =
        gst_query_has_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE);
Wim Taymans's avatar
Wim Taymans committed
883
  } else {
884
    /* not a problem, deal with defaults */
Wim Taymans's avatar
Wim Taymans committed
885
    GST_DEBUG_OBJECT (dec, "didn't get downstream ALLOCATION hints");
886 887 888 889 890 891 892 893
    dec->has_cropping = FALSE;
  }

  if (gst_query_get_n_allocation_pools (query) > 0) {
    /* we got configuration from our peer, parse them */
    gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
  } else {
    pool = NULL;
894
    size = 0;
895
    min = max = 0;
Wim Taymans's avatar
Wim Taymans committed
896
  }
897
  GST_DEBUG_OBJECT (dec, "downstream cropping %d", dec->has_cropping);
Wim Taymans's avatar
Wim Taymans committed
898 899 900

  if (pool == NULL) {
    /* we did not get a pool, make one ourselves then */
901
    pool = gst_video_buffer_pool_new ();
Wim Taymans's avatar
Wim Taymans committed
902 903
  }

904 905
  if (dec->pool) {
    gst_buffer_pool_set_active (dec->pool, FALSE);
Wim Taymans's avatar
Wim Taymans committed
906
    gst_object_unref (dec->pool);
907
  }
Wim Taymans's avatar
Wim Taymans committed
908 909
  dec->pool = pool;

910
  if (dec->has_cropping) {
911
    dec->vinfo = info;
912 913 914
    /* we can crop, configure the pool with buffers of caps and size of the
     * decoded picture size and then crop them with metadata */
    gst_caps_unref (caps);
915
    caps = gst_video_info_to_caps (&info);
916 917
  } else {
    /* no cropping, use cropped videoinfo */
918
    dec->vinfo = cinfo;
919
  }
920
  size = MAX (size, GST_VIDEO_INFO_SIZE (&dec->vinfo));
921

922
  config = gst_buffer_pool_get_config (pool);
Wim Taymans's avatar
Wim Taymans committed
923
  gst_buffer_pool_config_set_params (config, caps, size, min, max);
924 925
  gst_caps_unref (caps);

926 927 928 929 930 931 932
  if (gst_query_has_allocation_meta (query, GST_VIDEO_META_API_TYPE)) {
    /* just set the option, if the pool can support it we will transparently use
     * it through the video info API. We could also see if the pool support this
     * option and only activate it then. */
    gst_buffer_pool_config_add_option (config,
        GST_BUFFER_POOL_OPTION_VIDEO_META);
  }
933

Wim Taymans's avatar
Wim Taymans committed
934
  gst_buffer_pool_set_config (pool, config);
Wim Taymans's avatar
Wim Taymans committed
935 936 937
  /* and activate */
  gst_buffer_pool_set_active (pool, TRUE);

Wim Taymans's avatar
Wim Taymans committed
938 939
  gst_query_unref (query);

Wim Taymans's avatar
Wim Taymans committed
940
  return GST_FLOW_OK;
941 942 943 944 945 946 947

  /* ERRORS */
invalid_format:
  {
    GST_ERROR_OBJECT (dec, "Invalid pixel format %d", dec->info.pixel_fmt);
    return GST_FLOW_ERROR;
  }
Wim Taymans's avatar
Wim Taymans committed
948 949
}

950 951 952
static GstFlowReturn
theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet)
{
953
  GstFlowReturn ret = GST_FLOW_OK;
Wim Taymans's avatar
Wim Taymans committed
954
  GList *walk;
955

956 957
  if ((ret = theora_negotiate (dec)) != GST_FLOW_OK)
    goto negotiate_failed;
Wim Taymans's avatar
Wim Taymans committed
958

Wim Taymans's avatar
Wim Taymans committed
959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978