gsttheoradec.c 28.9 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 109
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);
110 111
static gboolean theora_dec_decide_allocation (GstVideoDecoder * decoder,
    GstQuery * query);
112 113 114

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

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

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

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 175
  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));
  }
176

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

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

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

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

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

212 213 214 215
static void
gst_theora_dec_reset (GstTheoraDec * dec)
{
  dec->need_keyframe = TRUE;
216
  dec->can_crop = FALSE;
217 218
}

219
static gboolean
220
theora_dec_start (GstVideoDecoder * decoder)
221
{
222
  GstTheoraDec *dec = GST_THEORA_DEC (decoder);
Wim Taymans's avatar
Wim Taymans committed
223

224 225 226 227 228 229
  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);
230

231
  return TRUE;
232 233
}

Benjamin Otte's avatar
Benjamin Otte committed
234
static gboolean
235
theora_dec_stop (GstVideoDecoder * decoder)
Benjamin Otte's avatar
Benjamin Otte committed
236
{
237 238 239 240 241 242 243 244 245 246
  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);
247
  if (dec->input_state) {
248
    gst_video_codec_state_unref (dec->input_state);
249 250 251
    dec->input_state = NULL;
  }
  if (dec->output_state) {
252
    gst_video_codec_state_unref (dec->output_state);
253 254
    dec->output_state = NULL;
  }
255

256
  return TRUE;
Benjamin Otte's avatar
Benjamin Otte committed
257
}
258

259
/* FIXME : Do we want to handle hard resets differently ? */
260
static gboolean
261
theora_dec_reset (GstVideoDecoder * bdec, gboolean hard)
262
{
263 264
  gst_theora_dec_reset (GST_THEORA_DEC (bdec));
  return TRUE;
Wim Taymans's avatar
Wim Taymans committed
265 266
}

267 268 269
static GstFlowReturn
theora_dec_parse (GstVideoDecoder * decoder,
    GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos)
Benjamin Otte's avatar
Benjamin Otte committed
270
{
271 272
  gint av;
  const guint8 *data;
Benjamin Otte's avatar
Benjamin Otte committed
273

274
  av = gst_adapter_available (adapter);
Benjamin Otte's avatar
Benjamin Otte committed
275

Wim Taymans's avatar
Wim Taymans committed
276 277 278 279 280 281 282
  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);
  }
283

284 285 286
  /* and pass along all */
  gst_video_decoder_add_to_frame (decoder, av);
  return gst_video_decoder_have_frame (decoder);
287 288
}

Benjamin Otte's avatar
Benjamin Otte committed
289

290
static gboolean
291
theora_dec_set_format (GstVideoDecoder * bdec, GstVideoCodecState * state)
292 293 294
{
  GstTheoraDec *dec;

295
  dec = GST_THEORA_DEC (bdec);
296

297 298 299 300
  /* 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);
301

302 303 304
  /* FIXME : Interesting, we always accept any kind of caps ? */
  if (state->codec_data) {
    GstBuffer *buffer;
305
    GstMapInfo minfo;
306 307 308
    guint8 *data;
    guint size;
    guint offset;
309

310
    buffer = state->codec_data;
311
    gst_buffer_map (buffer, &minfo, GST_MAP_READ);
312

313
    offset = 0;
314 315
    size = minfo.size;
    data = (guint8 *) minfo.data;
316

317 318 319
    while (size > 2) {
      guint psize;
      GstBuffer *buf;
320

321 322 323 324 325
      psize = (data[0] << 8) | data[1];
      /* skip header */
      data += 2;
      size -= 2;
      offset += 2;
326

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

330
      buf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset, psize);
331

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

336 337 338
      /* now feed it to the decoder we can ignore the error */
      theora_dec_decode_buffer (dec, buf, NULL);
      gst_buffer_unref (buf);
339

340 341 342 343
      /* skip the data */
      size -= psize;
      data += psize;
      offset += psize;
344
    }
345 346

    gst_buffer_unmap (buffer, &minfo);
347 348
  }

349
  GST_DEBUG_OBJECT (dec, "Done");
350 351 352 353

  return TRUE;
}

354
static GstFlowReturn
355
theora_handle_comment_packet (GstTheoraDec * dec, ogg_packet * packet)
Benjamin Otte's avatar
Benjamin Otte committed
356
{
357 358 359
  gchar *encoder = NULL;
  GstTagList *list;

360
  GST_DEBUG_OBJECT (dec, "parsing comment packet");
361

362
  list =
363 364
      gst_tag_list_from_vorbiscomment (packet->packet, packet->bytes,
      (guint8 *) "\201theora", 7, &encoder);
365 366 367

  if (!list) {
    GST_ERROR_OBJECT (dec, "couldn't decode comments");
368
    list = gst_tag_list_new_empty ();
369 370 371 372 373 374 375 376 377 378
  }
  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);

379 380 381 382 383 384
  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);
  }

385 386 387 388
  gst_video_decoder_merge_tags (GST_VIDEO_DECODER (dec),
      list, GST_TAG_MERGE_REPLACE);

  gst_tag_list_unref (list);
389 390 391 392 393

  return GST_FLOW_OK;
}

static GstFlowReturn
394
theora_handle_type_packet (GstTheoraDec * dec)
395 396
{
  gint par_num, par_den;
397
  GstFlowReturn ret = GST_FLOW_OK;
398 399
  GstVideoCodecState *state;
  GstVideoFormat fmt;
400 401 402 403 404 405
  GstVideoInfo *info;

  if (!dec->input_state)
    return GST_FLOW_NOT_NEGOTIATED;

  info = &dec->input_state->info;
406 407 408 409 410 411 412

  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;
413
   * 0:x and x:0 are allowed and can be interpreted as 1:1.
414
   */
415 416 417 418 419 420
  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)) {
421 422 423
    par_num = dec->info.aspect_numerator;
    par_den = dec->info.aspect_denominator;
  }
424 425 426
  /* theora has:
   *
   *  width/height : dimension of the encoded frame 
427 428
   *  pic_width/pic_height : dimension of the visible part
   *  pic_x/pic_y : offset in encoded frame where visible part starts
429
   */
430 431
  GST_DEBUG_OBJECT (dec, "dimension %dx%d, PAR %d/%d", dec->info.pic_width,
      dec->info.pic_height, par_num, par_den);
432
  GST_DEBUG_OBJECT (dec, "frame dimension %dx%d, offset %d:%d",
433 434
      dec->info.pic_width, dec->info.pic_height,
      dec->info.pic_x, dec->info.pic_y);
435

436 437 438 439 440 441 442 443 444 445 446 447
  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;
448
  }
449

450 451
  GST_VIDEO_INFO_WIDTH (info) = dec->info.pic_width;
  GST_VIDEO_INFO_HEIGHT (info) = dec->info.pic_height;
452

453 454 455 456 457 458 459 460 461
  /* 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)++;
  }
462 463

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

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

469
  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_MV,
470
          &dec->telemetry_mv, sizeof (dec->telemetry_mv)) != TH_EIMPL) {
471
    GST_WARNING_OBJECT (dec, "Could not enable MV visualisation");
472
  }
473
  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_MBMODE,
474
          &dec->telemetry_mbmode, sizeof (dec->telemetry_mbmode)) != TH_EIMPL) {
475
    GST_WARNING_OBJECT (dec, "Could not enable MB mode visualisation");
476
  }
477
  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_QI,
478
          &dec->telemetry_qi, sizeof (dec->telemetry_qi)) != TH_EIMPL) {
479
    GST_WARNING_OBJECT (dec, "Could not enable QI mode visualisation");
480
  }
481
  if (th_decode_ctl (dec->decoder, TH_DECCTL_SET_TELEMETRY_BITS,
482
          &dec->telemetry_bits, sizeof (dec->telemetry_bits)) != TH_EIMPL) {
483
    GST_WARNING_OBJECT (dec, "Could not enable BITS mode visualisation");
484
  }
485

486 487 488 489
  /* 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);
490

491 492 493 494 495
  /* 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
496

497 498
  /* these values are for all versions of the colorspace specified in the
   * theora info */
499
  state->info.chroma_site = GST_VIDEO_CHROMA_SITE_JPEG;
500 501 502 503 504 505 506 507 508 509 510 511 512 513
  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;
  }
514

515 516
  gst_video_decoder_negotiate (GST_VIDEO_DECODER (dec));

517
  dec->have_header = TRUE;
518

519
  return ret;
520 521 522 523 524 525 526

  /* ERRORS */
unsupported_format:
  {
    GST_ERROR_OBJECT (dec, "Invalid pixel format %d", dec->info.pixel_fmt);
    return GST_FLOW_ERROR;
  }
527 528 529 530 531 532
}

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

535
  GST_DEBUG_OBJECT (dec, "parsing header packet");
536

537 538
  ret = th_decode_headerin (&dec->info, &dec->comment, &dec->setup, packet);
  if (ret < 0)
539 540
    goto header_read_error;

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

581
  result = gst_video_decoder_allocate_output_frame (decoder, frame);
Michael Smith's avatar
Michael Smith committed
582

583
  if (G_UNLIKELY (result != GST_FLOW_OK)) {
584 585 586 587 588
    GST_DEBUG_OBJECT (dec, "could not get buffer, reason: %s",
        gst_flow_get_name (result));
    return result;
  }

589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
  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) {
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631
      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);
632 633 634

      /* we can do things slightly more efficient when we know that
       * downstream understands clipping */
635 636 637 638
      cmeta->x = dec->info.pic_x;
      cmeta->y = dec->info.pic_y;
      cmeta->width = dec->info.pic_width;
      cmeta->height = dec->info.pic_height;
639 640 641 642 643 644
    }
  }

  /* 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");
645

646 647 648
  if (G_UNLIKELY (!gst_video_frame_map (&vframe, &dec->output_state->info,
              frame->output_buffer, GST_MAP_WRITE)))
    goto invalid_frame;
649

650 651 652 653 654 655 656 657
  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);
658

659 660 661 662
    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;
663 664

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

667
      dest += stride;
668
      src += buf[comp].stride;
669 670
    }
  }
671
  gst_video_frame_unmap (&vframe);
672

673
  return GST_FLOW_OK;
674 675 676 677 678
invalid_frame:
  {
    GST_DEBUG_OBJECT (dec, "could not map video frame");
    return GST_FLOW_ERROR;
  }
679 680 681 682
}

static GstFlowReturn
theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet,
683
    GstVideoCodecFrame * frame)
684 685
{
  /* normal data packet */
686
  th_ycbcr_buffer buf;
687 688
  gboolean keyframe;
  GstFlowReturn result;
689
  ogg_int64_t gp;
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706

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

710 711 712 713
  if (frame &&
      (gst_video_decoder_get_max_decode_time (GST_VIDEO_DECODER (dec),
              frame) < 0))
    goto dropping_qos;
714 715 716

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

720 721
  if (G_UNLIKELY ((buf[0].width != dec->info.frame_width)
          || (buf[0].height != dec->info.frame_height)))
722 723
    goto wrong_dimensions;

724
  result = theora_handle_image (dec, buf, frame);
725 726 727 728 729 730 731

  return result;

  /* ERRORS */
not_initialized:
  {
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
Wim Taymans's avatar
Wim Taymans committed
732
        (NULL), ("no header sent yet"));
733 734 735 736 737
    return GST_FLOW_ERROR;
  }
dropping:
  {
    GST_WARNING_OBJECT (dec, "dropping frame because we need a keyframe");
738
    return GST_CUSTOM_FLOW_DROP;
739
  }
740 741 742
dropping_qos:
  {
    GST_WARNING_OBJECT (dec, "dropping frame because of QoS");
743
    return GST_CUSTOM_FLOW_DROP;
744 745
  }
decode_error:
746 747
  {
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
748
        (NULL), ("theora decoder did not decode data packet"));
749 750
    return GST_FLOW_ERROR;
  }
751
no_yuv:
752 753 754 755 756 757 758
  {
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
        (NULL), ("couldn't read out YUV image"));
    return GST_FLOW_ERROR;
  }
wrong_dimensions:
  {
759
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, FORMAT,
760 761 762 763 764 765
        (NULL), ("dimensions of image do not match header"));
    return GST_FLOW_ERROR;
  }
}

static GstFlowReturn
766 767
theora_dec_decode_buffer (GstTheoraDec * dec, GstBuffer * buf,
    GstVideoCodecFrame * frame)
768
{
Benjamin Otte's avatar
Benjamin Otte committed
769
  ogg_packet packet;
770
  GstFlowReturn result = GST_FLOW_OK;
771
  GstMapInfo minfo;
Benjamin Otte's avatar
Benjamin Otte committed
772 773

  /* make ogg_packet out of the buffer */
774 775 776
  gst_buffer_map (buf, &minfo, GST_MAP_READ);
  packet.packet = minfo.data;
  packet.bytes = minfo.size;
Wim Taymans's avatar
Wim Taymans committed
777
  packet.granulepos = -1;
Wim Taymans's avatar
Wim Taymans committed
778 779
  packet.packetno = 0;          /* we don't really care */
  packet.b_o_s = dec->have_header ? 0 : 1;
780
  /* EOS does not matter for the decoder */
781
  packet.e_o_s = 0;
782

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

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

787 788 789
  /* 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
790
    if (dec->have_header) {
791
      GST_WARNING_OBJECT (GST_OBJECT (dec), "Ignoring header");
792 793
      GST_VIDEO_CODEC_FRAME_FLAG_SET (frame,
          GST_VIDEO_CODEC_FRAME_FLAG_DECODE_ONLY);
794
      result = GST_CUSTOM_FLOW_DROP;
795
      goto done;
796
    }
797
    result = theora_handle_header_packet (dec, &packet);
798 799 800 801 802
    /* 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
803
  } else {
804
    result = theora_handle_data_packet (dec, &packet, frame);
Benjamin Otte's avatar
Benjamin Otte committed
805
  }
806

807
done:
808 809
  gst_buffer_unmap (buf, &minfo);

810
  return result;
Benjamin Otte's avatar
Benjamin Otte committed
811 812
}

813
static GstFlowReturn
814
theora_dec_handle_frame (GstVideoDecoder * bdec, GstVideoCodecFrame * frame)
815 816 817 818
{
  GstTheoraDec *dec;
  GstFlowReturn res;

819
  dec = GST_THEORA_DEC (bdec);
820

821
  res = theora_dec_decode_buffer (dec, frame->input_buffer, frame);
822 823 824 825 826 827 828 829 830 831 832
  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;
  }
833 834 835 836

  return res;
}

837
static gboolean
838
theora_dec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query)
839 840
{
  GstTheoraDec *dec = GST_THEORA_DEC (decoder);
841
  GstVideoCodecState *state;
842 843 844 845
  GstBufferPool *pool;
  guint size, min, max;
  GstStructure *config;

846 847 848
  if (!GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (decoder,
          query))
    return FALSE;
849

850
  state = gst_video_decoder_get_output_state (decoder);
851

852
  gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
853

854
  dec->can_crop = FALSE;
855
  config = gst_buffer_pool_get_config (pool);
Wim Taymans's avatar
Wim Taymans committed
856
  if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
857 858
    gst_buffer_pool_config_add_option (config,
        GST_BUFFER_POOL_OPTION_VIDEO_META);
859
    dec->can_crop =
Wim Taymans's avatar
Wim Taymans committed
860 861
        gst_query_find_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE,
        NULL);
862
  }
863

864 865
  if (dec->can_crop) {
    GstVideoInfo info = state->info;
866
    GstCaps *caps;
867 868 869 870 871

    /* 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);
872 873 874
    caps = gst_video_info_to_caps (&info);
    gst_buffer_pool_config_set_params (config, caps, size, min, max);
    gst_caps_unref (caps);
875
  }
876

877
  gst_buffer_pool_set_config (pool, config);
878

879
  gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
880

881
  gst_object_unref (pool);
882 883
  gst_video_codec_state_unref (state);

884
  return TRUE;
885 886
}

887 888 889 890 891 892 893
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) {
894 895 896 897 898 899 900 901 902 903 904 905
    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;
906 907 908 909 910 911 912 913 914 915 916 917 918
    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) {
919 920 921 922 923 924 925 926 927 928 929 930
    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;
931 932 933 934 935
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
936 937 938 939 940 941 942

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