gsttheoradec.c 24.2 KB
Newer Older
Benjamin Otte's avatar
Benjamin Otte committed
1 2
/* GStreamer
 * Copyright (C) 2004 Benjamin Otte <in7y118@public.uni-hamburg.de>
3 4 5
 * Copyright (c) 2012 Collabora Ltd.
 *	Author : Edward Hervey <edward@collabora.com>
 *      Author : Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
Benjamin Otte's avatar
Benjamin Otte committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * 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
23 24 25 26 27 28 29 30
/**
 * 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.
31 32
 *
 * <refsect2>
Wim Taymans's avatar
Wim Taymans committed
33
 * <title>Example pipeline</title>
34
 * |[
Wim Taymans's avatar
Wim Taymans committed
35
 * gst-launch -v filesrc location=videotestsrc.ogg ! oggdemux ! theoradec ! xvimagesink
36
 * ]| This example pipeline will decode an ogg stream and decodes the theora video. Refer to
Wim Taymans's avatar
Wim Taymans committed
37 38 39 40 41 42
 * 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
43 44 45 46
#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

Wim Taymans's avatar
Wim Taymans committed
47
#include "gsttheoradec.h"
Benjamin Otte's avatar
Benjamin Otte committed
48
#include <gst/tag/tag.h>
49
#include <gst/video/video.h>
50 51
#include <gst/video/gstvideometa.h>
#include <gst/video/gstvideopool.h>
Benjamin Otte's avatar
Benjamin Otte committed
52

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
53
#define GST_CAT_DEFAULT theoradec_debug
54
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
55
GST_DEBUG_CATEGORY_EXTERN (GST_CAT_PERFORMANCE);
Benjamin Otte's avatar
Benjamin Otte committed
56

57 58 59 60 61
#define THEORA_DEF_TELEMETRY_MV 0
#define THEORA_DEF_TELEMETRY_MBMODE 0
#define THEORA_DEF_TELEMETRY_QI 0
#define THEORA_DEF_TELEMETRY_BITS 0

62 63
enum
{
64
  PROP_0,
65 66 67 68
  PROP_TELEMETRY_MV,
  PROP_TELEMETRY_MBMODE,
  PROP_TELEMETRY_QI,
  PROP_TELEMETRY_BITS
69 70
};

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

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

88 89
#define gst_theora_dec_parent_class parent_class
G_DEFINE_TYPE (GstTheoraDec, gst_theora_dec, GST_TYPE_VIDEO_DECODER);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
90

91 92 93 94 95
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);

96 97 98 99 100 101 102 103 104 105 106 107
static gboolean theora_dec_start (GstVideoDecoder * decoder);
static gboolean theora_dec_stop (GstVideoDecoder * decoder);
static gboolean theora_dec_set_format (GstVideoDecoder * decoder,
    GstVideoCodecState * state);
static gboolean theora_dec_reset (GstVideoDecoder * decoder, gboolean hard);
static GstFlowReturn theora_dec_parse (GstVideoDecoder * decoder,
    GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos);
static GstFlowReturn theora_dec_handle_frame (GstVideoDecoder * decoder,
    GstVideoCodecFrame * frame);

static GstFlowReturn theora_dec_decode_buffer (GstTheoraDec * dec,
    GstBuffer * buf, GstVideoCodecFrame * frame);
Benjamin Otte's avatar
Benjamin Otte committed
108

109 110 111 112 113 114 115
static gboolean
gst_theora_dec_ctl_is_supported (int req)
{
  /* should return TH_EFAULT or TH_EINVAL if supported, and TH_EIMPL if not */
  return (th_decode_ctl (NULL, req, NULL, 0) != TH_EIMPL);
}

Benjamin Otte's avatar
Benjamin Otte committed
116
static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
117
gst_theora_dec_class_init (GstTheoraDecClass * klass)
Benjamin Otte's avatar
Benjamin Otte committed
118
{
119
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
120
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
121
  GstVideoDecoderClass *video_decoder_class = GST_VIDEO_DECODER_CLASS (klass);
Benjamin Otte's avatar
Benjamin Otte committed
122

123 124 125
  gobject_class->set_property = theora_dec_set_property;
  gobject_class->get_property = theora_dec_get_property;

126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
  if (gst_theora_dec_ctl_is_supported (TH_DECCTL_SET_TELEMETRY_MV)) {
    g_object_class_install_property (gobject_class, PROP_TELEMETRY_MV,
        g_param_spec_int ("visualize-motion-vectors",
            "Visualize motion vectors",
            "Show motion vector selection overlaid on image. "
            "Value gives a mask for motion vector (MV) modes to show",
            0, 0xffff, THEORA_DEF_TELEMETRY_MV,
            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  }

  if (gst_theora_dec_ctl_is_supported (TH_DECCTL_SET_TELEMETRY_MBMODE)) {
    g_object_class_install_property (gobject_class, PROP_TELEMETRY_MBMODE,
        g_param_spec_int ("visualize-macroblock-modes",
            "Visualize macroblock modes",
            "Show macroblock mode selection overlaid on image. "
            "Value gives a mask for macroblock (MB) modes to show",
            0, 0xffff, THEORA_DEF_TELEMETRY_MBMODE,
            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  }

  if (gst_theora_dec_ctl_is_supported (TH_DECCTL_SET_TELEMETRY_QI)) {
    g_object_class_install_property (gobject_class, PROP_TELEMETRY_QI,
        g_param_spec_int ("visualize-quantization-modes",
            "Visualize adaptive quantization modes",
            "Show adaptive quantization mode selection overlaid on image. "
            "Value gives a mask for quantization (QI) modes to show",
            0, 0xffff, THEORA_DEF_TELEMETRY_QI,
            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  }

  if (gst_theora_dec_ctl_is_supported (TH_DECCTL_SET_TELEMETRY_BITS)) {
    /* FIXME: make this a boolean instead? The value scales the bars so
     * they're less wide. Default is to use full width, and anything else
     * doesn't seem particularly useful, since the smaller bars just disappear
     * then (they almost disappear for a value of 2 already). */
    g_object_class_install_property (gobject_class, PROP_TELEMETRY_BITS,
        g_param_spec_int ("visualize-bit-usage",
            "Visualize bitstream usage breakdown",
            "Sets the bitstream breakdown visualization mode. "
            "Values influence the width of the bit usage bars to show",
            0, 0xff, THEORA_DEF_TELEMETRY_BITS,
            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  }
169

170 171 172 173 174 175 176 177 178
  gst_element_class_add_pad_template (element_class,
      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_simple (element_class,
      "Theora video decoder", "Codec/Decoder/Video",
      "decode raw theora streams to raw YUV video",
      "Benjamin Otte <otte@gnome.org>, Wim Taymans <wim@fluendo.com>");

179 180 181 182 183 184 185
  video_decoder_class->start = GST_DEBUG_FUNCPTR (theora_dec_start);
  video_decoder_class->stop = GST_DEBUG_FUNCPTR (theora_dec_stop);
  video_decoder_class->reset = GST_DEBUG_FUNCPTR (theora_dec_reset);
  video_decoder_class->set_format = GST_DEBUG_FUNCPTR (theora_dec_set_format);
  video_decoder_class->parse = GST_DEBUG_FUNCPTR (theora_dec_parse);
  video_decoder_class->handle_frame =
      GST_DEBUG_FUNCPTR (theora_dec_handle_frame);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
186 187

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

static void
191
gst_theora_dec_init (GstTheoraDec * dec)
Benjamin Otte's avatar
Benjamin Otte committed
192
{
193 194 195 196
  dec->telemetry_mv = THEORA_DEF_TELEMETRY_MV;
  dec->telemetry_mbmode = THEORA_DEF_TELEMETRY_MBMODE;
  dec->telemetry_qi = THEORA_DEF_TELEMETRY_QI;
  dec->telemetry_bits = THEORA_DEF_TELEMETRY_BITS;
197 198 199

  /* input is packetized,
   * but is not marked that way so data gets parsed and keyframes marked */
Benjamin Otte's avatar
Benjamin Otte committed
200
}
201

202 203 204 205
static void
gst_theora_dec_reset (GstTheoraDec * dec)
{
  dec->need_keyframe = TRUE;
206 207
}

208
static gboolean
209
theora_dec_start (GstVideoDecoder * decoder)
210
{
211
  GstTheoraDec *dec = GST_THEORA_DEC (decoder);
Wim Taymans's avatar
Wim Taymans committed
212

213 214 215 216 217 218
  GST_DEBUG_OBJECT (dec, "start");
  th_info_clear (&dec->info);
  th_comment_clear (&dec->comment);
  GST_DEBUG_OBJECT (dec, "Setting have_header to FALSE");
  dec->have_header = FALSE;
  gst_theora_dec_reset (dec);
219

220
  return TRUE;
221 222
}

Benjamin Otte's avatar
Benjamin Otte committed
223
static gboolean
224
theora_dec_stop (GstVideoDecoder * decoder)
Benjamin Otte's avatar
Benjamin Otte committed
225
{
226 227 228 229 230 231 232 233 234 235 236 237 238
  GstTheoraDec *dec = GST_THEORA_DEC (decoder);

  GST_DEBUG_OBJECT (dec, "stop");
  th_info_clear (&dec->info);
  th_comment_clear (&dec->comment);
  th_setup_free (dec->setup);
  dec->setup = NULL;
  th_decode_free (dec->decoder);
  dec->decoder = NULL;
  gst_theora_dec_reset (dec);
  if (dec->tags) {
    gst_tag_list_free (dec->tags);
    dec->tags = NULL;
Benjamin Otte's avatar
Benjamin Otte committed
239
  }
240

241
  return TRUE;
Benjamin Otte's avatar
Benjamin Otte committed
242
}
243

244
/* FIXME : Do we want to handle hard resets differently ? */
245
static gboolean
246
theora_dec_reset (GstVideoDecoder * bdec, gboolean hard)
247
{
248 249
  gst_theora_dec_reset (GST_THEORA_DEC (bdec));
  return TRUE;
Wim Taymans's avatar
Wim Taymans committed
250 251
}

252 253 254
static GstFlowReturn
theora_dec_parse (GstVideoDecoder * decoder,
    GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos)
Benjamin Otte's avatar
Benjamin Otte committed
255
{
256 257
  gint av;
  const guint8 *data;
Benjamin Otte's avatar
Benjamin Otte committed
258

259
  av = gst_adapter_available (adapter);
Benjamin Otte's avatar
Benjamin Otte committed
260

261
  data = gst_adapter_map (adapter, 1);
262 263 264
  /* check for keyframe; must not be header packet */
  if (!(data[0] & 0x80) && (data[0] & 0x40) == 0)
    GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
265
  gst_adapter_unmap (adapter);
266

267 268 269
  /* and pass along all */
  gst_video_decoder_add_to_frame (decoder, av);
  return gst_video_decoder_have_frame (decoder);
270 271
}

Benjamin Otte's avatar
Benjamin Otte committed
272

273
static gboolean
274
theora_dec_set_format (GstVideoDecoder * bdec, GstVideoCodecState * state)
275 276 277
{
  GstTheoraDec *dec;

278
  dec = GST_THEORA_DEC (bdec);
279

280 281 282 283
  /* Keep a copy of the input state */
  if (dec->input_state)
    gst_video_codec_state_unref (dec->input_state);
  dec->input_state = gst_video_codec_state_ref (state);
284

285 286 287
  /* FIXME : Interesting, we always accept any kind of caps ? */
  if (state->codec_data) {
    GstBuffer *buffer;
288
    GstMapInfo minfo;
289 290 291
    guint8 *data;
    guint size;
    guint offset;
292

293
    buffer = state->codec_data;
294
    gst_buffer_map (buffer, &minfo, GST_MAP_READ);
295

296
    offset = 0;
297 298
    size = minfo.size;
    data = (guint8 *) minfo.data;
299

300 301 302
    while (size > 2) {
      guint psize;
      GstBuffer *buf;
303

304 305 306 307 308
      psize = (data[0] << 8) | data[1];
      /* skip header */
      data += 2;
      size -= 2;
      offset += 2;
309

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

313
      buf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset, psize);
314

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

319 320 321
      /* now feed it to the decoder we can ignore the error */
      theora_dec_decode_buffer (dec, buf, NULL);
      gst_buffer_unref (buf);
322

323 324 325 326
      /* skip the data */
      size -= psize;
      data += psize;
      offset += psize;
327
    }
328 329

    gst_buffer_unmap (buffer, &minfo);
330 331
  }

332
  GST_DEBUG_OBJECT (dec, "Done");
333 334 335 336

  return TRUE;
}

337
static GstFlowReturn
338
theora_handle_comment_packet (GstTheoraDec * dec, ogg_packet * packet)
Benjamin Otte's avatar
Benjamin Otte committed
339
{
340 341 342
  gchar *encoder = NULL;
  GstTagList *list;

343
  GST_DEBUG_OBJECT (dec, "parsing comment packet");
344

345
  list =
346 347
      gst_tag_list_from_vorbiscomment (packet->packet, packet->bytes,
      (guint8 *) "\201theora", 7, &encoder);
348 349 350

  if (!list) {
    GST_ERROR_OBJECT (dec, "couldn't decode comments");
351
    list = gst_tag_list_new_empty ();
352 353 354 355 356 357 358 359 360 361
  }
  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);

362 363 364 365 366 367
  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);
  }

368 369
  if (dec->tags)
    gst_tag_list_free (dec->tags);
370
  dec->tags = list;
371 372 373 374 375 376 377 378

  return GST_FLOW_OK;
}

static GstFlowReturn
theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet)
{
  gint par_num, par_den;
379
  GstFlowReturn ret = GST_FLOW_OK;
380 381 382
  GstVideoCodecState *state;
  GstVideoFormat fmt;
  GstVideoInfo *info = &dec->input_state->info;
383 384 385 386 387 388 389

  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;
390
   * 0:x and x:0 are allowed and can be interpreted as 1:1.
391
   */
392 393 394 395 396 397
  par_num = GST_VIDEO_INFO_PAR_N (info);
  par_den = GST_VIDEO_INFO_PAR_D (info);

  /* If we have a default PAR, see if the decoder specified a different one */
  if (par_num == 1 && par_den == 1 &&
      (dec->info.aspect_numerator != 0 && dec->info.aspect_denominator != 0)) {
398 399 400
    par_num = dec->info.aspect_numerator;
    par_den = dec->info.aspect_denominator;
  }
401 402 403
  /* theora has:
   *
   *  width/height : dimension of the encoded frame 
404 405
   *  pic_width/pic_height : dimension of the visible part
   *  pic_x/pic_y : offset in encoded frame where visible part starts
406
   */
407 408
  GST_DEBUG_OBJECT (dec, "dimension %dx%d, PAR %d/%d", dec->info.pic_width,
      dec->info.pic_height, par_num, par_den);
409
  GST_DEBUG_OBJECT (dec, "frame dimension %dx%d, offset %d:%d",
410 411
      dec->info.pic_width, dec->info.pic_height,
      dec->info.pic_x, dec->info.pic_y);
412

413 414 415 416 417 418 419 420 421 422 423 424
  switch (dec->info.pixel_fmt) {
    case TH_PF_420:
      fmt = GST_VIDEO_FORMAT_I420;
      break;
    case TH_PF_422:
      fmt = GST_VIDEO_FORMAT_Y42B;
      break;
    case TH_PF_444:
      fmt = GST_VIDEO_FORMAT_Y444;
      break;
    default:
      goto unsupported_format;
425
  }
426

427 428 429 430 431 432 433
  /* FIXME: Use crop metadata */

  /* no cropping, use the encoded dimensions */
  GST_VIDEO_INFO_WIDTH (info) = dec->info.frame_width;
  GST_VIDEO_INFO_HEIGHT (info) = dec->info.frame_height;
  dec->offset_x = 0;
  dec->offset_y = 0;
434 435

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

  /* done */
439
  dec->decoder = th_decode_alloc (&dec->info, dec->setup);
440

441
  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_MV,
442
          &dec->telemetry_mv, sizeof (dec->telemetry_mv)) != TH_EIMPL) {
443
    GST_WARNING_OBJECT (dec, "Could not enable MV visualisation");
444
  }
445
  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_MBMODE,
446
          &dec->telemetry_mbmode, sizeof (dec->telemetry_mbmode)) != TH_EIMPL) {
447
    GST_WARNING_OBJECT (dec, "Could not enable MB mode visualisation");
448
  }
449
  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_QI,
450
          &dec->telemetry_qi, sizeof (dec->telemetry_qi)) != TH_EIMPL) {
451
    GST_WARNING_OBJECT (dec, "Could not enable QI mode visualisation");
452
  }
453
  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_BITS,
454
          &dec->telemetry_bits, sizeof (dec->telemetry_bits)) != TH_EIMPL) {
455
    GST_WARNING_OBJECT (dec, "Could not enable BITS mode visualisation");
456
  }
457

458 459 460 461
  /* Create the output state */
  dec->output_state = state =
      gst_video_decoder_set_output_state (GST_VIDEO_DECODER (dec), fmt,
      info->width, info->height, dec->input_state);
462

463 464 465 466 467
  /* FIXME : Do we still need to set fps/par now that we pass the reference input stream ? */
  state->info.fps_n = dec->info.fps_numerator;
  state->info.fps_d = dec->info.fps_denominator;
  state->info.par_n = par_num;
  state->info.par_d = par_den;
Wim Taymans's avatar
Wim Taymans committed
468

469 470
  /* these values are for all versions of the colorspace specified in the
   * theora info */
471
  state->info.chroma_site = GST_VIDEO_CHROMA_SITE_JPEG;
472 473 474 475 476 477 478 479 480 481 482 483 484 485
  state->info.colorimetry.range = GST_VIDEO_COLOR_RANGE_16_235;
  state->info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT601;
  state->info.colorimetry.transfer = GST_VIDEO_TRANSFER_BT709;
  switch (dec->info.colorspace) {
    case TH_CS_ITU_REC_470M:
      state->info.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT470M;
      break;
    case TH_CS_ITU_REC_470BG:
      state->info.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT470BG;
      break;
    default:
      state->info.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_UNKNOWN;
      break;
  }
486 487

  dec->have_header = TRUE;
488

489 490
  /* FIXME : Put this on the next outgoing frame */
  /* FIXME :  */
491
  if (dec->tags) {
492 493
    gst_pad_push_event (GST_VIDEO_DECODER (dec)->srcpad,
        gst_event_new_tag (dec->tags));
494 495 496 497
    dec->tags = NULL;
  }

  return ret;
498 499 500 501 502 503 504

  /* ERRORS */
unsupported_format:
  {
    GST_ERROR_OBJECT (dec, "Invalid pixel format %d", dec->info.pixel_fmt);
    return GST_FLOW_ERROR;
  }
505 506 507 508 509 510
}

static GstFlowReturn
theora_handle_header_packet (GstTheoraDec * dec, ogg_packet * packet)
{
  GstFlowReturn res;
511
  int ret;
512

513
  GST_DEBUG_OBJECT (dec, "parsing header packet");
514

515 516
  ret = th_decode_headerin (&dec->info, &dec->comment, &dec->setup, packet);
  if (ret < 0)
517 518
    goto header_read_error;

Wim Taymans's avatar
Wim Taymans committed
519 520
  switch (packet->packet[0]) {
    case 0x81:
521 522
      res = theora_handle_comment_packet (dec, packet);
      break;
Wim Taymans's avatar
Wim Taymans committed
523
    case 0x82:
524 525 526 527
      res = theora_handle_type_packet (dec, packet);
      break;
    default:
      /* ignore */
Wim Taymans's avatar
Wim Taymans committed
528 529 530
      g_warning ("unknown theora header packet found");
    case 0x80:
      /* nothing special, this is the identification header */
531 532 533 534 535 536 537 538 539 540 541 542 543 544
      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;
  }
}

Michael Smith's avatar
Michael Smith committed
545 546
/* Allocate buffer and copy image data into Y444 format */
static GstFlowReturn
547 548
theora_handle_image (GstTheoraDec * dec, th_ycbcr_buffer buf,
    GstVideoCodecFrame * frame)
Michael Smith's avatar
Michael Smith committed
549
{
550 551
  GstVideoDecoder *decoder = GST_VIDEO_DECODER (dec);
  GstVideoInfo *info;
552
  gint width, height, stride;
Michael Smith's avatar
Michael Smith committed
553 554
  GstFlowReturn result;
  int i, plane;
555
  guint8 *dest, *src;
556
  GstBuffer *out;
557
  GstMapInfo minfo;
Michael Smith's avatar
Michael Smith committed
558

559
  result = gst_video_decoder_alloc_output_frame (decoder, frame);
Michael Smith's avatar
Michael Smith committed
560

561
  if (G_UNLIKELY (result != GST_FLOW_OK)) {
562 563 564 565 566
    GST_DEBUG_OBJECT (dec, "could not get buffer, reason: %s",
        gst_flow_get_name (result));
    return result;
  }

567 568 569
  out = frame->output_buffer;
  info = &dec->output_state->info;

570 571 572
  gst_buffer_map (out, &minfo, GST_MAP_WRITE);

  /* FIXME : Use crop metadata */
573
  for (plane = 0; plane < 3; plane++) {
574 575 576
    width = GST_VIDEO_INFO_COMP_WIDTH (info, plane);
    height = GST_VIDEO_INFO_COMP_HEIGHT (info, plane);
    stride = GST_VIDEO_INFO_COMP_STRIDE (info, plane);
577

578
    dest = minfo.data + GST_VIDEO_INFO_COMP_OFFSET (info, plane);
579
    src = buf[plane].data;
580 581 582
    src +=
        ((height ==
            GST_VIDEO_INFO_HEIGHT (info)) ? dec->offset_y : dec->offset_y / 2)
583
        * buf[plane].stride;
584 585 586
    src +=
        (width ==
        GST_VIDEO_INFO_WIDTH (info)) ? dec->offset_x : dec->offset_x / 2;
587 588

    for (i = 0; i < height; i++) {
589
      memcpy (dest, src, width);
590

591 592
      dest += stride;
      src += buf[plane].stride;
593 594
    }
  }
Wim Taymans's avatar
Wim Taymans committed
595

596 597
  gst_buffer_unmap (out, &minfo);

598
  return GST_FLOW_OK;
599 600 601 602
}

static GstFlowReturn
theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet,
603
    GstVideoCodecFrame * frame)
604 605
{
  /* normal data packet */
606
  th_ycbcr_buffer buf;
607 608
  gboolean keyframe;
  GstFlowReturn result;
609
  ogg_int64_t gp;
610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626

  if (G_UNLIKELY (!dec->have_header))
    goto not_initialized;

  /* the second most significant bit of the first data byte is cleared 
   * for keyframes. We can only check it if it's not a zero-length packet. */
  keyframe = packet->bytes && ((packet->packet[0] & 0x40) == 0);
  if (G_UNLIKELY (keyframe)) {
    GST_DEBUG_OBJECT (dec, "we have a keyframe");
    dec->need_keyframe = FALSE;
  } else if (G_UNLIKELY (dec->need_keyframe)) {
    goto dropping;
  }

  GST_DEBUG_OBJECT (dec, "parsing data packet");

  /* this does the decoding */
627
  if (G_UNLIKELY (th_decode_packetin (dec->decoder, packet, &gp) < 0))
628 629
    goto decode_error;

630 631 632 633
  if (frame &&
      (gst_video_decoder_get_max_decode_time (GST_VIDEO_DECODER (dec),
              frame) < 0))
    goto dropping_qos;
634 635 636

  /* this does postprocessing and set up the decoded frame
   * pointers in our yuv variable */
637
  if (G_UNLIKELY (th_decode_ycbcr_out (dec->decoder, buf) < 0))
638 639
    goto no_yuv;

640 641
  if (G_UNLIKELY ((buf[0].width != dec->info.frame_width)
          || (buf[0].height != dec->info.frame_height)))
642 643
    goto wrong_dimensions;

644
  result = theora_handle_image (dec, buf, frame);
645 646
  if (result != GST_FLOW_OK)
    return result;
647 648 649 650 651 652 653

  return result;

  /* ERRORS */
not_initialized:
  {
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
Wim Taymans's avatar
Wim Taymans committed
654
        (NULL), ("no header sent yet"));
655 656 657 658 659
    return GST_FLOW_ERROR;
  }
dropping:
  {
    GST_WARNING_OBJECT (dec, "dropping frame because we need a keyframe");
660
    return GST_VIDEO_DECODER_FLOW_NEED_DATA;
661
  }
662 663 664
dropping_qos:
  {
    GST_WARNING_OBJECT (dec, "dropping frame because of QoS");
665
    return GST_VIDEO_DECODER_FLOW_NEED_DATA;
666 667
  }
decode_error:
668 669
  {
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
670
        (NULL), ("theora decoder did not decode data packet"));
671 672
    return GST_FLOW_ERROR;
  }
673
no_yuv:
674 675 676 677 678 679 680
  {
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
        (NULL), ("couldn't read out YUV image"));
    return GST_FLOW_ERROR;
  }
wrong_dimensions:
  {
681
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, FORMAT,
682 683 684 685 686 687
        (NULL), ("dimensions of image do not match header"));
    return GST_FLOW_ERROR;
  }
}

static GstFlowReturn
688 689
theora_dec_decode_buffer (GstTheoraDec * dec, GstBuffer * buf,
    GstVideoCodecFrame * frame)
690
{
Benjamin Otte's avatar
Benjamin Otte committed
691
  ogg_packet packet;
692
  GstFlowReturn result = GST_FLOW_OK;
693
  GstMapInfo minfo;
Benjamin Otte's avatar
Benjamin Otte committed
694 695

  /* make ogg_packet out of the buffer */
696 697 698
  gst_buffer_map (buf, &minfo, GST_MAP_READ);
  packet.packet = minfo.data;
  packet.bytes = minfo.size;
Wim Taymans's avatar
Wim Taymans committed
699
  packet.granulepos = -1;
Wim Taymans's avatar
Wim Taymans committed
700 701
  packet.packetno = 0;          /* we don't really care */
  packet.b_o_s = dec->have_header ? 0 : 1;
702
  /* EOS does not matter for the decoder */
703
  packet.e_o_s = 0;
704

705
  GST_LOG_OBJECT (dec, "decode buffer of size %ld", packet.bytes);
706

707
  GST_DEBUG_OBJECT (dec, "header=%02x", packet.bytes ? packet.packet[0] : -1);
708

709 710 711
  /* switch depending on packet type. A zero byte packet is always a data
   * packet; we don't dereference it in that case. */
  if (packet.bytes && packet.packet[0] & 0x80) {
Wim Taymans's avatar
Wim Taymans committed
712
    if (dec->have_header) {
713
      GST_WARNING_OBJECT (GST_OBJECT (dec), "Ignoring header");
714
      goto done;
715
    }
716
    result = theora_handle_header_packet (dec, &packet);
717 718 719 720 721
    /* header packets are not meant to be displayed */
    /* FIXME : This is a temporary hack. The proper fix would be to
     * not call _finish_frame() for these types of packets */
    GST_VIDEO_CODEC_FRAME_FLAG_SET (frame,
        GST_VIDEO_CODEC_FRAME_FLAG_DECODE_ONLY);
Benjamin Otte's avatar
Benjamin Otte committed
722
  } else {
723
    result = theora_handle_data_packet (dec, &packet, frame);
Benjamin Otte's avatar
Benjamin Otte committed
724
  }
725

726
done:
727 728
  gst_buffer_unmap (buf, &minfo);

729
  return result;
Benjamin Otte's avatar
Benjamin Otte committed
730 731
}

732
static GstFlowReturn
733
theora_dec_handle_frame (GstVideoDecoder * bdec, GstVideoCodecFrame * frame)
734 735 736 737
{
  GstTheoraDec *dec;
  GstFlowReturn res;

738
  dec = GST_THEORA_DEC (bdec);
739

740 741 742
  res = theora_dec_decode_buffer (dec, frame->input_buffer, frame);
  if (res == GST_FLOW_OK)
    res = gst_video_decoder_finish_frame (bdec, frame);
743 744 745 746

  return res;
}

747 748 749 750 751 752 753
static void
theora_dec_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
  GstTheoraDec *dec = GST_THEORA_DEC (object);

  switch (prop_id) {
754 755 756 757 758 759 760 761 762 763 764 765
    case PROP_TELEMETRY_MV:
      dec->telemetry_mv = g_value_get_int (value);
      break;
    case PROP_TELEMETRY_MBMODE:
      dec->telemetry_mbmode = g_value_get_int (value);
      break;
    case PROP_TELEMETRY_QI:
      dec->telemetry_qi = g_value_get_int (value);
      break;
    case PROP_TELEMETRY_BITS:
      dec->telemetry_bits = g_value_get_int (value);
      break;
766 767 768 769 770 771 772 773 774 775 776 777 778
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
theora_dec_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
{
  GstTheoraDec *dec = GST_THEORA_DEC (object);

  switch (prop_id) {
779 780 781 782 783 784 785 786 787 788 789 790
    case PROP_TELEMETRY_MV:
      g_value_set_int (value, dec->telemetry_mv);
      break;
    case PROP_TELEMETRY_MBMODE:
      g_value_set_int (value, dec->telemetry_mbmode);
      break;
    case PROP_TELEMETRY_QI:
      g_value_set_int (value, dec->telemetry_qi);
      break;
    case PROP_TELEMETRY_BITS:
      g_value_set_int (value, dec->telemetry_bits);
      break;
791 792 793 794 795
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
796 797 798 799 800 801 802

gboolean
gst_theora_dec_register (GstPlugin * plugin)
{
  return gst_element_register (plugin, "theoradec",
      GST_RANK_PRIMARY, GST_TYPE_THEORA_DEC);
}