theoradec.c 29.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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
/**
 * SECTION:element-theoradec
 * @see_also: theoraenc, oggdemux
 *
 * <refsect2>
 * <para>
 * 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.
 * </para>
 * <para>
 * </para>
 * <title>Example pipeline</title>
 * <programlisting>
 * gst-launch -v filesrc location=videotestsrc.ogg ! oggdemux ! theoradec ! xvimagesink
 * </programlisting>
 * This example pipeline will decode an ogg stream and decodes the theora video. Refer to
 * 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
44 45 46 47
#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

Wim Taymans's avatar
Wim Taymans committed
48
#include "gsttheoradec.h"
Benjamin Otte's avatar
Benjamin Otte committed
49 50
#include <gst/tag/tag.h>

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
51 52
GST_DEBUG_CATEGORY (theoradec_debug);
#define GST_CAT_DEFAULT theoradec_debug
Benjamin Otte's avatar
Benjamin Otte committed
53

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
54
#define THEORA_DEF_CROP         TRUE
55 56 57 58 59 60
enum
{
  ARG_0,
  ARG_CROP
};

Benjamin Otte's avatar
Benjamin Otte committed
61 62
static GstElementDetails theora_dec_details = {
  "TheoraDec",
63
  "Codec/Decoder/Video",
Benjamin Otte's avatar
Benjamin Otte committed
64
  "decode raw theora streams to raw YUV video",
65 66
  "Benjamin Otte <in7y118@public.uni-hamburg.de>, "
      "Wim Taymans <wim@fluendo.com>",
Benjamin Otte's avatar
Benjamin Otte committed
67 68 69
};

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

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

GST_BOILERPLATE (GstTheoraDec, gst_theora_dec, GstElement, 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 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);
Wim Taymans's avatar
Wim Taymans committed
98
static gboolean theora_dec_src_query (GstPad * pad, GstQuery * query);
99 100 101 102 103 104
static gboolean theora_dec_src_convert (GstPad * pad,
    GstFormat src_format, gint64 src_value,
    GstFormat * dest_format, gint64 * dest_value);
static gboolean theora_dec_sink_convert (GstPad * pad,
    GstFormat src_format, gint64 src_value,
    GstFormat * dest_format, gint64 * dest_value);
Wim Taymans's avatar
Wim Taymans committed
105
static gboolean theora_dec_sink_query (GstPad * pad, GstQuery * query);
106
static GstCaps *theora_dec_src_getcaps (GstPad * pad);
Wim Taymans's avatar
Wim Taymans committed
107 108

#if 0
109
static const GstFormat *theora_get_formats (GstPad * pad);
Wim Taymans's avatar
Wim Taymans committed
110 111
#endif
#if 0
112
static const GstEventMask *theora_get_event_masks (GstPad * pad);
Wim Taymans's avatar
Wim Taymans committed
113
#endif
114
static const GstQueryType *theora_get_query_types (GstPad * pad);
Benjamin Otte's avatar
Benjamin Otte committed
115 116 117 118 119 120


static void
gst_theora_dec_base_init (gpointer g_class)
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
121 122

  gst_element_class_add_pad_template (element_class,
Benjamin Otte's avatar
Benjamin Otte committed
123 124 125 126 127 128 129
      gst_static_pad_template_get (&theora_dec_src_factory));
  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&theora_dec_sink_factory));
  gst_element_class_set_details (element_class, &theora_dec_details);
}

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

135 136 137 138 139 140 141 142
  gobject_class->set_property = theora_dec_set_property;
  gobject_class->get_property = theora_dec_get_property;

  g_object_class_install_property (gobject_class, ARG_CROP,
      g_param_spec_boolean ("crop", "Crop",
          "Crop the image to the visible region", THEORA_DEF_CROP,
          (GParamFlags) G_PARAM_READWRITE));

Benjamin Otte's avatar
Benjamin Otte committed
143
  gstelement_class->change_state = theora_dec_change_state;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
144 145

  GST_DEBUG_CATEGORY_INIT (theoradec_debug, "theoradec", 0, "Theora decoder");
Benjamin Otte's avatar
Benjamin Otte committed
146 147 148
}

static void
149
gst_theora_dec_init (GstTheoraDec * dec, GstTheoraDecClass * g_class)
Benjamin Otte's avatar
Benjamin Otte committed
150
{
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
151
  dec->sinkpad =
152
      gst_pad_new_from_static_template (&theora_dec_sink_factory, "sink");
Wim Taymans's avatar
Wim Taymans committed
153
  gst_pad_set_query_function (dec->sinkpad, theora_dec_sink_query);
154
  gst_pad_set_event_function (dec->sinkpad, theora_dec_sink_event);
Benjamin Otte's avatar
Benjamin Otte committed
155 156 157
  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
158
  dec->srcpad =
159
      gst_pad_new_from_static_template (&theora_dec_src_factory, "src");
160
  gst_pad_set_getcaps_function (dec->srcpad, theora_dec_src_getcaps);
Benjamin Otte's avatar
Benjamin Otte committed
161
  gst_pad_set_event_function (dec->srcpad, theora_dec_src_event);
162
  gst_pad_set_query_type_function (dec->srcpad, theora_get_query_types);
163
  gst_pad_set_query_function (dec->srcpad, theora_dec_src_query);
164

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

167
  dec->crop = THEORA_DEF_CROP;
168
  dec->queued = NULL;
Benjamin Otte's avatar
Benjamin Otte committed
169
}
170 171

/* FIXME: copy from libtheora, theora should somehow make this available for seeking */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
172 173 174 175 176 177
static int
_theora_ilog (unsigned int v)
{
  int ret = 0;

  while (v) {
178
    ret++;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
179
    v >>= 1;
180
  }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
181
  return (ret);
182 183
}

184 185
static gint64
_theora_granule_frame (GstTheoraDec * dec, gint64 granulepos)
186 187 188 189
{
  guint ilog;
  gint framecount;

190 191
  if (granulepos == -1)
    return -1;
192

193
  ilog = dec->granule_shift;
194

195 196 197 198
  /* granulepos is last ilog bits for counting pframes since last iframe and 
   * bits in front of that for the framenumber of the last iframe. */
  framecount = granulepos >> ilog;
  framecount += granulepos - (framecount << ilog);
199 200 201

  GST_DEBUG_OBJECT (dec, "framecount=%d, ilog=%u", framecount, ilog);

202 203 204 205 206 207 208 209 210 211 212
  return framecount;
}

static GstClockTime
_theora_granule_time (GstTheoraDec * dec, gint64 granulepos)
{
  gint framecount;

  if (granulepos == -1)
    return -1;

213
  framecount = _theora_granule_frame (dec, granulepos);
214 215 216 217 218 219 220 221 222 223 224 225

  return gst_util_uint64_scale_int (framecount * GST_SECOND,
      dec->info.fps_denominator, dec->info.fps_numerator);
}

static gint64
_inc_granulepos (GstTheoraDec * dec, gint64 granulepos)
{
  gint framecount;

  if (granulepos == -1)
    return -1;
226

227 228 229
  framecount = _theora_granule_frame (dec, granulepos);

  return (framecount + 1) << dec->granule_shift;
230 231
}

Wim Taymans's avatar
Wim Taymans committed
232
#if 0
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
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
250
#endif
251

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

static const GstQueryType *
theora_get_query_types (GstPad * pad)
{
  static const GstQueryType theora_src_query_types[] = {
    GST_QUERY_POSITION,
    0
  };

  return theora_src_query_types;
}


277
static gboolean
278 279 280
theora_dec_src_convert (GstPad * pad,
    GstFormat src_format, gint64 src_value,
    GstFormat * dest_format, gint64 * dest_value)
281
{
282 283 284 285
  gboolean res = TRUE;
  GstTheoraDec *dec;
  guint64 scale = 1;

286
  dec = GST_THEORA_DEC (GST_PAD_PARENT (pad));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
287

288
  /* we need the info part before we can done something */
Wim Taymans's avatar
Wim Taymans committed
289
  if (!dec->have_header)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
290 291
    return FALSE;

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

297 298 299 300
  switch (src_format) {
    case GST_FORMAT_BYTES:
      switch (*dest_format) {
        case GST_FORMAT_DEFAULT:
301 302
          *dest_value = gst_util_uint64_scale_int (src_value, 2,
              dec->info.height * dec->info.width * 3);
303 304 305 306 307 308 309
          break;
        case GST_FORMAT_TIME:
          /* seems like a rather silly conversion, implement me if you like */
        default:
          res = FALSE;
      }
      break;
310
    case GST_FORMAT_TIME:
311 312
      switch (*dest_format) {
        case GST_FORMAT_BYTES:
313
          scale = 3 * (dec->info.width * dec->info.height) / 2;
314
        case GST_FORMAT_DEFAULT:
315
          *dest_value = scale * gst_util_uint64_scale (src_value,
316
              dec->info.fps_numerator, dec->info.fps_denominator * GST_SECOND);
317 318 319 320
          break;
        default:
          res = FALSE;
      }
321 322
      break;
    case GST_FORMAT_DEFAULT:
323 324
      switch (*dest_format) {
        case GST_FORMAT_TIME:
325
          *dest_value = gst_util_uint64_scale (src_value,
326
              GST_SECOND * dec->info.fps_denominator, dec->info.fps_numerator);
327 328 329 330 331 332 333 334
          break;
        case GST_FORMAT_BYTES:
          *dest_value =
              src_value * 3 * (dec->info.width * dec->info.height) / 2;
          break;
        default:
          res = FALSE;
      }
335 336
      break;
    default:
337
      res = FALSE;
338
  }
339 340

  return res;
341 342
}

Benjamin Otte's avatar
Benjamin Otte committed
343
static gboolean
344 345 346
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
347
{
348 349
  gboolean res = TRUE;
  GstTheoraDec *dec;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
350

351
  dec = GST_THEORA_DEC (GST_PAD_PARENT (pad));
352 353

  /* we need the info part before we can done something */
Wim Taymans's avatar
Wim Taymans committed
354
  if (!dec->have_header)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
355 356
    return FALSE;

Wim Taymans's avatar
Wim Taymans committed
357 358 359 360 361
  if (src_format == *dest_format) {
    *dest_value = src_value;
    return TRUE;
  }

362
  switch (src_format) {
Benjamin Otte's avatar
Benjamin Otte committed
363
    case GST_FORMAT_DEFAULT:
364 365 366
    {
      switch (*dest_format) {
        case GST_FORMAT_TIME:
367
          *dest_value = _theora_granule_time (dec, src_value);
368 369 370 371
          break;
        default:
          res = FALSE;
      }
372
      break;
373
    }
374 375 376 377 378
    case GST_FORMAT_TIME:
    {
      switch (*dest_format) {
        case GST_FORMAT_DEFAULT:
        {
379
          guint rest;
380

381
          /* framecount */
382
          *dest_value = gst_util_uint64_scale (src_value,
383
              dec->info.fps_numerator, GST_SECOND * dec->info.fps_denominator);
384 385 386 387

          /* funny way of calculating granulepos in theora */
          rest = *dest_value / dec->info.keyframe_frequency_force;
          *dest_value -= rest;
388
          *dest_value <<= dec->granule_shift;
389
          *dest_value += rest;
390 391 392 393 394 395 396 397
          break;
        }
        default:
          res = FALSE;
          break;
      }
      break;
    }
Benjamin Otte's avatar
Benjamin Otte committed
398
    default:
399
      res = FALSE;
Benjamin Otte's avatar
Benjamin Otte committed
400
  }
401 402

  return res;
Benjamin Otte's avatar
Benjamin Otte committed
403
}
404 405

static gboolean
Wim Taymans's avatar
Wim Taymans committed
406
theora_dec_src_query (GstPad * pad, GstQuery * query)
407
{
408
  GstTheoraDec *dec = GST_THEORA_DEC (GST_PAD_PARENT (pad));
Wim Taymans's avatar
Wim Taymans committed
409 410 411 412 413
  gboolean res = FALSE;

  switch (GST_QUERY_TYPE (query)) {
    case GST_QUERY_POSITION:
    {
Wim Taymans's avatar
Wim Taymans committed
414
      gint64 granulepos, value;
Wim Taymans's avatar
Wim Taymans committed
415 416 417 418 419 420
      GstFormat my_format, format;
      gint64 time;

      /* we can convert a granule position to everything */
      granulepos = dec->granulepos;

421 422 423
      GST_LOG_OBJECT (dec,
          "query %p: we have current granule: %lld", query, granulepos);

Wim Taymans's avatar
Wim Taymans committed
424 425
      /* parse format */
      gst_query_parse_position (query, &format, NULL);
426

Wim Taymans's avatar
Wim Taymans committed
427 428 429 430 431 432 433 434
      /* and convert to the final format in two steps with time as the 
       * intermediate step */
      my_format = GST_FORMAT_TIME;
      if (!(res =
              theora_dec_sink_convert (dec->sinkpad, GST_FORMAT_DEFAULT,
                  granulepos, &my_format, &time)))
        goto error;

Wim Taymans's avatar
Wim Taymans committed
435
      time = (time - dec->segment_start) + dec->segment_time;
436

437 438 439
      GST_LOG_OBJECT (dec,
          "query %p: our time: %" GST_TIME_FORMAT, query, GST_TIME_ARGS (time));

Wim Taymans's avatar
Wim Taymans committed
440 441 442 443
      if (!(res =
              theora_dec_src_convert (pad, my_format, time, &format, &value)))
        goto error;

Wim Taymans's avatar
Wim Taymans committed
444
      gst_query_set_position (query, format, value);
Wim Taymans's avatar
Wim Taymans committed
445 446

      GST_LOG_OBJECT (dec,
Wim Taymans's avatar
Wim Taymans committed
447
          "query %p: we return %lld (format %u)", query, value, format);
Wim Taymans's avatar
Wim Taymans committed
448 449 450

      break;
    }
Wim Taymans's avatar
Wim Taymans committed
451 452 453 454 455
    case GST_QUERY_DURATION:
      /* forward to peer for total */
      if (!(res = gst_pad_query (GST_PAD_PEER (dec->sinkpad), query)))
        goto error;
      break;
Wim Taymans's avatar
Wim Taymans committed
456 457 458 459 460 461
    case GST_QUERY_CONVERT:
    {
      GstFormat src_fmt, dest_fmt;
      gint64 src_val, dest_val;

      gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
462
      if (!(res =
Wim Taymans's avatar
Wim Taymans committed
463 464
              theora_dec_src_convert (pad, src_fmt, src_val, &dest_fmt,
                  &dest_val)))
465 466 467
        goto error;

      gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
Wim Taymans's avatar
Wim Taymans committed
468 469 470
      break;
    }
    default:
471
      res = gst_pad_query_default (pad, query);
Wim Taymans's avatar
Wim Taymans committed
472
      break;
473
  }
474
  return res;
475

Wim Taymans's avatar
Wim Taymans committed
476
error:
477
  GST_DEBUG ("query failed");
Wim Taymans's avatar
Wim Taymans committed
478 479 480 481 482 483 484 485 486 487 488 489 490
  return res;
}

static gboolean
theora_dec_sink_query (GstPad * pad, GstQuery * query)
{
  gboolean res = FALSE;

  switch (GST_QUERY_TYPE (query)) {
    case GST_QUERY_CONVERT:
    {
      GstFormat src_fmt, dest_fmt;
      gint64 src_val, dest_val;
491

Wim Taymans's avatar
Wim Taymans committed
492 493 494 495 496 497 498 499 500 501
      gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
      if (!(res =
              theora_dec_sink_convert (pad, src_fmt, src_val, &dest_fmt,
                  &dest_val)))
        goto error;

      gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
      break;
    }
    default:
502
      res = gst_pad_query_default (pad, query);
Wim Taymans's avatar
Wim Taymans committed
503 504
      break;
  }
505

Wim Taymans's avatar
Wim Taymans committed
506 507
error:
  return res;
508 509
}

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

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

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

      gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
          &stop_type, &stop);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
530

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

543
      /* then seek with time on the peer */
544 545
      real_seek = gst_event_new_seek (rate, GST_FORMAT_TIME,
          flags, cur_type, tcur, stop_type, tstop);
546

547
      res = gst_pad_push_event (dec->sinkpad, real_seek);
548

Benjamin Otte's avatar
Benjamin Otte committed
549 550 551 552 553 554 555 556 557
      gst_event_unref (event);
      break;
    }
    default:
      res = gst_pad_event_default (pad, event);
      break;
  }

  return res;
558 559 560 561

error:
  gst_event_unref (event);
  return res;
Benjamin Otte's avatar
Benjamin Otte committed
562 563
}

564 565 566 567 568
static GstCaps *
theora_dec_src_getcaps (GstPad * pad)
{
  GstCaps *caps;

569
  GST_OBJECT_LOCK (pad);
570 571 572
  if (!(caps = GST_PAD_CAPS (pad)))
    caps = (GstCaps *) gst_pad_get_pad_template_caps (pad);
  caps = gst_caps_ref (caps);
573
  GST_OBJECT_UNLOCK (pad);
574

575
  return caps;
576 577
}

578 579
static gboolean
theora_dec_sink_event (GstPad * pad, GstEvent * event)
Benjamin Otte's avatar
Benjamin Otte committed
580
{
581
  gboolean ret = FALSE;
582 583
  GstTheoraDec *dec;

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

Benjamin Otte's avatar
Benjamin Otte committed
586 587
  GST_LOG_OBJECT (dec, "handling event");
  switch (GST_EVENT_TYPE (event)) {
Wim Taymans's avatar
Wim Taymans committed
588 589 590
    case GST_EVENT_EOS:
      ret = gst_pad_push_event (dec->srcpad, event);
      break;
591
    case GST_EVENT_NEWSEGMENT:
592 593 594
    {
      GstFormat format;
      gdouble rate;
Wim Taymans's avatar
Wim Taymans committed
595
      gint64 start, stop, time;
596

597
      gst_event_parse_new_segment (event, NULL, &rate, &format, &start, &stop,
Wim Taymans's avatar
Wim Taymans committed
598
          &time);
599 600 601 602 603 604 605 606 607 608 609 610

      /* we need TIME and a positive rate */
      if (format != GST_FORMAT_TIME)
        goto newseg_wrong_format;

      if (rate <= 0.0)
        goto newseg_wrong_rate;

      /* now copy over the values */
      dec->segment_rate = rate;
      dec->segment_start = start;
      dec->segment_stop = stop;
Wim Taymans's avatar
Wim Taymans committed
611
      dec->segment_time = time;
612

Wim Taymans's avatar
Wim Taymans committed
613 614 615 616
      dec->need_keyframe = TRUE;
      dec->granulepos = -1;
      dec->last_timestamp = -1;
      ret = gst_pad_push_event (dec->srcpad, event);
Benjamin Otte's avatar
Benjamin Otte committed
617
      break;
618
    }
Benjamin Otte's avatar
Benjamin Otte committed
619
    default:
Wim Taymans's avatar
Wim Taymans committed
620
      ret = gst_pad_push_event (dec->srcpad, event);
Benjamin Otte's avatar
Benjamin Otte committed
621 622
      break;
  }
623
done:
Wim Taymans's avatar
Wim Taymans committed
624 625
  gst_object_unref (dec);

626
  return ret;
627 628 629 630 631 632 633 634 635 636 637 638

  /* ERRORS */
newseg_wrong_format:
  {
    GST_DEBUG ("received non TIME newsegment");
    goto done;
  }
newseg_wrong_rate:
  {
    GST_DEBUG ("negative rates not supported yet");
    goto done;
  }
Benjamin Otte's avatar
Benjamin Otte committed
639 640
}

641 642 643 644
#define ROUND_UP_2(x) (((x) + 1) & ~1)
#define ROUND_UP_4(x) (((x) + 3) & ~3)
#define ROUND_UP_8(x) (((x) + 7) & ~7)

645
static GstFlowReturn
646
theora_handle_comment_packet (GstTheoraDec * dec, ogg_packet * packet)
Benjamin Otte's avatar
Benjamin Otte committed
647
{
648
  gchar *encoder = NULL;
Benjamin Otte's avatar
Benjamin Otte committed
649
  GstBuffer *buf;
650 651 652 653 654
  GstTagList *list;

  GST_DEBUG ("parsing comment packet");

  buf = gst_buffer_new_and_alloc (packet->bytes);
655
  memcpy (GST_BUFFER_DATA (buf), packet->packet, packet->bytes);
656

657 658
  list =
      gst_tag_list_from_vorbiscomment_buffer (buf, (guint8 *) "\201theora", 7,
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675
      &encoder);

  gst_buffer_unref (buf);

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

676 677 678 679 680 681 682
  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);
  }

  gst_element_found_tags_for_pad (GST_ELEMENT (dec), dec->srcpad, list);
683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732

  return GST_FLOW_OK;
}

static GstFlowReturn
theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet)
{
  GstCaps *caps;
  gint par_num, par_den;

  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;
   * 0:0 is allowed and can be interpreted as 1:1, so correct for it */
  par_num = dec->info.aspect_numerator;
  par_den = dec->info.aspect_denominator;
  if (par_num == 0 && par_den == 0) {
    par_num = par_den = 1;
  }
  /* theora has:
   *
   *  width/height : dimension of the encoded frame 
   *  frame_width/frame_height : dimension of the visible part
   *  offset_x/offset_y : offset in encoded frame where visible part starts
   */
  GST_DEBUG_OBJECT (dec, "dimension %dx%d, PAR %d/%d", dec->info.width,
      dec->info.height, par_num, par_den);
  GST_DEBUG_OBJECT (dec, "frame dimension %dx%d, offset %d:%d",
      dec->info.frame_width, dec->info.frame_height,
      dec->info.offset_x, dec->info.offset_y);

  if (dec->crop) {
    /* add black borders to make width/height/offsets even. we need this because
     * we cannot express an offset to the peer plugin. */
    dec->width = ROUND_UP_2 (dec->info.frame_width + (dec->info.offset_x & 1));
    dec->height =
        ROUND_UP_2 (dec->info.frame_height + (dec->info.offset_y & 1));
    dec->offset_x = dec->info.offset_x & ~1;
    dec->offset_y = dec->info.offset_y & ~1;
  } else {
    /* no cropping, use the encoded dimensions */
    dec->width = dec->info.width;
    dec->height = dec->info.height;
    dec->offset_x = 0;
    dec->offset_y = 0;
  }

733 734
  dec->granule_shift = _theora_ilog (dec->info.keyframe_frequency_force - 1);

735 736 737 738 739 740 741 742
  GST_DEBUG_OBJECT (dec, "after fixup frame dimension %dx%d, offset %d:%d",
      dec->width, dec->height, dec->offset_x, dec->offset_y);

  /* done */
  theora_decode_init (&dec->state, &dec->info);

  caps = gst_caps_new_simple ("video/x-raw-yuv",
      "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
743 744
      "framerate", GST_TYPE_FRACTION,
      dec->info.fps_numerator, dec->info.fps_denominator,
745 746 747 748 749
      "pixel-aspect-ratio", GST_TYPE_FRACTION, par_num, par_den,
      "width", G_TYPE_INT, dec->width, "height", G_TYPE_INT, dec->height, NULL);
  gst_pad_set_caps (dec->srcpad, caps);
  gst_caps_unref (caps);

Wim Taymans's avatar
Wim Taymans committed
750
  dec->have_header = TRUE;
751 752 753 754 755 756 757 758 759 760 761 762 763 764

  return GST_FLOW_OK;
}

static GstFlowReturn
theora_handle_header_packet (GstTheoraDec * dec, ogg_packet * packet)
{
  GstFlowReturn res;

  GST_DEBUG ("parsing header packet");

  if (theora_decode_header (&dec->info, &dec->comment, packet))
    goto header_read_error;

Wim Taymans's avatar
Wim Taymans committed
765 766
  switch (packet->packet[0]) {
    case 0x81:
767 768
      res = theora_handle_comment_packet (dec, packet);
      break;
Wim Taymans's avatar
Wim Taymans committed
769
    case 0x82:
770 771 772 773
      res = theora_handle_type_packet (dec, packet);
      break;
    default:
      /* ignore */
Wim Taymans's avatar
Wim Taymans committed
774 775 776
      g_warning ("unknown theora header packet found");
    case 0x80:
      /* nothing special, this is the identification header */
777 778 779 780 781 782 783 784 785 786 787 788 789 790
      res = GST_FLOW_OK;
      break;
  }
  return res;

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

791 792 793 794
static GstFlowReturn
theora_dec_push (GstTheoraDec * dec, GstBuffer * buf)
{
  GstFlowReturn result;
Wim Taymans's avatar
Wim Taymans committed
795
  GstClockTime outtime = GST_BUFFER_TIMESTAMP (buf);
796

Wim Taymans's avatar
Wim Taymans committed
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 824 825 826 827
  if (outtime == GST_CLOCK_TIME_NONE) {
    dec->queued = g_list_append (dec->queued, buf);
    GST_DEBUG_OBJECT (dec, "queued buffer");
    result = GST_FLOW_OK;
  } else {
    if (dec->queued) {
      gint64 size;
      GList *walk;

      GST_DEBUG_OBJECT (dec, "first buffer with time %" GST_TIME_FORMAT,
          GST_TIME_ARGS (outtime));

      size = g_list_length (dec->queued);
      for (walk = dec->queued; walk; walk = g_list_next (walk)) {
        GstBuffer *buffer = GST_BUFFER (walk->data);
        GstClockTime time;

        time = outtime - ((size * GST_SECOND * dec->info.fps_denominator)
            / dec->info.fps_numerator);

        GST_DEBUG_OBJECT (dec, "patch buffer %lld %lld", size, time);
        GST_BUFFER_TIMESTAMP (buffer) = time;
        /* ignore the result */
        gst_pad_push (dec->srcpad, buffer);
        size--;
      }
      g_list_free (dec->queued);
      dec->queued = NULL;
    }
    result = gst_pad_push (dec->srcpad, buf);
  }
828 829 830 831

  return result;
}

832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
static GstFlowReturn
theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet,
    GstClockTime outtime)
{
  /* normal data packet */
  yuv_buffer yuv;
  GstBuffer *out;
  guint i;
  gboolean keyframe;
  gint out_size;
  gint stride_y, stride_uv;
  gint width, height;
  gint cwidth, cheight;
  GstFlowReturn result;

Wim Taymans's avatar
Wim Taymans committed
847
  if (!dec->have_header)
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883
    goto not_initialized;

  /* the second most significant bit of the first data byte is cleared 
   * for keyframes */
  keyframe = (packet->packet[0] & 0x40) == 0;
  if (keyframe) {
    dec->need_keyframe = FALSE;
  } else if (dec->need_keyframe) {
    goto dropping;
  }

  if (theora_decode_packetin (&dec->state, packet))
    goto could_not_read;

  if (theora_decode_YUVout (&dec->state, &yuv) < 0)
    goto decode_error;

  if ((yuv.y_width != dec->info.width) || (yuv.y_height != dec->info.height))
    goto wrong_dimensions;


  width = dec->width;
  height = dec->height;
  cwidth = width / 2;
  cheight = height / 2;

  /* should get the stride from the caps, for now we round up to the nearest
   * multiple of 4 because some element needs it. chroma needs special 
   * treatment, see videotestsrc. */
  stride_y = ROUND_UP_4 (width);
  stride_uv = ROUND_UP_8 (width) / 2;

  out_size = stride_y * height + stride_uv * cheight * 2;

  /* now copy over the area contained in offset_x,offset_y,
   * frame_width, frame_height */
884 885 886
  result =
      gst_pad_alloc_buffer_and_set_caps (dec->srcpad, GST_BUFFER_OFFSET_NONE,
      out_size, GST_PAD_CAPS (dec->srcpad), &out);
Wim Taymans's avatar
Wim Taymans committed
887
  if (result != GST_FLOW_OK)
888 889 890 891 892
    goto no_buffer;

  /* copy the visible region to the destination. This is actually pretty
   * complicated and gstreamer doesn't support all the needed caps to do this
   * correctly. For example, when we have an odd offset, we should only combine
893
   * 1 row/column of luma samples with one chroma sample in colorspace conversion. 
Wim Taymans's avatar
Wim Taymans committed
894
   * We compensate for this by adding a black border around the image when the
895
   * offset or size is odd (see above).
896 897
   */
  {
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
898 899 900
    guchar *dest_y, *src_y;
    guchar *dest_u, *src_u;
    guchar *dest_v, *src_v;
901

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
902
    dest_y = GST_BUFFER_DATA (out);
903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928
    dest_u = dest_y + stride_y * height;
    dest_v = dest_u + stride_uv * cheight;

    src_y = yuv.y + dec->offset_x + dec->offset_y * yuv.y_stride;

    for (i = 0; i < height; i++) {
      memcpy (dest_y, src_y, width);

      dest_y += stride_y;
      src_y += yuv.y_stride;
    }

    src_u = yuv.u + dec->offset_x / 2 + dec->offset_y / 2 * yuv.uv_stride;
    src_v = yuv.v + dec->offset_x / 2 + dec->offset_y / 2 * yuv.uv_stride;

    for (i = 0; i < cheight; i++) {
      memcpy (dest_u, src_u, cwidth);
      memcpy (dest_v, src_v, cwidth);

      dest_u += stride_uv;
      src_u += yuv.uv_stride;
      dest_v += stride_uv;
      src_v += yuv.uv_stride;
    }
  }

Wim Taymans's avatar
Wim Taymans committed
929 930 931
  GST_BUFFER_OFFSET (out) = dec->frame_nr;
  dec->frame_nr++;
  GST_BUFFER_OFFSET_END (out) = dec->frame_nr;
932
  GST_BUFFER_DURATION (out) =
933 934
      gst_util_uint64_scale_int (GST_SECOND, dec->info.fps_denominator,
      dec->info.fps_numerator);
935 936
  GST_BUFFER_TIMESTAMP (out) = outtime;

937
  result = theora_dec_push (dec, out);
938 939 940 941 942 943 944

  return result;

  /* ERRORS */
not_initialized:
  {
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
Wim Taymans's avatar
Wim Taymans committed
945
        (NULL), ("no header sent yet"));
946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972
    return GST_FLOW_ERROR;
  }
dropping:
  {
    GST_WARNING_OBJECT (dec, "dropping frame because we need a keyframe");
    return GST_FLOW_OK;
  }
could_not_read:
  {
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
        (NULL), ("theora decoder did not read data packet"));
    return GST_FLOW_ERROR;
  }
decode_error:
  {
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
        (NULL), ("couldn't read out YUV image"));
    return GST_FLOW_ERROR;
  }
wrong_dimensions:
  {
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
        (NULL), ("dimensions of image do not match header"));
    return GST_FLOW_ERROR;
  }
no_buffer:
  {
973
    return result;
974 975 976 977 978 979
  }
}

static GstFlowReturn
theora_dec_chain (GstPad * pad, GstBuffer * buf)
{
Benjamin Otte's avatar
Benjamin Otte committed
980 981
  GstTheoraDec *dec;
  ogg_packet packet;
982
  GstFlowReturn result = GST_FLOW_OK;
Benjamin Otte's avatar
Benjamin Otte committed
983

Wim Taymans's avatar
Wim Taymans committed
984
  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
985

Benjamin Otte's avatar
Benjamin Otte committed
986 987 988
  /* make ogg_packet out of the buffer */
  packet.packet = GST_BUFFER_DATA (buf);
  packet.bytes = GST_BUFFER_SIZE (buf);
Wim Taymans's avatar
Wim Taymans committed
989 990 991
  packet.granulepos = GST_BUFFER_OFFSET_END (buf);
  packet.packetno = 0;          /* we don't really care */
  packet.b_o_s = dec->have_header ? 0 : 1;
992
  packet.e_o_s = 0;
993

Wim Taymans's avatar
Wim Taymans committed
994 995 996
  if (dec->have_header) {
    if (packet.granulepos != -1) {
      dec->granulepos = packet.granulepos;
997
      dec->last_timestamp = _theora_granule_time (dec, packet.granulepos);
Wim Taymans's avatar
Wim Taymans committed
998
    } else if (dec->last_timestamp != -1) {
999
      dec->last_timestamp = _theora_granule_time (dec, dec->granulepos);
Wim Taymans's avatar
Wim Taymans committed
1000 1001 1002 1003 1004
    }
  } else {
    dec->last_timestamp = -1;
  }

1005
  GST_DEBUG_OBJECT (dec, "header=%d packetno=%lld, outtime=%" GST_TIME_FORMAT,
Wim Taymans's avatar
Wim Taymans committed
1006
      packet.packet[0], packet.packetno, GST_TIME_ARGS (dec->last_timestamp));
1007

Benjamin Otte's avatar
Benjamin Otte committed
1008 1009
  /* switch depending on packet type */
  if (packet.packet[0] & 0x80) {
Wim Taymans's avatar
Wim Taymans committed
1010
    if (dec->have_header) {
1011
      GST_WARNING_OBJECT (GST_OBJECT (dec), "Ignoring header");
1012
      goto done;
1013
    }
1014
    result = theora_handle_header_packet (dec, &packet);
Benjamin Otte's avatar
Benjamin Otte committed
1015
  } else {
Wim Taymans's avatar
Wim Taymans committed
1016
    result = theora_handle_data_packet (dec, &packet, dec->last_timestamp);
Benjamin Otte's avatar
Benjamin Otte committed
1017
  }
1018

1019
done:
1020
  dec->granulepos = _inc_granulepos (dec, dec->granulepos);
1021

Wim Taymans's avatar
Wim Taymans committed
1022 1023
  gst_object_unref (dec);

1024
  gst_buffer_unref (buf);
1025 1026

  return result;
Benjamin Otte's avatar
Benjamin Otte committed
1027 1028
}

1029 1030
static GstStateChangeReturn
theora_dec_change_state (GstElement * element, GstStateChange transition)
Benjamin Otte's avatar
Benjamin Otte committed
1031