gstvp8dec.c 17.2 KB
Newer Older
1
/* VP8
2 3
 * Copyright (C) 2006 David Schleef <ds@schleef.org>
 * Copyright (C) 2008,2009,2010 Entropy Wave Inc
4
 * Copyright (C) 2010-2012 Sebastian Dröge <sebastian.droege@collabora.co.uk>
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 * 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.
 *
 */
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
/**
 * SECTION:element-vp8dec
 * @see_also: vp8enc, matroskademux
 *
 * This element decodes VP8 streams into raw video.
 * <ulink url="http://www.webmproject.org">VP8</ulink> is a royalty-free
 * video codec maintained by <ulink url="http://www.google.com/">Google
 * </ulink>. It's the successor of On2 VP3, which was the base of the
 * Theora video codec.
 *
 * <refsect2>
 * <title>Example pipeline</title>
 * |[
 * gst-launch -v filesrc location=videotestsrc.webm ! matroskademux ! vp8dec ! xvimagesink
 * ]| This example pipeline will decode a WebM stream and decodes the VP8 video.
 * </refsect2>
 */
39 40 41 42 43

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

44 45
#ifdef HAVE_VP8_DECODER

46 47
#include <string.h>

48
#include "gstvp8dec.h"
49
#include "gstvp8utils.h"
50

51 52 53
#include <gst/video/gstvideometa.h>
#include <gst/video/gstvideopool.h>

54
GST_DEBUG_CATEGORY_STATIC (gst_vp8dec_debug);
55 56
#define GST_CAT_DEFAULT gst_vp8dec_debug

57
#define DEFAULT_POST_PROCESSING FALSE
58
#define DEFAULT_POST_PROCESSING_FLAGS (VP8_DEBLOCK | VP8_DEMACROBLOCK | VP8_MFQE)
59 60
#define DEFAULT_DEBLOCKING_LEVEL 4
#define DEFAULT_NOISE_LEVEL 0
61
#define DEFAULT_THREADS 1
62

63 64
enum
{
65 66 67 68
  PROP_0,
  PROP_POST_PROCESSING,
  PROP_POST_PROCESSING_FLAGS,
  PROP_DEBLOCKING_LEVEL,
69 70
  PROP_NOISE_LEVEL,
  PROP_THREADS
71 72
};

73 74 75 76 77 78 79 80 81
#define C_FLAGS(v) ((guint) v)
#define GST_VP8_DEC_TYPE_POST_PROCESSING_FLAGS (gst_vp8_dec_post_processing_flags_get_type())
static GType
gst_vp8_dec_post_processing_flags_get_type (void)
{
  static const GFlagsValue values[] = {
    {C_FLAGS (VP8_DEBLOCK), "Deblock", "deblock"},
    {C_FLAGS (VP8_DEMACROBLOCK), "Demacroblock", "demacroblock"},
    {C_FLAGS (VP8_ADDNOISE), "Add noise", "addnoise"},
82
    {C_FLAGS (VP8_MFQE), "Multi-frame quality enhancement", "mfqe"},
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
    {0, NULL, NULL}
  };
  static volatile GType id = 0;

  if (g_once_init_enter ((gsize *) & id)) {
    GType _id;

    _id = g_flags_register_static ("GstVP8DecPostProcessingFlags", values);

    g_once_init_leave ((gsize *) & id, _id);
  }

  return id;
}

#undef C_FLAGS

100 101 102 103 104
static void gst_vp8_dec_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec);
static void gst_vp8_dec_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec);

105 106 107 108 109 110 111
static gboolean gst_vp8_dec_start (GstVideoDecoder * decoder);
static gboolean gst_vp8_dec_stop (GstVideoDecoder * decoder);
static gboolean gst_vp8_dec_set_format (GstVideoDecoder * decoder,
    GstVideoCodecState * state);
static gboolean gst_vp8_dec_reset (GstVideoDecoder * decoder, gboolean hard);
static GstFlowReturn gst_vp8_dec_handle_frame (GstVideoDecoder * decoder,
    GstVideoCodecFrame * frame);
112 113
static gboolean gst_vp8_dec_decide_allocation (GstVideoDecoder * decoder,
    GstQuery * query);
114 115 116 117 118 119 120 121 122 123 124 125

static GstStaticPadTemplate gst_vp8_dec_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("video/x-vp8")
    );

static GstStaticPadTemplate gst_vp8_dec_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
126
    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("I420"))
127 128
    );

129 130
#define parent_class gst_vp8_dec_parent_class
G_DEFINE_TYPE (GstVP8Dec, gst_vp8_dec, GST_TYPE_VIDEO_DECODER);
131 132 133 134 135

static void
gst_vp8_dec_class_init (GstVP8DecClass * klass)
{
  GObjectClass *gobject_class;
136
  GstElementClass *element_class;
137
  GstVideoDecoderClass *base_video_decoder_class;
138 139

  gobject_class = G_OBJECT_CLASS (klass);
140
  element_class = GST_ELEMENT_CLASS (klass);
141
  base_video_decoder_class = GST_VIDEO_DECODER_CLASS (klass);
142 143 144 145

  gobject_class->set_property = gst_vp8_dec_set_property;
  gobject_class->get_property = gst_vp8_dec_get_property;

146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
  g_object_class_install_property (gobject_class, PROP_POST_PROCESSING,
      g_param_spec_boolean ("post-processing", "Post Processing",
          "Enable post processing", DEFAULT_POST_PROCESSING,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

  g_object_class_install_property (gobject_class, PROP_POST_PROCESSING_FLAGS,
      g_param_spec_flags ("post-processing-flags", "Post Processing Flags",
          "Flags to control post processing",
          GST_VP8_DEC_TYPE_POST_PROCESSING_FLAGS, DEFAULT_POST_PROCESSING_FLAGS,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

  g_object_class_install_property (gobject_class, PROP_DEBLOCKING_LEVEL,
      g_param_spec_uint ("deblocking-level", "Deblocking Level",
          "Deblocking level",
          0, 16, DEFAULT_DEBLOCKING_LEVEL,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

  g_object_class_install_property (gobject_class, PROP_NOISE_LEVEL,
      g_param_spec_uint ("noise-level", "Noise Level",
          "Noise level",
          0, 16, DEFAULT_NOISE_LEVEL,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

169 170 171 172 173
  g_object_class_install_property (gobject_class, PROP_THREADS,
      g_param_spec_uint ("threads", "Max Threads",
          "Maximum number of decoding threads",
          1, 16, DEFAULT_THREADS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

174 175 176 177 178
  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&gst_vp8_dec_src_template));
  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&gst_vp8_dec_sink_template));

179
  gst_element_class_set_metadata (element_class,
180 181
      "On2 VP8 Decoder",
      "Codec/Decoder/Video",
182 183
      "Decode VP8 video streams", "David Schleef <ds@entropywave.com>, "
      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
184

185 186 187 188 189 190 191
  base_video_decoder_class->start = GST_DEBUG_FUNCPTR (gst_vp8_dec_start);
  base_video_decoder_class->stop = GST_DEBUG_FUNCPTR (gst_vp8_dec_stop);
  base_video_decoder_class->reset = GST_DEBUG_FUNCPTR (gst_vp8_dec_reset);
  base_video_decoder_class->set_format =
      GST_DEBUG_FUNCPTR (gst_vp8_dec_set_format);
  base_video_decoder_class->handle_frame =
      GST_DEBUG_FUNCPTR (gst_vp8_dec_handle_frame);
192
  base_video_decoder_class->decide_allocation = gst_vp8_dec_decide_allocation;
193 194

  GST_DEBUG_CATEGORY_INIT (gst_vp8dec_debug, "vp8dec", 0, "VP8 Decoder");
195 196 197
}

static void
198
gst_vp8_dec_init (GstVP8Dec * gst_vp8_dec)
199
{
200
  GstVideoDecoder *decoder = (GstVideoDecoder *) gst_vp8_dec;
201

202
  GST_DEBUG_OBJECT (gst_vp8_dec, "gst_vp8_dec_init");
203
  gst_video_decoder_set_packetized (decoder, TRUE);
204 205 206 207
  gst_vp8_dec->post_processing = DEFAULT_POST_PROCESSING;
  gst_vp8_dec->post_processing_flags = DEFAULT_POST_PROCESSING_FLAGS;
  gst_vp8_dec->deblocking_level = DEFAULT_DEBLOCKING_LEVEL;
  gst_vp8_dec->noise_level = DEFAULT_NOISE_LEVEL;
208 209 210 211 212 213
}

static void
gst_vp8_dec_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
214
  GstVP8Dec *dec;
215

216
  g_return_if_fail (GST_IS_VP8_DEC (object));
217
  dec = GST_VP8_DEC (object);
218

219
  GST_DEBUG_OBJECT (object, "gst_vp8_dec_set_property");
220
  switch (prop_id) {
221 222 223 224 225 226 227 228 229 230 231 232
    case PROP_POST_PROCESSING:
      dec->post_processing = g_value_get_boolean (value);
      break;
    case PROP_POST_PROCESSING_FLAGS:
      dec->post_processing_flags = g_value_get_flags (value);
      break;
    case PROP_DEBLOCKING_LEVEL:
      dec->deblocking_level = g_value_get_uint (value);
      break;
    case PROP_NOISE_LEVEL:
      dec->noise_level = g_value_get_uint (value);
      break;
233 234 235
    case PROP_THREADS:
      dec->threads = g_value_get_uint (value);
      break;
236
    default:
237
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
238 239 240 241 242 243 244 245
      break;
  }
}

static void
gst_vp8_dec_get_property (GObject * object, guint prop_id, GValue * value,
    GParamSpec * pspec)
{
246
  GstVP8Dec *dec;
247

248
  g_return_if_fail (GST_IS_VP8_DEC (object));
249
  dec = GST_VP8_DEC (object);
250 251

  switch (prop_id) {
252 253 254 255 256 257 258 259 260 261 262 263
    case PROP_POST_PROCESSING:
      g_value_set_boolean (value, dec->post_processing);
      break;
    case PROP_POST_PROCESSING_FLAGS:
      g_value_set_flags (value, dec->post_processing_flags);
      break;
    case PROP_DEBLOCKING_LEVEL:
      g_value_set_uint (value, dec->deblocking_level);
      break;
    case PROP_NOISE_LEVEL:
      g_value_set_uint (value, dec->noise_level);
      break;
264 265 266
    case PROP_THREADS:
      g_value_set_uint (value, dec->threads);
      break;
267 268 269 270 271 272 273
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static gboolean
274
gst_vp8_dec_start (GstVideoDecoder * decoder)
275 276 277
{
  GstVP8Dec *gst_vp8_dec = GST_VP8_DEC (decoder);

278
  GST_DEBUG_OBJECT (gst_vp8_dec, "start");
279
  gst_vp8_dec->decoder_inited = FALSE;
280 281 282 283 284

  return TRUE;
}

static gboolean
285
gst_vp8_dec_stop (GstVideoDecoder * base_video_decoder)
286
{
287
  GstVP8Dec *gst_vp8_dec = GST_VP8_DEC (base_video_decoder);
288

289
  GST_DEBUG_OBJECT (gst_vp8_dec, "stop");
290 291 292 293 294 295 296 297 298

  if (gst_vp8_dec->output_state) {
    gst_video_codec_state_unref (gst_vp8_dec->output_state);
    gst_vp8_dec->output_state = NULL;
  }
  if (gst_vp8_dec->input_state) {
    gst_video_codec_state_unref (gst_vp8_dec->input_state);
    gst_vp8_dec->input_state = NULL;
  }
299 300 301
  if (gst_vp8_dec->decoder_inited)
    vpx_codec_destroy (&gst_vp8_dec->decoder);
  gst_vp8_dec->decoder_inited = FALSE;
302 303 304
  return TRUE;
}

305
static gboolean
306
gst_vp8_dec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state)
307 308 309 310 311 312
{
  GstVP8Dec *gst_vp8_dec = GST_VP8_DEC (decoder);

  GST_DEBUG_OBJECT (gst_vp8_dec, "set_format");
  gst_vp8_dec->decoder_inited = FALSE;

313 314 315 316
  if (gst_vp8_dec->input_state)
    gst_video_codec_state_unref (gst_vp8_dec->input_state);
  gst_vp8_dec->input_state = gst_video_codec_state_ref (state);

317 318 319
  return TRUE;
}

320
static gboolean
321
gst_vp8_dec_reset (GstVideoDecoder * base_video_decoder, gboolean hard)
322 323 324
{
  GstVP8Dec *decoder;

325
  GST_DEBUG_OBJECT (base_video_decoder, "reset");
326 327 328

  decoder = GST_VP8_DEC (base_video_decoder);

329 330 331 332
  if (decoder->output_state) {
    gst_video_codec_state_unref (decoder->output_state);
    decoder->output_state = NULL;
  }
333 334 335 336
  if (hard && decoder->input_state) {
    gst_video_codec_state_unref (decoder->input_state);
    decoder->input_state = NULL;
  }
337 338
  if (decoder->decoder_inited)
    vpx_codec_destroy (&decoder->decoder);
339 340 341 342 343 344 345 346 347 348
  decoder->decoder_inited = FALSE;

  return TRUE;
}

static void
gst_vp8_dec_send_tags (GstVP8Dec * dec)
{
  GstTagList *list;

349
  list = gst_tag_list_new_empty ();
350 351 352
  gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
      GST_TAG_VIDEO_CODEC, "VP8 video", NULL);

353
  gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (dec),
354
      gst_event_new_tag (list));
355 356
}

357 358 359 360
static void
gst_vp8_dec_image_to_buffer (GstVP8Dec * dec, const vpx_image_t * img,
    GstBuffer * buffer)
{
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
  int deststride, srcstride, height, width, line, comp;
  guint8 *dest, *src;
  GstVideoFrame frame;
  GstVideoInfo *info = &dec->output_state->info;

  if (!gst_video_frame_map (&frame, info, buffer, GST_MAP_WRITE)) {
    GST_ERROR_OBJECT (dec, "Could not map video buffer");
  }

  for (comp = 0; comp < 3; comp++) {
    dest = GST_VIDEO_FRAME_COMP_DATA (&frame, comp);
    src = img->planes[comp];
    width = GST_VIDEO_FRAME_COMP_WIDTH (&frame, comp);
    height = GST_VIDEO_FRAME_COMP_HEIGHT (&frame, comp);
    deststride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, comp);
    srcstride = img->stride[comp];

    /* FIXME (Edward) : Do a plane memcpy is srcstride == deststride instead
     * of copying line by line */
    for (line = 0; line < height; line++) {
      memcpy (dest, src, width);
      dest += deststride;
      src += srcstride;
    }
  }

  gst_video_frame_unmap (&frame);
388 389
}

390
static GstFlowReturn
391
open_codec (GstVP8Dec * dec, GstVideoCodecFrame * frame)
392
{
393 394 395
  int flags = 0;
  vpx_codec_stream_info_t stream_info;
  vpx_codec_caps_t caps;
396
  vpx_codec_dec_cfg_t cfg;
397
  GstVideoCodecState *state = dec->input_state;
398
  vpx_codec_err_t status;
399
  GstMapInfo minfo;
400

401
  memset (&stream_info, 0, sizeof (stream_info));
402
  memset (&cfg, 0, sizeof (cfg));
403
  stream_info.sz = sizeof (stream_info);
404

405 406 407 408 409
  if (!gst_buffer_map (frame->input_buffer, &minfo, GST_MAP_READ)) {
    GST_ERROR_OBJECT (dec, "Failed to map input buffer");
    return GST_FLOW_ERROR;
  }

410
  status = vpx_codec_peek_stream_info (&vpx_codec_vp8_dx_algo,
411 412 413
      minfo.data, minfo.size, &stream_info);

  gst_buffer_unmap (frame->input_buffer, &minfo);
414

415 416 417 418 419
  if (status != VPX_CODEC_OK || !stream_info.is_kf) {
    GST_WARNING_OBJECT (dec, "No keyframe, skipping");
    gst_video_decoder_finish_frame (GST_VIDEO_DECODER (dec), frame);
    return GST_FLOW_OK;
  }
420

421 422 423
  g_assert (dec->output_state == NULL);
  dec->output_state =
      gst_video_decoder_set_output_state (GST_VIDEO_DECODER (dec),
424
      GST_VIDEO_FORMAT_I420, stream_info.w, stream_info.h, state);
425
  gst_video_decoder_negotiate (GST_VIDEO_DECODER (dec));
426
  gst_vp8_dec_send_tags (dec);
427

428 429 430 431
  cfg.w = stream_info.w;
  cfg.h = stream_info.h;
  cfg.threads = dec->threads;

432
  caps = vpx_codec_get_caps (&vpx_codec_vp8_dx_algo);
433

434 435 436 437 438
  if (dec->post_processing) {
    if (!(caps & VPX_CODEC_CAP_POSTPROC)) {
      GST_WARNING_OBJECT (dec, "Decoder does not support post processing");
    } else {
      flags |= VPX_CODEC_USE_POSTPROC;
439
    }
440
  }
441

442
  status =
443
      vpx_codec_dec_init (&dec->decoder, &vpx_codec_vp8_dx_algo, &cfg, flags);
444 445 446 447 448 449
  if (status != VPX_CODEC_OK) {
    GST_ELEMENT_ERROR (dec, LIBRARY, INIT,
        ("Failed to initialize VP8 decoder"), ("%s",
            gst_vpx_error_name (status)));
    return GST_FLOW_ERROR;
  }
450

451 452
  if ((caps & VPX_CODEC_CAP_POSTPROC) && dec->post_processing) {
    vp8_postproc_cfg_t pp_cfg = { 0, };
453

454 455 456
    pp_cfg.post_proc_flag = dec->post_processing_flags;
    pp_cfg.deblocking_level = dec->deblocking_level;
    pp_cfg.noise_level = dec->noise_level;
457

458
    status = vpx_codec_control (&dec->decoder, VP8_SET_POSTPROC, &pp_cfg);
459
    if (status != VPX_CODEC_OK) {
460 461
      GST_WARNING_OBJECT (dec, "Couldn't set postprocessing settings: %s",
          gst_vpx_error_name (status));
462
    }
463
  }
464

465
  dec->decoder_inited = TRUE;
466

467 468
  return GST_FLOW_OK;
}
469

470 471 472 473 474 475 476 477 478 479
static GstFlowReturn
gst_vp8_dec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
{
  GstVP8Dec *dec;
  GstFlowReturn ret = GST_FLOW_OK;
  vpx_codec_err_t status;
  vpx_codec_iter_t iter = NULL;
  vpx_image_t *img;
  long decoder_deadline = 0;
  GstClockTimeDiff deadline;
480
  GstMapInfo minfo;
481

482
  GST_DEBUG_OBJECT (decoder, "handle_frame");
483

484 485 486 487
  dec = GST_VP8_DEC (decoder);

  if (!dec->decoder_inited)
    ret = open_codec (dec, frame);
488

489
  deadline = gst_video_decoder_get_max_decode_time (decoder, frame);
490 491 492 493 494 495 496 497
  if (deadline < 0) {
    decoder_deadline = 1;
  } else if (deadline == G_MAXINT64) {
    decoder_deadline = 0;
  } else {
    decoder_deadline = MAX (1, deadline / GST_MSECOND);
  }

498 499 500 501 502
  if (!gst_buffer_map (frame->input_buffer, &minfo, GST_MAP_READ)) {
    GST_ERROR_OBJECT (dec, "Failed to map input buffer");
    return GST_FLOW_ERROR;
  }

503
  status = vpx_codec_decode (&dec->decoder,
504 505 506 507
      minfo.data, minfo.size, NULL, decoder_deadline);

  gst_buffer_unmap (frame->input_buffer, &minfo);

508
  if (status) {
509 510
    GST_ELEMENT_ERROR (decoder, LIBRARY, ENCODE,
        ("Failed to decode frame"), ("%s", gst_vpx_error_name (status)));
511 512 513
    return GST_FLOW_ERROR;
  }

514 515
  img = vpx_codec_get_frame (&dec->decoder, &iter);
  if (img) {
516 517 518
    if (deadline < 0) {
      GST_LOG_OBJECT (dec, "Skipping late frame (%f s past deadline)",
          (double) -deadline / GST_SECOND);
519
      gst_video_decoder_drop_frame (decoder, frame);
520
    } else {
521
      ret = gst_video_decoder_allocate_output_frame (decoder, frame);
522 523

      if (ret == GST_FLOW_OK) {
524 525
        gst_vp8_dec_image_to_buffer (dec, img, frame->output_buffer);
        ret = gst_video_decoder_finish_frame (decoder, frame);
526
      } else {
527
        gst_video_decoder_finish_frame (decoder, frame);
528
      }
529
    }
530

531 532 533 534
    vpx_img_free (img);

    while ((img = vpx_codec_get_frame (&dec->decoder, &iter))) {
      GST_WARNING_OBJECT (decoder, "Multiple decoded frames... dropping");
535
      vpx_img_free (img);
536
    }
537 538
  } else {
    /* Invisible frame */
539 540
    GST_VIDEO_CODEC_FRAME_SET_DECODE_ONLY (frame);
    gst_video_decoder_finish_frame (decoder, frame);
541
  }
542 543 544

  return ret;
}
545

546 547 548 549 550 551 552 553 554 555 556 557 558 559
static gboolean
gst_vp8_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query)
{
  GstBufferPool *pool;
  GstStructure *config;

  if (!GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (bdec, query))
    return FALSE;

  g_assert (gst_query_get_n_allocation_pools (query) > 0);
  gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL);
  g_assert (pool != NULL);

  config = gst_buffer_pool_get_config (pool);
560
  if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
561 562 563 564 565 566 567 568 569
    gst_buffer_pool_config_add_option (config,
        GST_BUFFER_POOL_OPTION_VIDEO_META);
  }
  gst_buffer_pool_set_config (pool, config);
  gst_object_unref (pool);

  return TRUE;
}

570
#endif /* HAVE_VP8_DECODER */