theoradec.c 48.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 46
#include <gst/tag/tag.h>

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

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
50
#define THEORA_DEF_CROP         TRUE
51 52 53 54 55 56
enum
{
  ARG_0,
  ARG_CROP
};

Stefan Kost's avatar
Stefan Kost committed
57
static const GstElementDetails theora_dec_details =
j^'s avatar
j^ committed
58
GST_ELEMENT_DETAILS ("Theora video decoder",
59 60 61 62
    "Codec/Decoder/Video",
    "decode raw theora streams to raw YUV video",
    "Benjamin Otte <in7y118@public.uni-hamburg.de>, "
    "Wim Taymans <wim@fluendo.com>");
Benjamin Otte's avatar
Benjamin Otte committed
63 64

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

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

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

83 84 85 86 87
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);

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

#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


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

  gst_element_class_add_pad_template (element_class,
Benjamin Otte's avatar
Benjamin Otte committed
118 119 120 121 122 123 124
      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
125
gst_theora_dec_class_init (GstTheoraDecClass * klass)
Benjamin Otte's avatar
Benjamin Otte committed
126
{
127
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Benjamin Otte's avatar
Benjamin Otte committed
128 129
  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);

130 131 132 133 134 135
  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,
136
          (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
137

Benjamin Otte's avatar
Benjamin Otte committed
138
  gstelement_class->change_state = theora_dec_change_state;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
139 140

  GST_DEBUG_CATEGORY_INIT (theoradec_debug, "theoradec", 0, "Theora decoder");
Benjamin Otte's avatar
Benjamin Otte committed
141 142 143
}

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

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

163
  dec->crop = THEORA_DEF_CROP;
164 165
  dec->gather = NULL;
  dec->decode = NULL;
166
  dec->queued = NULL;
Wim Taymans's avatar
Wim Taymans committed
167
  dec->pendingevents = NULL;
Benjamin Otte's avatar
Benjamin Otte committed
168
}
169

170 171 172 173 174 175
static void
gst_theora_dec_reset (GstTheoraDec * dec)
{
  dec->need_keyframe = TRUE;
  dec->last_timestamp = -1;
  dec->granulepos = -1;
176 177
  dec->discont = TRUE;
  dec->frame_nr = -1;
Wim Taymans's avatar
Wim Taymans committed
178
  dec->seqnum = gst_util_seqnum_next ();
179 180 181 182 183 184
  gst_segment_init (&dec->segment, GST_FORMAT_TIME);

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

186
  g_list_foreach (dec->queued, (GFunc) gst_mini_object_unref, NULL);
187 188
  g_list_free (dec->queued);
  dec->queued = NULL;
189 190 191 192 193 194
  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
195 196 197
  g_list_foreach (dec->pendingevents, (GFunc) gst_mini_object_unref, NULL);
  g_list_free (dec->pendingevents);
  dec->pendingevents = NULL;
198 199 200 201 202

  if (dec->tags) {
    gst_tag_list_free (dec->tags);
    dec->tags = NULL;
  }
203 204
}

205 206 207 208 209 210 211 212 213 214 215 216
static int
_theora_ilog (unsigned int v)
{
  int ret = 0;

  while (v) {
    ret++;
    v >>= 1;
  }
  return (ret);
}

217 218
/* Return the frame number (starting from zero) corresponding to this 
 * granulepos */
219 220
static gint64
_theora_granule_frame (GstTheoraDec * dec, gint64 granulepos)
221 222
{
  guint ilog;
223
  gint framenum;
224

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

228
  ilog = dec->granule_shift;
229

230 231
  /* granulepos is last ilog bits for counting pframes since last iframe and 
   * bits in front of that for the framenumber of the last iframe. */
232 233 234
  framenum = granulepos >> ilog;
  framenum += granulepos - (framenum << ilog);

235
  /* This is 0-based for old bitstreams, 1-based for new. Fix up. */
236
  if (!dec->is_old_bitstream)
237
    framenum -= 1;
238

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

241
  return framenum;
242 243
}

244
/* Return the frame start time corresponding to this granulepos */
245
static GstClockTime
246
_theora_granule_start_time (GstTheoraDec * dec, gint64 granulepos)
247
{
248
  gint64 framecount;
249

250
  /* invalid granule results in invalid time */
251
  if (granulepos == -1)
252
    return GST_CLOCK_TIME_NONE;
253

254
  /* get framecount */
255 256
  if ((framecount = _theora_granule_frame (dec, granulepos)) < 0)
    return GST_CLOCK_TIME_NONE;
257

258 259
  if (framecount < 0)
    return GST_CLOCK_TIME_NONE;
260 261 262 263 264 265 266 267 268 269 270
  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;
271

272 273
  framecount = _theora_granule_frame (dec, granulepos);

274 275
  return (framecount + 1 +
      (dec->is_old_bitstream ? 0 : 1)) << dec->granule_shift;
276 277
}

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

Wim Taymans's avatar
Wim Taymans committed
298
#if 0
299 300 301 302 303 304 305 306 307 308
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
309
#endif
310 311 312 313 314 315

static const GstQueryType *
theora_get_query_types (GstPad * pad)
{
  static const GstQueryType theora_src_query_types[] = {
    GST_QUERY_POSITION,
316 317
    GST_QUERY_DURATION,
    GST_QUERY_CONVERT,
318 319 320 321 322 323 324
    0
  };

  return theora_src_query_types;
}


325
static gboolean
326 327 328
theora_dec_src_convert (GstPad * pad,
    GstFormat src_format, gint64 src_value,
    GstFormat * dest_format, gint64 * dest_value)
329
{
330 331 332 333
  gboolean res = TRUE;
  GstTheoraDec *dec;
  guint64 scale = 1;

Wim Taymans's avatar
Wim Taymans committed
334 335 336 337 338
  if (src_format == *dest_format) {
    *dest_value = src_value;
    return TRUE;
  }

339 340 341 342 343 344
  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;

345 346 347 348
  switch (src_format) {
    case GST_FORMAT_BYTES:
      switch (*dest_format) {
        case GST_FORMAT_DEFAULT:
349
          *dest_value = gst_util_uint64_scale_int (src_value, 8,
350
              dec->info.height * dec->info.width * dec->output_bpp);
351 352 353 354 355 356 357
          break;
        case GST_FORMAT_TIME:
          /* seems like a rather silly conversion, implement me if you like */
        default:
          res = FALSE;
      }
      break;
358
    case GST_FORMAT_TIME:
359 360
      switch (*dest_format) {
        case GST_FORMAT_BYTES:
361
          scale = dec->output_bpp * (dec->info.width * dec->info.height) / 8;
362
        case GST_FORMAT_DEFAULT:
363
          *dest_value = scale * gst_util_uint64_scale (src_value,
364
              dec->info.fps_numerator, dec->info.fps_denominator * GST_SECOND);
365 366 367 368
          break;
        default:
          res = FALSE;
      }
369 370
      break;
    case GST_FORMAT_DEFAULT:
371 372
      switch (*dest_format) {
        case GST_FORMAT_TIME:
373
          *dest_value = gst_util_uint64_scale (src_value,
374
              GST_SECOND * dec->info.fps_denominator, dec->info.fps_numerator);
375 376
          break;
        case GST_FORMAT_BYTES:
377
          *dest_value = gst_util_uint64_scale_int (src_value,
378
              dec->output_bpp * dec->info.width * dec->info.height, 8);
379 380 381 382
          break;
        default:
          res = FALSE;
      }
383 384
      break;
    default:
385
      res = FALSE;
386
  }
387 388
done:
  gst_object_unref (dec);
389
  return res;
390 391 392 393 394 395 396 397

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

Benjamin Otte's avatar
Benjamin Otte committed
400
static gboolean
401 402 403
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
404
{
405 406
  gboolean res = TRUE;
  GstTheoraDec *dec;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
407

Wim Taymans's avatar
Wim Taymans committed
408 409 410 411 412
  if (src_format == *dest_format) {
    *dest_value = src_value;
    return TRUE;
  }

413 414 415 416 417 418
  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;

419
  switch (src_format) {
Benjamin Otte's avatar
Benjamin Otte committed
420
    case GST_FORMAT_DEFAULT:
421 422
      switch (*dest_format) {
        case GST_FORMAT_TIME:
423
          *dest_value = _theora_granule_start_time (dec, src_value);
424 425 426 427
          break;
        default:
          res = FALSE;
      }
428
      break;
429 430 431 432
    case GST_FORMAT_TIME:
      switch (*dest_format) {
        case GST_FORMAT_DEFAULT:
        {
433
          guint rest;
434

435
          /* framecount */
436
          *dest_value = gst_util_uint64_scale (src_value,
437
              dec->info.fps_numerator, GST_SECOND * dec->info.fps_denominator);
438 439

          /* funny way of calculating granulepos in theora */
440
          rest = *dest_value / dec->info.keyframe_frequency_force;
441
          *dest_value -= rest;
442
          *dest_value <<= dec->granule_shift;
443
          *dest_value += rest;
444 445 446 447 448 449 450
          break;
        }
        default:
          res = FALSE;
          break;
      }
      break;
Benjamin Otte's avatar
Benjamin Otte committed
451
    default:
452
      res = FALSE;
Benjamin Otte's avatar
Benjamin Otte committed
453
  }
454 455
done:
  gst_object_unref (dec);
456
  return res;
457 458 459 460 461 462 463 464

  /* ERRORS */
no_header:
  {
    GST_DEBUG_OBJECT (dec, "no header yet, cannot convert");
    res = FALSE;
    goto done;
  }
Benjamin Otte's avatar
Benjamin Otte committed
465
}
466 467

static gboolean
Wim Taymans's avatar
Wim Taymans committed
468
theora_dec_src_query (GstPad * pad, GstQuery * query)
469
{
470 471
  GstTheoraDec *dec;

Wim Taymans's avatar
Wim Taymans committed
472 473
  gboolean res = FALSE;

474 475
  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));

Wim Taymans's avatar
Wim Taymans committed
476 477 478
  switch (GST_QUERY_TYPE (query)) {
    case GST_QUERY_POSITION:
    {
Wim Taymans's avatar
Wim Taymans committed
479
      gint64 granulepos, value;
Wim Taymans's avatar
Wim Taymans committed
480 481 482 483 484 485
      GstFormat my_format, format;
      gint64 time;

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

486 487 488
      GST_LOG_OBJECT (dec,
          "query %p: we have current granule: %lld", query, granulepos);

Wim Taymans's avatar
Wim Taymans committed
489 490
      /* parse format */
      gst_query_parse_position (query, &format, NULL);
491

Wim Taymans's avatar
Wim Taymans committed
492 493 494 495 496 497 498 499
      /* 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;

500
      time = gst_segment_to_stream_time (&dec->segment, GST_FORMAT_TIME, time);
501

502 503 504
      GST_LOG_OBJECT (dec,
          "query %p: our time: %" GST_TIME_FORMAT, query, GST_TIME_ARGS (time));

Wim Taymans's avatar
Wim Taymans committed
505 506 507 508
      if (!(res =
              theora_dec_src_convert (pad, my_format, time, &format, &value)))
        goto error;

Wim Taymans's avatar
Wim Taymans committed
509
      gst_query_set_position (query, format, value);
Wim Taymans's avatar
Wim Taymans committed
510 511

      GST_LOG_OBJECT (dec,
Wim Taymans's avatar
Wim Taymans committed
512
          "query %p: we return %lld (format %u)", query, value, format);
Wim Taymans's avatar
Wim Taymans committed
513 514 515

      break;
    }
Wim Taymans's avatar
Wim Taymans committed
516
    case GST_QUERY_DURATION:
517 518 519 520 521 522
    {
      GstPad *peer;

      if (!(peer = gst_pad_get_peer (dec->sinkpad)))
        goto error;

Wim Taymans's avatar
Wim Taymans committed
523
      /* forward to peer for total */
524 525 526
      res = gst_pad_query (peer, query);
      gst_object_unref (peer);
      if (!res)
Wim Taymans's avatar
Wim Taymans committed
527
        goto error;
528

Wim Taymans's avatar
Wim Taymans committed
529
      break;
530
    }
Wim Taymans's avatar
Wim Taymans committed
531 532 533 534 535 536
    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);
537
      if (!(res =
Wim Taymans's avatar
Wim Taymans committed
538 539
              theora_dec_src_convert (pad, src_fmt, src_val, &dest_fmt,
                  &dest_val)))
540 541 542
        goto error;

      gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
Wim Taymans's avatar
Wim Taymans committed
543 544 545
      break;
    }
    default:
546
      res = gst_pad_query_default (pad, query);
Wim Taymans's avatar
Wim Taymans committed
547
      break;
548
  }
549 550 551
done:
  gst_object_unref (dec);

552
  return res;
553

554
  /* ERRORS */
Wim Taymans's avatar
Wim Taymans committed
555
error:
556 557 558 559
  {
    GST_DEBUG_OBJECT (dec, "query failed");
    goto done;
  }
Wim Taymans's avatar
Wim Taymans committed
560 561 562 563 564 565 566 567 568 569 570 571
}

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

Wim Taymans's avatar
Wim Taymans committed
573 574 575 576 577 578 579 580 581 582
      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:
583
      res = gst_pad_query_default (pad, query);
Wim Taymans's avatar
Wim Taymans committed
584 585
      break;
  }
586

Wim Taymans's avatar
Wim Taymans committed
587 588
error:
  return res;
589 590
}

Benjamin Otte's avatar
Benjamin Otte committed
591
static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
592
theora_dec_src_event (GstPad * pad, GstEvent * event)
Benjamin Otte's avatar
Benjamin Otte committed
593 594 595 596
{
  gboolean res = TRUE;
  GstTheoraDec *dec;

597
  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
Benjamin Otte's avatar
Benjamin Otte committed
598 599

  switch (GST_EVENT_TYPE (event)) {
600 601
    case GST_EVENT_SEEK:
    {
602 603
      GstFormat format, tformat;
      gdouble rate;
Scott Wheeler Wheeler's avatar
Scott Wheeler Wheeler committed
604
      GstEvent *real_seek;
605 606 607 608
      GstSeekFlags flags;
      GstSeekType cur_type, stop_type;
      gint64 cur, stop;
      gint64 tcur, tstop;
Wim Taymans's avatar
Wim Taymans committed
609
      guint32 seqnum;
610 611 612

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

616 617 618 619 620 621
      /* 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 
       */
622 623
      tformat = GST_FORMAT_TIME;
      if (!(res = theora_dec_src_convert (pad, format, cur, &tformat, &tcur)))
624
        goto convert_error;
625
      if (!(res = theora_dec_src_convert (pad, format, stop, &tformat, &tstop)))
626
        goto convert_error;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
627

628
      /* then seek with time on the peer */
629 630
      real_seek = gst_event_new_seek (rate, GST_FORMAT_TIME,
          flags, cur_type, tcur, stop_type, tstop);
Wim Taymans's avatar
Wim Taymans committed
631
      gst_event_set_seqnum (real_seek, seqnum);
632

633
      res = gst_pad_push_event (dec->sinkpad, real_seek);
Benjamin Otte's avatar
Benjamin Otte committed
634 635
      break;
    }
636 637 638 639 640 641 642 643 644 645
    case GST_EVENT_QOS:
    {
      gdouble proportion;
      GstClockTimeDiff diff;
      GstClockTime timestamp;

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

      /* we cannot randomly skip frame decoding since we don't have
       * B frames. we can however use the timestamp and diff to not
646 647
       * push late frames. This would at least save us the time to
       * crop/memcpy the data. */
648 649 650 651 652
      GST_OBJECT_LOCK (dec);
      dec->proportion = proportion;
      dec->earliest_time = timestamp + diff;
      GST_OBJECT_UNLOCK (dec);

653 654 655
      GST_DEBUG_OBJECT (dec, "got QoS %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
          GST_TIME_ARGS (timestamp), diff);

656
      res = gst_pad_push_event (dec->sinkpad, event);
657 658
      break;
    }
Benjamin Otte's avatar
Benjamin Otte committed
659
    default:
660
      res = gst_pad_push_event (dec->sinkpad, event);
Benjamin Otte's avatar
Benjamin Otte committed
661 662
      break;
  }
663 664
done:
  gst_object_unref (dec);
Benjamin Otte's avatar
Benjamin Otte committed
665 666

  return res;
667

668 669 670 671 672 673
  /* ERRORS */
convert_error:
  {
    GST_DEBUG_OBJECT (dec, "could not convert format");
    goto done;
  }
674 675
}

676 677
static gboolean
theora_dec_sink_event (GstPad * pad, GstEvent * event)
Benjamin Otte's avatar
Benjamin Otte committed
678
{
679
  gboolean ret = FALSE;
680 681
  GstTheoraDec *dec;

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

Benjamin Otte's avatar
Benjamin Otte committed
684 685
  GST_LOG_OBJECT (dec, "handling event");
  switch (GST_EVENT_TYPE (event)) {
686 687 688 689 690 691 692
    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
693 694 695
    case GST_EVENT_EOS:
      ret = gst_pad_push_event (dec->srcpad, event);
      break;
696
    case GST_EVENT_NEWSEGMENT:
697
    {
698
      gboolean update;
699
      GstFormat format;
700
      gdouble rate, arate;
Wim Taymans's avatar
Wim Taymans committed
701
      gint64 start, stop, time;
702

703 704
      gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
          &start, &stop, &time);
705

706
      /* we need TIME format */
707 708 709
      if (format != GST_FORMAT_TIME)
        goto newseg_wrong_format;

710
      /* now configure the values */
711 712
      gst_segment_set_newsegment_full (&dec->segment, update,
          rate, arate, format, start, stop, time);
Wim Taymans's avatar
Wim Taymans committed
713
      dec->seqnum = gst_event_get_seqnum (event);
714

Wim Taymans's avatar
Wim Taymans committed
715
      /* We don't forward this unless/until the decoder is initialised */
716 717 718
      if (dec->have_header) {
        ret = gst_pad_push_event (dec->srcpad, event);
      } else {
Wim Taymans's avatar
Wim Taymans committed
719
        dec->pendingevents = g_list_append (dec->pendingevents, event);
720 721
        ret = TRUE;
      }
Benjamin Otte's avatar
Benjamin Otte committed
722
      break;
723
    }
724 725 726 727 728 729 730 731 732 733 734 735
    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
736
    default:
Wim Taymans's avatar
Wim Taymans committed
737
      ret = gst_pad_push_event (dec->srcpad, event);
Benjamin Otte's avatar
Benjamin Otte committed
738 739
      break;
  }
740
done:
Wim Taymans's avatar
Wim Taymans committed
741 742
  gst_object_unref (dec);

743
  return ret;
744 745 746 747

  /* ERRORS */
newseg_wrong_format:
  {
748
    GST_DEBUG_OBJECT (dec, "received non TIME newsegment");
749
    gst_event_unref (event);
750 751
    goto done;
  }
Benjamin Otte's avatar
Benjamin Otte committed
752 753
}

754 755 756 757 758
static gboolean
theora_dec_setcaps (GstPad * pad, GstCaps * caps)
{
  GstTheoraDec *dec;
  GstStructure *s;
759
  const GValue *codec_data;
760 761 762 763 764 765 766 767 768

  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));

  s = gst_caps_get_structure (caps, 0);

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

769 770 771 772 773 774 775 776 777 778 779 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
  if ((codec_data = gst_structure_get_value (s, "codec_data"))) {
    if (G_VALUE_TYPE (codec_data) == GST_TYPE_BUFFER) {
      GstBuffer *buffer;
      guint8 *data;
      guint size;
      guint offset;

      buffer = gst_value_get_buffer (codec_data);

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

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

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

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

        buf = gst_buffer_create_sub (buffer, offset, psize);

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

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

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

812 813 814 815 816
  gst_object_unref (dec);

  return TRUE;
}

817
static GstFlowReturn
818
theora_handle_comment_packet (GstTheoraDec * dec, ogg_packet * packet)
Benjamin Otte's avatar
Benjamin Otte committed
819
{
820
  gchar *encoder = NULL;
Benjamin Otte's avatar
Benjamin Otte committed
821
  GstBuffer *buf;
822 823
  GstTagList *list;

824
  GST_DEBUG_OBJECT (dec, "parsing comment packet");
825

826 827 828
  buf = gst_buffer_new ();
  GST_BUFFER_SIZE (buf) = packet->bytes;
  GST_BUFFER_DATA (buf) = packet->packet;
829

830 831
  list =
      gst_tag_list_from_vorbiscomment_buffer (buf, (guint8 *) "\201theora", 7,
832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848
      &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);

849 850 851 852 853 854
  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);
  }

855
  dec->tags = list;
856 857 858 859 860 861 862 863 864

  return GST_FLOW_OK;
}

static GstFlowReturn
theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet)
{
  GstCaps *caps;
  gint par_num, par_den;
865
  GstFlowReturn ret = GST_FLOW_OK;
866
  guint32 bitstream_version;
Wim Taymans's avatar
Wim Taymans committed
867
  GList *walk;
868
  guint32 fourcc;
869 870 871 872 873 874 875

  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;
876 877 878 879
   * 0:0 is allowed and can be interpreted as 1:1, so correct for it.
   * x:0 for other x isn't technically allowed, but it's seen in the wild and
   * is reasonable to treat the same. 
   */
880 881 882 883 884 885 886 887 888 889
  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;
  }
890
  if (par_den == 0) {
891 892 893 894 895
    par_num = par_den = 1;
  }
  /* theora has:
   *
   *  width/height : dimension of the encoded frame 
896 897
   *  frame_width/frame_height : dimension of the visible part
   *  offset_x/offset_y : offset in encoded frame where visible part starts
898
   */
899 900
  GST_DEBUG_OBJECT (dec, "dimension %dx%d, PAR %d/%d", dec->info.width,
      dec->info.height, par_num, par_den);
901
  GST_DEBUG_OBJECT (dec, "frame dimension %dx%d, offset %d:%d",
902 903
      dec->info.frame_width, dec->info.frame_height,
      dec->info.offset_x, dec->info.offset_y);
904

905
  if (dec->info.pixelformat == OC_PF_420) {
906 907
    dec->output_bpp = 12;       /* Average bits per pixel. */
    fourcc = GST_MAKE_FOURCC ('I', '4', '2', '0');
908
  } else if (dec->info.pixelformat == OC_PF_422) {
909
    dec->output_bpp = 16;
910
    fourcc = GST_MAKE_FOURCC ('Y', '4', '2', 'B');
911
  } else if (dec->info.pixelformat == OC_PF_444) {
912 913 914
    dec->output_bpp = 24;
    fourcc = GST_MAKE_FOURCC ('Y', '4', '4', '4');
  } else {
915
    GST_ERROR_OBJECT (dec, "Invalid pixel format %d", dec->info.pixelformat);