theoradec.c 21.9 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 20 21 22 23 24 25 26 27 28
/* 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.
 */

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#include <gst/gst.h>
#include <theora/theora.h>
#include <string.h>
#include <gst/tag/tag.h>

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
29 30
GST_DEBUG_CATEGORY (theoradec_debug);
#define GST_CAT_DEFAULT theoradec_debug
Benjamin Otte's avatar
Benjamin Otte committed
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45

#define GST_TYPE_THEORA_DEC \
  (gst_theora_dec_get_type())
#define GST_THEORA_DEC(obj) \
  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_THEORA_DEC,GstTheoraDec))
#define GST_THEORA_DEC_CLASS(klass) \
  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_THEORA_DEC,GstTheoraDec))
#define GST_IS_THEORA_DEC(obj) \
  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_THEORA_DEC))
#define GST_IS_THEORA_DEC_CLASS(obj) \
  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_THEORA_DEC))

typedef struct _GstTheoraDec GstTheoraDec;
typedef struct _GstTheoraDecClass GstTheoraDecClass;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
46 47 48 49 50 51 52 53 54 55 56 57 58
struct _GstTheoraDec
{
  GstElement element;

  GstPad *sinkpad;
  GstPad *srcpad;

  theora_state state;
  theora_info info;
  theora_comment comment;

  guint packetno;
  guint64 granulepos;
59 60

  gboolean need_keyframe;
61 62
  gint width, height;
  gint offset_x, offset_y;
Benjamin Otte's avatar
Benjamin Otte committed
63 64
};

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
65 66
struct _GstTheoraDecClass
{
Benjamin Otte's avatar
Benjamin Otte committed
67 68 69 70 71
  GstElementClass parent_class;
};

static GstElementDetails theora_dec_details = {
  "TheoraDec",
72
  "Codec/Decoder/Video",
Benjamin Otte's avatar
Benjamin Otte committed
73
  "decode raw theora streams to raw YUV video",
74 75
  "Benjamin Otte <in7y118@public.uni-hamburg.de>, "
      "Wim Taymans <wim@fluendo.com>",
Benjamin Otte's avatar
Benjamin Otte committed
76 77 78
};

static GstStaticPadTemplate theora_dec_src_factory =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
79 80 81 82
GST_STATIC_PAD_TEMPLATE ("src",
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("video/x-raw-yuv, "
83 84 85
        "format = (fourcc) I420, "
        "framerate = (double) [0, MAX], "
        "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
86
    );
Benjamin Otte's avatar
Benjamin Otte committed
87 88

static GstStaticPadTemplate theora_dec_sink_factory =
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
89 90 91 92 93
GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("video/x-theora")
    );
Benjamin Otte's avatar
Benjamin Otte committed
94 95

GST_BOILERPLATE (GstTheoraDec, gst_theora_dec, GstElement, GST_TYPE_ELEMENT);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
96 97 98 99 100 101

static void theora_dec_chain (GstPad * pad, GstData * data);
static GstElementStateReturn theora_dec_change_state (GstElement * element);
static gboolean theora_dec_src_event (GstPad * pad, GstEvent * event);
static gboolean theora_dec_src_query (GstPad * pad,
    GstQueryType query, GstFormat * format, gint64 * value);
102 103 104 105 106 107 108 109 110
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);
static const GstFormat *theora_get_formats (GstPad * pad);
static const GstEventMask *theora_get_event_masks (GstPad * pad);
static const GstQueryType *theora_get_query_types (GstPad * pad);
Benjamin Otte's avatar
Benjamin Otte committed
111 112 113 114 115 116


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

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

  gstelement_class->change_state = theora_dec_change_state;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
131 132

  GST_DEBUG_CATEGORY_INIT (theoradec_debug, "theoradec", 0, "Theora decoder");
Benjamin Otte's avatar
Benjamin Otte committed
133 134 135
}

static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
136
gst_theora_dec_init (GstTheoraDec * dec)
Benjamin Otte's avatar
Benjamin Otte committed
137
{
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
138 139 140
  dec->sinkpad =
      gst_pad_new_from_template (gst_static_pad_template_get
      (&theora_dec_sink_factory), "sink");
141 142
  gst_pad_set_formats_function (dec->sinkpad, theora_get_formats);
  gst_pad_set_convert_function (dec->sinkpad, theora_dec_sink_convert);
Benjamin Otte's avatar
Benjamin Otte committed
143 144 145
  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
146 147 148
  dec->srcpad =
      gst_pad_new_from_template (gst_static_pad_template_get
      (&theora_dec_src_factory), "src");
Benjamin Otte's avatar
Benjamin Otte committed
149
  gst_pad_use_explicit_caps (dec->srcpad);
150
  gst_pad_set_event_mask_function (dec->srcpad, theora_get_event_masks);
Benjamin Otte's avatar
Benjamin Otte committed
151
  gst_pad_set_event_function (dec->srcpad, theora_dec_src_event);
152
  gst_pad_set_query_type_function (dec->srcpad, theora_get_query_types);
153
  gst_pad_set_query_function (dec->srcpad, theora_dec_src_query);
154 155 156
  gst_pad_set_formats_function (dec->srcpad, theora_get_formats);
  gst_pad_set_convert_function (dec->srcpad, theora_dec_src_convert);

Benjamin Otte's avatar
Benjamin Otte committed
157 158 159 160
  gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);

  GST_FLAG_SET (dec, GST_ELEMENT_EVENT_AWARE);
}
161 162

/* FIXME: copy from libtheora, theora should somehow make this available for seeking */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
163 164 165 166 167 168
static int
_theora_ilog (unsigned int v)
{
  int ret = 0;

  while (v) {
169
    ret++;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
170
    v >>= 1;
171
  }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
172
  return (ret);
173 174
}

175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
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);
}

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

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

  return theora_src_query_types;
}


217
static gboolean
218 219 220
theora_dec_src_convert (GstPad * pad,
    GstFormat src_format, gint64 src_value,
    GstFormat * dest_format, gint64 * dest_value)
221
{
222 223 224 225 226
  gboolean res = TRUE;
  GstTheoraDec *dec;
  guint64 scale = 1;

  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
227

228
  /* we need the info part before we can done something */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
229 230 231
  if (dec->packetno < 1)
    return FALSE;

232 233 234 235 236 237 238 239 240 241 242 243 244
  switch (src_format) {
    case GST_FORMAT_BYTES:
      switch (*dest_format) {
        case GST_FORMAT_DEFAULT:
          *dest_value =
              src_value * 2 / (dec->info.height * dec->info.width * 3);
          break;
        case GST_FORMAT_TIME:
          /* seems like a rather silly conversion, implement me if you like */
        default:
          res = FALSE;
      }
      break;
245
    case GST_FORMAT_TIME:
246 247
      switch (*dest_format) {
        case GST_FORMAT_BYTES:
248
          scale = 3 * (dec->info.width * dec->info.height) / 2;
249
        case GST_FORMAT_DEFAULT:
250 251 252
          *dest_value =
              scale * (((guint64) src_value * dec->info.fps_numerator) /
              (dec->info.fps_denominator * GST_SECOND));
253 254 255 256
          break;
        default:
          res = FALSE;
      }
257 258
      break;
    case GST_FORMAT_DEFAULT:
259 260 261 262 263 264 265 266 267 268 269 270
      switch (*dest_format) {
        case GST_FORMAT_TIME:
          *dest_value = src_value * (GST_SECOND * dec->info.fps_denominator /
              dec->info.fps_numerator);
          break;
        case GST_FORMAT_BYTES:
          *dest_value =
              src_value * 3 * (dec->info.width * dec->info.height) / 2;
          break;
        default:
          res = FALSE;
      }
271 272
      break;
    default:
273
      res = FALSE;
274
  }
275 276

  return res;
277 278
}

Benjamin Otte's avatar
Benjamin Otte committed
279
static gboolean
280 281 282
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
283
{
284 285
  gboolean res = TRUE;
  GstTheoraDec *dec;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
286

287 288 289
  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));

  /* we need the info part before we can done something */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
290 291 292
  if (dec->packetno < 1)
    return FALSE;

293
  switch (src_format) {
Benjamin Otte's avatar
Benjamin Otte committed
294
    case GST_FORMAT_DEFAULT:
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
    {
      guint64 framecount;
      guint ilog;

      ilog = _theora_ilog (dec->info.keyframe_frequency_force - 1);

      /* 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 = src_value >> ilog;
      framecount += src_value - (framecount << ilog);

      switch (*dest_format) {
        case GST_FORMAT_TIME:
          *dest_value = framecount * (GST_SECOND * dec->info.fps_denominator /
              dec->info.fps_numerator);
          break;
        default:
          res = FALSE;
      }
314
      break;
315
    }
Benjamin Otte's avatar
Benjamin Otte committed
316
    default:
317
      res = FALSE;
Benjamin Otte's avatar
Benjamin Otte committed
318
  }
319 320

  return res;
Benjamin Otte's avatar
Benjamin Otte committed
321
}
322 323

static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
324 325
theora_dec_src_query (GstPad * pad, GstQueryType query, GstFormat * format,
    gint64 * value)
326 327 328 329
{
  gint64 granulepos;
  GstTheoraDec *dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
  GstFormat my_format = GST_FORMAT_DEFAULT;
330
  guint64 time;
331

332
  if (query == GST_QUERY_POSITION) {
333
    /* this is easy, we can convert a granule position to everything */
334 335
    granulepos = dec->granulepos;
  } else {
336
    /* for the total, we just forward the query to the peer */
337 338 339 340
    if (!gst_pad_query (GST_PAD_PEER (dec->sinkpad), query, &my_format,
            &granulepos))
      return FALSE;
  }
341

342 343 344
  /* and convert to the final format in two steps with time as the 
   * intermediate step */
  my_format = GST_FORMAT_TIME;
345
  if (!theora_dec_sink_convert (dec->sinkpad, GST_FORMAT_DEFAULT, granulepos,
346 347
          &my_format, &time))
    return FALSE;
348
  if (!gst_pad_convert (pad, my_format, time, format, value))
349 350
    return FALSE;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
351
  GST_LOG_OBJECT (dec,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
352
      "query %u: peer returned granulepos: %llu - we return %llu (format %u)",
353 354 355 356
      query, granulepos, *value, *format);
  return TRUE;
}

Benjamin Otte's avatar
Benjamin Otte committed
357
static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
358
theora_dec_src_event (GstPad * pad, GstEvent * event)
Benjamin Otte's avatar
Benjamin Otte committed
359 360 361
{
  gboolean res = TRUE;
  GstTheoraDec *dec;
362
  GstFormat format;
Benjamin Otte's avatar
Benjamin Otte committed
363 364 365 366

  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));

  switch (GST_EVENT_TYPE (event)) {
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
367
    case GST_EVENT_SEEK:{
Benjamin Otte's avatar
Benjamin Otte committed
368
      guint64 value;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
369

370 371 372 373 374 375 376 377
      /* 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 
       */
      format = GST_FORMAT_TIME;
      res = gst_pad_convert (pad, GST_EVENT_SEEK_FORMAT (event),
378
          GST_EVENT_SEEK_OFFSET (event), &format, &value);
379 380
      if (!res)
        goto error;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
381

382 383 384 385 386 387 388 389 390 391 392 393 394
      /* then seek with time on the peer */
      GstEvent *real_seek = gst_event_new_seek (
          (GST_EVENT_SEEK_TYPE (event) & ~GST_SEEK_FORMAT_MASK) |
          format, value);

      res = gst_pad_send_event (GST_PAD_PEER (dec->sinkpad), real_seek);
      if (!res)
        goto error;

      /* all worked, make sure we sync to keyframe */
      dec->need_keyframe = TRUE;

    error:
Benjamin Otte's avatar
Benjamin Otte committed
395 396 397 398 399 400 401 402 403 404 405 406
      gst_event_unref (event);
      break;
    }
    default:
      res = gst_pad_event_default (pad, event);
      break;
  }

  return res;
}

static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
407
theora_dec_event (GstTheoraDec * dec, GstEvent * event)
Benjamin Otte's avatar
Benjamin Otte committed
408
{
409
  guint64 value, time, bytes;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
410

Benjamin Otte's avatar
Benjamin Otte committed
411 412 413 414
  GST_LOG_OBJECT (dec, "handling event");
  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_DISCONTINUOUS:
      if (gst_event_discont_get_value (event, GST_FORMAT_DEFAULT, &value)) {
415 416
        dec->granulepos = value;
        GST_DEBUG_OBJECT (dec,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
417
            "setting granuleposition to %" G_GUINT64_FORMAT " after discont",
418
            value);
Benjamin Otte's avatar
Benjamin Otte committed
419
      } else {
420 421
        GST_WARNING_OBJECT (dec,
            "discont event didn't include offset, we might set it wrong now");
Benjamin Otte's avatar
Benjamin Otte committed
422
      }
423
      if (dec->packetno < 3) {
424 425 426 427 428 429 430
        if (dec->granulepos != 0)
          GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL),
              ("can't handle discont before parsing first 3 packets"));
        dec->packetno = 0;
        gst_pad_push (dec->srcpad, GST_DATA (gst_event_new_discontinuous (FALSE,
                    GST_FORMAT_TIME, (guint64) 0, GST_FORMAT_DEFAULT,
                    (guint64) 0, GST_FORMAT_BYTES, (guint64) 0, 0)));
431
      } else {
432 433 434 435 436 437
        GstFormat time_format, default_format, bytes_format;

        time_format = GST_FORMAT_TIME;
        default_format = GST_FORMAT_DEFAULT;
        bytes_format = GST_FORMAT_BYTES;

438
        /* if one of them works, all of them work */
439 440 441 442 443 444
        if (theora_dec_sink_convert (dec->sinkpad, GST_FORMAT_DEFAULT,
                dec->granulepos, &time_format, &time)
            && theora_dec_src_convert (dec->srcpad, GST_FORMAT_TIME, time,
                &default_format, &value)
            && theora_dec_src_convert (dec->srcpad, GST_FORMAT_TIME, time,
                &bytes_format, &bytes)) {
445 446 447 448
          gst_pad_push (dec->srcpad,
              GST_DATA (gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
                      time, GST_FORMAT_DEFAULT, value, GST_FORMAT_BYTES, bytes,
                      0)));
449 450
          /* store new framenumber */
          dec->packetno = value + 3;
451 452 453 454
        } else {
          GST_ERROR_OBJECT (dec,
              "failed to parse data for DISCONT event, not sending any");
        }
455 456
        /* sync to keyframe */
        dec->need_keyframe = TRUE;
457
      }
Benjamin Otte's avatar
Benjamin Otte committed
458 459 460 461 462 463 464
      break;
    default:
      break;
  }
  gst_pad_event_default (dec->sinkpad, event);
}

465 466 467 468
#define ROUND_UP_2(x) (((x) + 1) & ~1)
#define ROUND_UP_4(x) (((x) + 3) & ~3)
#define ROUND_UP_8(x) (((x) + 7) & ~7)

Benjamin Otte's avatar
Benjamin Otte committed
469
static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
470
theora_dec_chain (GstPad * pad, GstData * data)
Benjamin Otte's avatar
Benjamin Otte committed
471 472 473 474
{
  GstBuffer *buf;
  GstTheoraDec *dec;
  ogg_packet packet;
475
  guint64 offset_end;
476
  GstClockTime outtime;
Benjamin Otte's avatar
Benjamin Otte committed
477 478 479 480 481 482 483 484

  dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
  if (GST_IS_EVENT (data)) {
    theora_dec_event (dec, GST_EVENT (data));
    return;
  }

  buf = GST_BUFFER (data);
485

486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
  if (dec->packetno >= 3) {
    offset_end = GST_BUFFER_OFFSET_END (buf);
    if (offset_end != -1) {
      dec->granulepos = offset_end;
      /* granulepos to time */
      outtime = GST_SECOND * theora_granule_time (&dec->state, dec->granulepos);
    } else {
      GstFormat time_format = GST_FORMAT_TIME;

      /* framenumber to time */
      theora_dec_src_convert (dec->srcpad, GST_FORMAT_DEFAULT,
          dec->packetno - 3, &time_format, &outtime);
    }
  } else {
    /* we don't know yet */
    outtime = -1;
502 503
  }

Benjamin Otte's avatar
Benjamin Otte committed
504 505 506
  /* make ogg_packet out of the buffer */
  packet.packet = GST_BUFFER_DATA (buf);
  packet.bytes = GST_BUFFER_SIZE (buf);
507
  packet.granulepos = dec->granulepos;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
508
  packet.packetno = dec->packetno++;
509 510
  packet.b_o_s = (packet.packetno == 0) ? 1 : 0;
  packet.e_o_s = 0;
511

Benjamin Otte's avatar
Benjamin Otte committed
512 513 514 515
  /* switch depending on packet type */
  if (packet.packet[0] & 0x80) {
    /* header packet */
    if (theora_decode_header (&dec->info, &dec->comment, &packet)) {
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
516
      GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
517
          (NULL), ("couldn't read header packet"));
Benjamin Otte's avatar
Benjamin Otte committed
518 519 520 521
      gst_data_unref (data);
      return;
    }
    if (packet.packetno == 1) {
522
      gchar *encoder = NULL;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
523
      GstTagList *list =
524 525
          gst_tag_list_from_vorbiscomment_buffer (buf, "\201theora", 7,
          &encoder);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
526

527
      if (!list) {
528 529
        GST_ERROR_OBJECT (dec, "failed to parse tags");
        list = gst_tag_list_new ();
530 531
      }
      if (encoder) {
532 533 534
        gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
            GST_TAG_ENCODER, encoder, NULL);
        g_free (encoder);
535
      }
Benjamin Otte's avatar
Benjamin Otte committed
536
      gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
537
          GST_TAG_ENCODER_VERSION, dec->info.version_major, NULL);
Benjamin Otte's avatar
Benjamin Otte committed
538 539 540
      gst_element_found_tags_for_pad (GST_ELEMENT (dec), dec->srcpad, 0, list);
    } else if (packet.packetno == 2) {
      GstCaps *caps;
541 542 543 544 545 546 547 548 549 550 551 552 553
      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;
554

555
      }
556 557 558 559 560 561 562
      /* 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,
563
          dec->info.height, par_num, par_den);
564 565 566
      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);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
567

568 569 570 571 572 573 574 575 576 577 578 579
      /* 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;

      GST_DEBUG_OBJECT (dec, "after fixup frame dimension %dx%d, offset %d:%d",
          dec->width, dec->height, dec->offset_x, dec->offset_y);

Benjamin Otte's avatar
Benjamin Otte committed
580 581 582
      /* done */
      theora_decode_init (&dec->state, &dec->info);
      caps = gst_caps_new_simple ("video/x-raw-yuv",
583 584 585
          "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
          "framerate", G_TYPE_DOUBLE,
          ((gdouble) dec->info.fps_numerator) / dec->info.fps_denominator,
586
          "pixel-aspect-ratio", GST_TYPE_FRACTION, par_num, par_den,
587 588
          "width", G_TYPE_INT, dec->width, "height", G_TYPE_INT,
          dec->height, NULL);
Benjamin Otte's avatar
Benjamin Otte committed
589 590 591 592
      gst_pad_set_explicit_caps (dec->srcpad, caps);
      gst_caps_free (caps);
    }
  } else {
593
    /* normal data packet */
Benjamin Otte's avatar
Benjamin Otte committed
594 595 596
    yuv_buffer yuv;
    GstBuffer *out;
    guint i;
597
    gboolean keyframe;
598 599 600 601
    gint out_size;
    gint stride_y, stride_uv;
    gint width, height;
    gint cwidth, cheight;
602 603 604 605 606 607 608 609 610 611 612

    /* 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) {
      /* drop frames if we're looking for a keyframe */
      gst_data_unref (data);
      return;
    }
613 614 615 616 617
    if (theora_decode_packetin (&dec->state, &packet)) {
      GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
          (NULL), ("theora decoder did not read data packet"));
      gst_data_unref (data);
      return;
618
    }
619 620 621 622 623 624
    if (theora_decode_YUVout (&dec->state, &yuv) < 0) {
      GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
          (NULL), ("couldn't read out YUV image"));
      gst_data_unref (data);
      return;
    }
625

626 627
    g_return_if_fail (yuv.y_width == dec->info.width);
    g_return_if_fail (yuv.y_height == dec->info.height);
628

629 630 631 632
    width = dec->width;
    height = dec->height;
    cwidth = width / 2;
    cheight = height / 2;
633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649

    /* 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 */
    out = gst_pad_alloc_buffer (dec->srcpad, GST_BUFFER_OFFSET_NONE, out_size);

    /* 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
     * 1 row/column of luma samples with on chroma sample in colorspace conversion. 
650 651
     * We compensate for this by adding a block border around the image when the
     * offset of size is odd (see above).
652 653 654 655 656 657 658 659
     */
    {
      guint8 *dest_y, *src_y;
      guint8 *dest_u, *src_u;
      guint8 *dest_v, *src_v;

      dest_y = GST_BUFFER_DATA (out);
      dest_u = dest_y + stride_y * height;
660
      dest_v = dest_u + stride_uv * cheight;
661

662
      src_y = yuv.y + dec->offset_x + dec->offset_y * yuv.y_stride;
663 664 665 666 667 668 669 670

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

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

671 672
      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;
673 674 675 676 677 678 679 680 681 682

      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;
      }
683
    }
684

685 686 687 688 689 690 691
    GST_BUFFER_OFFSET (out) = dec->packetno - 4;
    GST_BUFFER_OFFSET_END (out) = dec->packetno - 3;
    GST_BUFFER_DURATION (out) =
        GST_SECOND * ((gdouble) dec->info.fps_denominator) /
        dec->info.fps_numerator;
    GST_BUFFER_TIMESTAMP (out) = outtime;

Benjamin Otte's avatar
Benjamin Otte committed
692 693 694 695 696 697
    gst_pad_push (dec->srcpad, GST_DATA (out));
  }
  gst_data_unref (data);
}

static GstElementStateReturn
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
698
theora_dec_change_state (GstElement * element)
Benjamin Otte's avatar
Benjamin Otte committed
699 700 701 702 703 704 705 706 707
{
  GstTheoraDec *dec = GST_THEORA_DEC (element);

  switch (GST_STATE_TRANSITION (element)) {
    case GST_STATE_NULL_TO_READY:
      break;
    case GST_STATE_READY_TO_PAUSED:
      theora_info_init (&dec->info);
      theora_comment_init (&dec->comment);
708
      dec->need_keyframe = TRUE;
Benjamin Otte's avatar
Benjamin Otte committed
709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728
      break;
    case GST_STATE_PAUSED_TO_PLAYING:
      break;
    case GST_STATE_PLAYING_TO_PAUSED:
      break;
    case GST_STATE_PAUSED_TO_READY:
      theora_clear (&dec->state);
      theora_comment_clear (&dec->comment);
      theora_info_clear (&dec->info);
      dec->packetno = 0;
      dec->granulepos = 0;
      break;
    case GST_STATE_READY_TO_NULL:
      break;
    default:
      break;
  }

  return parent_class->change_state (element);
}