gsttheoradec.c 28.5 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
 *
 * 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
Tim-Philipp Müller's avatar
Tim-Philipp Müller committed
19 20
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA 02110-1301, USA.
Benjamin Otte's avatar
Benjamin Otte committed
21 22
 */

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 64 65 66
/* This was removed from the base class, this is used as a
   temporary return to signal the need to call _drop_frame,
   and does not leave theoraenc. */
#define GST_CUSTOM_FLOW_DROP GST_FLOW_CUSTOM_SUCCESS_1

67 68
enum
{
69
  PROP_0,
70 71 72 73
  PROP_TELEMETRY_MV,
  PROP_TELEMETRY_MBMODE,
  PROP_TELEMETRY_QI,
  PROP_TELEMETRY_BITS
74 75
};

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

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

93 94
#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
95

96 97 98 99 100
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);

101 102 103 104 105 106 107 108
static gboolean theora_dec_start (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);
109 110
static gboolean theora_dec_decide_allocation (GstVideoDecoder * decoder,
    GstQuery * query);
111 112 113

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

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

129 130 131
  gobject_class->set_property = theora_dec_set_property;
  gobject_class->get_property = theora_dec_get_property;

132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
  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));
  }
175

176 177 178 179
  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));
180
  gst_element_class_set_static_metadata (element_class,
181 182 183 184
      "Theora video decoder", "Codec/Decoder/Video",
      "decode raw theora streams to raw YUV video",
      "Benjamin Otte <otte@gnome.org>, Wim Taymans <wim@fluendo.com>");

185 186 187 188 189 190
  video_decoder_class->start = GST_DEBUG_FUNCPTR (theora_dec_start);
  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);
191 192
  video_decoder_class->decide_allocation =
      GST_DEBUG_FUNCPTR (theora_dec_decide_allocation);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
193 194

  GST_DEBUG_CATEGORY_INIT (theoradec_debug, "theoradec", 0, "Theora decoder");
Benjamin Otte's avatar
Benjamin Otte committed
195 196 197
}

static void
198
gst_theora_dec_init (GstTheoraDec * dec)
Benjamin Otte's avatar
Benjamin Otte committed
199
{
200 201 202 203
  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;
204 205 206

  /* input is packetized,
   * but is not marked that way so data gets parsed and keyframes marked */
Wim Taymans's avatar
Wim Taymans committed
207
  gst_video_decoder_set_packetized (GST_VIDEO_DECODER (dec), FALSE);
Benjamin Otte's avatar
Benjamin Otte committed
208
}
209 210

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

215 216 217
  GST_DEBUG_OBJECT (dec, "start");
  GST_DEBUG_OBJECT (dec, "Setting have_header to FALSE");
  dec->have_header = FALSE;
218

219
  return TRUE;
220 221
}

Benjamin Otte's avatar
Benjamin Otte committed
222
static gboolean
223
theora_dec_reset (GstVideoDecoder * decoder, gboolean hard)
Benjamin Otte's avatar
Benjamin Otte committed
224
{
225 226
  GstTheoraDec *dec = GST_THEORA_DEC (decoder);

227
  dec->need_keyframe = TRUE;
228

229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
  if (hard) {
    th_info_clear (&dec->info);
    th_comment_clear (&dec->comment);
    if (dec->setup) {
      th_setup_free (dec->setup);
      dec->setup = NULL;
    }
    if (dec->decoder) {
      th_decode_free (dec->decoder);
      dec->decoder = NULL;
    }

    if (dec->input_state) {
      gst_video_codec_state_unref (dec->input_state);
      dec->input_state = NULL;
    }
    if (dec->output_state) {
      gst_video_codec_state_unref (dec->output_state);
      dec->output_state = NULL;
    }
    dec->can_crop = FALSE;
  }
251

252
  return TRUE;
Wim Taymans's avatar
Wim Taymans committed
253 254
}

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

262
  av = gst_adapter_available (adapter);
Benjamin Otte's avatar
Benjamin Otte committed
263

Wim Taymans's avatar
Wim Taymans committed
264 265 266 267 268 269 270
  if (av > 0) {
    data = gst_adapter_map (adapter, 1);
    /* check for keyframe; must not be header packet */
    if (!(data[0] & 0x80) && (data[0] & 0x40) == 0)
      GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
    gst_adapter_unmap (adapter);
  }
271

272 273 274
  /* and pass along all */
  gst_video_decoder_add_to_frame (decoder, av);
  return gst_video_decoder_have_frame (decoder);
275 276
}

Benjamin Otte's avatar
Benjamin Otte committed
277

278
static gboolean
279
theora_dec_set_format (GstVideoDecoder * bdec, GstVideoCodecState * state)
280 281 282
{
  GstTheoraDec *dec;

283
  dec = GST_THEORA_DEC (bdec);
284

285 286 287 288
  /* 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);
289

290 291 292
  /* FIXME : Interesting, we always accept any kind of caps ? */
  if (state->codec_data) {
    GstBuffer *buffer;
293
    GstMapInfo minfo;
294 295 296
    guint8 *data;
    guint size;
    guint offset;
297

298
    buffer = state->codec_data;
299
    gst_buffer_map (buffer, &minfo, GST_MAP_READ);
300

301
    offset = 0;
302 303
    size = minfo.size;
    data = (guint8 *) minfo.data;
304

305 306 307
    while (size > 2) {
      guint psize;
      GstBuffer *buf;
308

309 310 311 312 313
      psize = (data[0] << 8) | data[1];
      /* skip header */
      data += 2;
      size -= 2;
      offset += 2;
314

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

318
      buf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset, psize);
319

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

324 325 326
      /* now feed it to the decoder we can ignore the error */
      theora_dec_decode_buffer (dec, buf, NULL);
      gst_buffer_unref (buf);
327

328 329 330 331
      /* skip the data */
      size -= psize;
      data += psize;
      offset += psize;
332
    }
333 334

    gst_buffer_unmap (buffer, &minfo);
335 336
  }

337
  GST_DEBUG_OBJECT (dec, "Done");
338 339 340 341

  return TRUE;
}

342
static GstFlowReturn
343
theora_handle_comment_packet (GstTheoraDec * dec, ogg_packet * packet)
Benjamin Otte's avatar
Benjamin Otte committed
344
{
345 346 347
  gchar *encoder = NULL;
  GstTagList *list;

348
  GST_DEBUG_OBJECT (dec, "parsing comment packet");
349

350
  list =
351 352
      gst_tag_list_from_vorbiscomment (packet->packet, packet->bytes,
      (guint8 *) "\201theora", 7, &encoder);
353 354 355

  if (!list) {
    GST_ERROR_OBJECT (dec, "couldn't decode comments");
356
    list = gst_tag_list_new_empty ();
357 358 359 360 361 362 363 364 365 366
  }
  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);

367 368 369 370 371 372
  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);
  }

373 374 375 376
  gst_video_decoder_merge_tags (GST_VIDEO_DECODER (dec),
      list, GST_TAG_MERGE_REPLACE);

  gst_tag_list_unref (list);
377 378 379 380 381

  return GST_FLOW_OK;
}

static GstFlowReturn
382
theora_handle_type_packet (GstTheoraDec * dec)
383 384
{
  gint par_num, par_den;
385
  GstFlowReturn ret = GST_FLOW_OK;
386 387
  GstVideoCodecState *state;
  GstVideoFormat fmt;
388 389 390 391 392 393
  GstVideoInfo *info;

  if (!dec->input_state)
    return GST_FLOW_NOT_NEGOTIATED;

  info = &dec->input_state->info;
394 395 396 397 398 399 400

  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;
401
   * 0:x and x:0 are allowed and can be interpreted as 1:1.
402
   */
403 404 405 406 407 408
  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)) {
409 410 411
    par_num = dec->info.aspect_numerator;
    par_den = dec->info.aspect_denominator;
  }
412 413 414
  /* theora has:
   *
   *  width/height : dimension of the encoded frame 
415 416
   *  pic_width/pic_height : dimension of the visible part
   *  pic_x/pic_y : offset in encoded frame where visible part starts
417
   */
418 419
  GST_DEBUG_OBJECT (dec, "dimension %dx%d, PAR %d/%d", dec->info.pic_width,
      dec->info.pic_height, par_num, par_den);
420
  GST_DEBUG_OBJECT (dec, "frame dimension %dx%d, offset %d:%d",
421 422
      dec->info.pic_width, dec->info.pic_height,
      dec->info.pic_x, dec->info.pic_y);
423

424 425 426 427 428 429 430 431 432 433 434 435
  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;
436
  }
437

438 439
  GST_VIDEO_INFO_WIDTH (info) = dec->info.pic_width;
  GST_VIDEO_INFO_HEIGHT (info) = dec->info.pic_height;
440

441 442 443 444 445 446 447 448 449
  /* Ensure correct offsets in chroma for formats that need it
   * by rounding the offset. libtheora will add proper pixels,
   * so no need to handle them ourselves. */
  if (dec->info.pic_x & 1 && dec->info.pixel_fmt != TH_PF_444) {
    GST_VIDEO_INFO_WIDTH (info)++;
  }
  if (dec->info.pic_y & 1 && dec->info.pixel_fmt == TH_PF_420) {
    GST_VIDEO_INFO_HEIGHT (info)++;
  }
450 451

  GST_DEBUG_OBJECT (dec, "after fixup frame dimension %dx%d, offset %d:%d",
452
      info->width, info->height, dec->info.pic_x, dec->info.pic_y);
453 454

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

457
  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_MV,
458
          &dec->telemetry_mv, sizeof (dec->telemetry_mv)) != TH_EIMPL) {
459
    GST_WARNING_OBJECT (dec, "Could not enable MV visualisation");
460
  }
461
  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_MBMODE,
462
          &dec->telemetry_mbmode, sizeof (dec->telemetry_mbmode)) != TH_EIMPL) {
463
    GST_WARNING_OBJECT (dec, "Could not enable MB mode visualisation");
464
  }
465
  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_QI,
466
          &dec->telemetry_qi, sizeof (dec->telemetry_qi)) != TH_EIMPL) {
467
    GST_WARNING_OBJECT (dec, "Could not enable QI mode visualisation");
468
  }
469
  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_BITS,
470
          &dec->telemetry_bits, sizeof (dec->telemetry_bits)) != TH_EIMPL) {
471
    GST_WARNING_OBJECT (dec, "Could not enable BITS mode visualisation");
472
  }
473

474 475 476 477
  /* 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);
478

479 480 481 482 483
  /* 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
484

485 486
  /* these values are for all versions of the colorspace specified in the
   * theora info */
487
  state->info.chroma_site = GST_VIDEO_CHROMA_SITE_JPEG;
488 489 490 491 492 493 494 495 496 497 498 499 500 501
  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;
  }
502

503 504
  gst_video_decoder_negotiate (GST_VIDEO_DECODER (dec));

505
  dec->have_header = TRUE;
506

507
  return ret;
508 509 510 511 512 513 514

  /* ERRORS */
unsupported_format:
  {
    GST_ERROR_OBJECT (dec, "Invalid pixel format %d", dec->info.pixel_fmt);
    return GST_FLOW_ERROR;
  }
515 516 517 518 519 520
}

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

523
  GST_DEBUG_OBJECT (dec, "parsing header packet");
524

525 526
  ret = th_decode_headerin (&dec->info, &dec->comment, &dec->setup, packet);
  if (ret < 0)
527 528
    goto header_read_error;

Wim Taymans's avatar
Wim Taymans committed
529 530
  switch (packet->packet[0]) {
    case 0x81:
531 532
      res = theora_handle_comment_packet (dec, packet);
      break;
Wim Taymans's avatar
Wim Taymans committed
533
    case 0x82:
534
      res = theora_handle_type_packet (dec);
535 536 537
      break;
    default:
      /* ignore */
Wim Taymans's avatar
Wim Taymans committed
538 539 540
      g_warning ("unknown theora header packet found");
    case 0x80:
      /* nothing special, this is the identification header */
541 542 543 544 545 546 547 548 549 550 551 552 553 554
      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
555 556
/* Allocate buffer and copy image data into Y444 format */
static GstFlowReturn
557 558
theora_handle_image (GstTheoraDec * dec, th_ycbcr_buffer buf,
    GstVideoCodecFrame * frame)
Michael Smith's avatar
Michael Smith committed
559
{
560
  GstVideoDecoder *decoder = GST_VIDEO_DECODER (dec);
561
  gint width, height, stride;
Michael Smith's avatar
Michael Smith committed
562
  GstFlowReturn result;
563
  gint i, comp;
564
  guint8 *dest, *src;
565 566 567
  GstVideoFrame vframe;
  gint pic_width, pic_height;
  gint offset_x, offset_y;
Michael Smith's avatar
Michael Smith committed
568

569
  result = gst_video_decoder_allocate_output_frame (decoder, frame);
Michael Smith's avatar
Michael Smith committed
570

571
  if (G_UNLIKELY (result != GST_FLOW_OK)) {
572 573 574 575 576
    GST_DEBUG_OBJECT (dec, "could not get buffer, reason: %s",
        gst_flow_get_name (result));
    return result;
  }

577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
  if (!dec->can_crop) {
    /* we need to crop the hard way */
    offset_x = dec->info.pic_x;
    offset_y = dec->info.pic_y;
    pic_width = dec->info.pic_width;
    pic_height = dec->info.pic_height;
    /* Ensure correct offsets in chroma for formats that need it
     * by rounding the offset. libtheora will add proper pixels,
     * so no need to handle them ourselves. */
    if (offset_x & 1 && dec->info.pixel_fmt != TH_PF_444)
      offset_x--;
    if (offset_y & 1 && dec->info.pixel_fmt == TH_PF_420)
      offset_y--;
  } else {
    /* copy the whole frame */
    offset_x = 0;
    offset_y = 0;
    pic_width = dec->info.frame_width;
    pic_height = dec->info.frame_height;

    if (dec->info.pic_width != dec->info.frame_width ||
        dec->info.pic_height != dec->info.frame_height ||
        dec->info.pic_x != 0 || dec->info.pic_y != 0) {
600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
      GstVideoMeta *vmeta;
      GstVideoCropMeta *cmeta;

      vmeta = gst_buffer_get_video_meta (frame->output_buffer);
      /* If the buffer pool didn't add the meta already
       * we add it ourselves here */
      if (!vmeta)
        vmeta = gst_buffer_add_video_meta (frame->output_buffer,
            GST_VIDEO_FRAME_FLAG_NONE,
            dec->output_state->info.finfo->format,
            dec->info.frame_width, dec->info.frame_height);

      /* Just to be sure that the buffer pool doesn't do something
       * completely weird and we would crash later
       */
      g_assert (vmeta->format == dec->output_state->info.finfo->format);
      g_assert (vmeta->width == dec->info.frame_width);
      g_assert (vmeta->height == dec->info.frame_height);

      cmeta = gst_buffer_add_video_crop_meta (frame->output_buffer);
620 621 622

      /* we can do things slightly more efficient when we know that
       * downstream understands clipping */
623 624 625 626
      cmeta->x = dec->info.pic_x;
      cmeta->y = dec->info.pic_y;
      cmeta->width = dec->info.pic_width;
      cmeta->height = dec->info.pic_height;
627 628 629 630 631 632
    }
  }

  /* if only libtheora would allow us to give it a destination frame */
  GST_CAT_TRACE_OBJECT (GST_CAT_PERFORMANCE, dec,
      "doing unavoidable video frame copy");
633

634 635 636
  if (G_UNLIKELY (!gst_video_frame_map (&vframe, &dec->output_state->info,
              frame->output_buffer, GST_MAP_WRITE)))
    goto invalid_frame;
637

638 639 640 641 642 643 644 645
  for (comp = 0; comp < 3; comp++) {
    width =
        GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (vframe.info.finfo, comp, pic_width);
    height =
        GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (vframe.info.finfo, comp,
        pic_height);
    stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, comp);
    dest = GST_VIDEO_FRAME_COMP_DATA (&vframe, comp);
646

647 648 649 650
    src = buf[comp].data;
    src += ((height == pic_height) ? offset_y : offset_y / 2)
        * buf[comp].stride;
    src += (width == pic_width) ? offset_x : offset_x / 2;
651 652

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

655
      dest += stride;
656
      src += buf[comp].stride;
657 658
    }
  }
659
  gst_video_frame_unmap (&vframe);
660

661
  return GST_FLOW_OK;
662 663 664 665 666
invalid_frame:
  {
    GST_DEBUG_OBJECT (dec, "could not map video frame");
    return GST_FLOW_ERROR;
  }
667 668 669 670
}

static GstFlowReturn
theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet,
671
    GstVideoCodecFrame * frame)
672 673
{
  /* normal data packet */
674
  th_ycbcr_buffer buf;
675 676
  gboolean keyframe;
  GstFlowReturn result;
677
  ogg_int64_t gp;
678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694

  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 */
695
  if (G_UNLIKELY (th_decode_packetin (dec->decoder, packet, &gp) < 0))
696 697
    goto decode_error;

698 699 700 701
  if (frame &&
      (gst_video_decoder_get_max_decode_time (GST_VIDEO_DECODER (dec),
              frame) < 0))
    goto dropping_qos;
702 703 704

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

708 709
  if (G_UNLIKELY ((buf[0].width != dec->info.frame_width)
          || (buf[0].height != dec->info.frame_height)))
710 711
    goto wrong_dimensions;

712
  result = theora_handle_image (dec, buf, frame);
713 714 715 716 717 718 719

  return result;

  /* ERRORS */
not_initialized:
  {
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
Wim Taymans's avatar
Wim Taymans committed
720
        (NULL), ("no header sent yet"));
721 722 723 724 725
    return GST_FLOW_ERROR;
  }
dropping:
  {
    GST_WARNING_OBJECT (dec, "dropping frame because we need a keyframe");
726
    return GST_CUSTOM_FLOW_DROP;
727
  }
728 729 730
dropping_qos:
  {
    GST_WARNING_OBJECT (dec, "dropping frame because of QoS");
731
    return GST_CUSTOM_FLOW_DROP;
732 733
  }
decode_error:
734 735
  {
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
736
        (NULL), ("theora decoder did not decode data packet"));
737 738
    return GST_FLOW_ERROR;
  }
739
no_yuv:
740 741 742 743 744 745 746
  {
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
        (NULL), ("couldn't read out YUV image"));
    return GST_FLOW_ERROR;
  }
wrong_dimensions:
  {
747
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, FORMAT,
748 749 750 751 752 753
        (NULL), ("dimensions of image do not match header"));
    return GST_FLOW_ERROR;
  }
}

static GstFlowReturn
754 755
theora_dec_decode_buffer (GstTheoraDec * dec, GstBuffer * buf,
    GstVideoCodecFrame * frame)
756
{
Benjamin Otte's avatar
Benjamin Otte committed
757
  ogg_packet packet;
758
  GstFlowReturn result = GST_FLOW_OK;
759
  GstMapInfo minfo;
Benjamin Otte's avatar
Benjamin Otte committed
760 761

  /* make ogg_packet out of the buffer */
762 763 764
  gst_buffer_map (buf, &minfo, GST_MAP_READ);
  packet.packet = minfo.data;
  packet.bytes = minfo.size;
Wim Taymans's avatar
Wim Taymans committed
765
  packet.granulepos = -1;
Wim Taymans's avatar
Wim Taymans committed
766 767
  packet.packetno = 0;          /* we don't really care */
  packet.b_o_s = dec->have_header ? 0 : 1;
768
  /* EOS does not matter for the decoder */
769
  packet.e_o_s = 0;
770

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

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

775 776 777
  /* 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
778
    if (dec->have_header) {
779
      GST_WARNING_OBJECT (GST_OBJECT (dec), "Ignoring header");
780 781
      GST_VIDEO_CODEC_FRAME_FLAG_SET (frame,
          GST_VIDEO_CODEC_FRAME_FLAG_DECODE_ONLY);
782
      result = GST_CUSTOM_FLOW_DROP;
783
      goto done;
784
    }
785
    result = theora_handle_header_packet (dec, &packet);
786 787 788 789 790
    /* 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
791
  } else {
792
    result = theora_handle_data_packet (dec, &packet, frame);
Benjamin Otte's avatar
Benjamin Otte committed
793
  }
794

795
done:
796 797
  gst_buffer_unmap (buf, &minfo);

798
  return result;
Benjamin Otte's avatar
Benjamin Otte committed
799 800
}

801
static GstFlowReturn
802
theora_dec_handle_frame (GstVideoDecoder * bdec, GstVideoCodecFrame * frame)
803 804 805 806
{
  GstTheoraDec *dec;
  GstFlowReturn res;

807
  dec = GST_THEORA_DEC (bdec);
808

809
  res = theora_dec_decode_buffer (dec, frame->input_buffer, frame);
810 811 812 813 814 815 816 817 818 819 820
  switch (res) {
    case GST_FLOW_OK:
      res = gst_video_decoder_finish_frame (bdec, frame);
      break;
    case GST_CUSTOM_FLOW_DROP:
      res = gst_video_decoder_drop_frame (bdec, frame);
      break;
    default:
      gst_video_codec_frame_unref (frame);
      break;
  }
821 822 823 824

  return res;
}

825
static gboolean
826
theora_dec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query)
827 828
{
  GstTheoraDec *dec = GST_THEORA_DEC (decoder);
829
  GstVideoCodecState *state;
830 831 832 833
  GstBufferPool *pool;
  guint size, min, max;
  GstStructure *config;

834 835 836
  if (!GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (decoder,
          query))
    return FALSE;
837

838
  state = gst_video_decoder_get_output_state (decoder);
839

840
  gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
841

842
  dec->can_crop = FALSE;
843
  config = gst_buffer_pool_get_config (pool);
Wim Taymans's avatar
Wim Taymans committed
844
  if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
845 846
    gst_buffer_pool_config_add_option (config,
        GST_BUFFER_POOL_OPTION_VIDEO_META);
847
    dec->can_crop =
Wim Taymans's avatar
Wim Taymans committed
848 849
        gst_query_find_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE,
        NULL);
850
  }
851

852 853
  if (dec->can_crop) {
    GstVideoInfo info = state->info;
854
    GstCaps *caps;
855 856 857 858 859

    /* Calculate uncropped size */
    gst_video_info_set_format (&info, info.finfo->format, dec->info.frame_width,
        dec->info.frame_height);
    size = MAX (size, info.size);
860 861 862
    caps = gst_video_info_to_caps (&info);
    gst_buffer_pool_config_set_params (config, caps, size, min, max);
    gst_caps_unref (caps);
863
  }
864

865
  gst_buffer_pool_set_config (pool, config);
866

867
  gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
868

869
  gst_object_unref (pool);
870 871
  gst_video_codec_state_unref (state);

872
  return TRUE;
873 874
}

875 876 877 878 879 880 881
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) {
882 883 884 885 886 887 888 889 890 891 892 893
    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;
894 895 896 897 898 899 900 901 902 903 904 905 906
    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) {
907 908 909 910 911 912 913 914 915 916 917 918
    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;
919 920 921 922 923
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
924 925 926 927 928 929 930

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