gstvp8dec.c 17.5 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
 *
 * 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
18 19
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA 02110-1301, USA.
20 21
 *
 */
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_static_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

  if (gst_vp8_dec->output_state) {
    gst_video_codec_state_unref (gst_vp8_dec->output_state);
    gst_vp8_dec->output_state = NULL;
  }
295

296 297 298 299
  if (gst_vp8_dec->input_state) {
    gst_video_codec_state_unref (gst_vp8_dec->input_state);
    gst_vp8_dec->input_state = NULL;
  }
300

301 302 303
  if (gst_vp8_dec->decoder_inited)
    vpx_codec_destroy (&gst_vp8_dec->decoder);
  gst_vp8_dec->decoder_inited = FALSE;
304

305 306 307
  return TRUE;
}

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

  GST_DEBUG_OBJECT (gst_vp8_dec, "set_format");
314

Sebastian Dröge's avatar
Sebastian Dröge committed
315 316
  if (gst_vp8_dec->decoder_inited)
    vpx_codec_destroy (&gst_vp8_dec->decoder);
317 318
  gst_vp8_dec->decoder_inited = FALSE;

319 320 321 322
  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);

323 324 325
  return TRUE;
}

326
static gboolean
327
gst_vp8_dec_reset (GstVideoDecoder * base_video_decoder, gboolean hard)
328 329 330
{
  GstVP8Dec *decoder;

331
  GST_DEBUG_OBJECT (base_video_decoder, "reset");
332 333 334

  decoder = GST_VP8_DEC (base_video_decoder);

335 336 337 338
  if (decoder->output_state) {
    gst_video_codec_state_unref (decoder->output_state);
    decoder->output_state = NULL;
  }
339

340 341
  if (decoder->decoder_inited)
    vpx_codec_destroy (&decoder->decoder);
342 343 344 345 346 347 348 349 350 351
  decoder->decoder_inited = FALSE;

  return TRUE;
}

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

352
  list = gst_tag_list_new_empty ();
353 354 355
  gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
      GST_TAG_VIDEO_CODEC, "VP8 video", NULL);

356
  gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (dec),
357
      gst_event_new_tag (list));
358 359
}

360 361 362 363
static void
gst_vp8_dec_image_to_buffer (GstVP8Dec * dec, const vpx_image_t * img,
    GstBuffer * buffer)
{
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
  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);
391 392
}

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

404
  memset (&stream_info, 0, sizeof (stream_info));
405
  memset (&cfg, 0, sizeof (cfg));
406
  stream_info.sz = sizeof (stream_info);
407

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

413
  status = vpx_codec_peek_stream_info (&vpx_codec_vp8_dx_algo,
414 415 416
      minfo.data, minfo.size, &stream_info);

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

418 419 420 421 422 423 424
  if (status != VPX_CODEC_OK) {
    GST_WARNING_OBJECT (dec, "VPX preprocessing error: %s",
        gst_vpx_error_name (status));
    gst_video_decoder_finish_frame (GST_VIDEO_DECODER (dec), frame);
    return GST_FLOW_CUSTOM_SUCCESS_1;
  }
  if (!stream_info.is_kf) {
425 426
    GST_WARNING_OBJECT (dec, "No keyframe, skipping");
    gst_video_decoder_finish_frame (GST_VIDEO_DECODER (dec), frame);
427
    return GST_FLOW_CUSTOM_SUCCESS_1;
428
  }
429

430 431 432
  g_assert (dec->output_state == NULL);
  dec->output_state =
      gst_video_decoder_set_output_state (GST_VIDEO_DECODER (dec),
433
      GST_VIDEO_FORMAT_I420, stream_info.w, stream_info.h, state);
434
  gst_video_decoder_negotiate (GST_VIDEO_DECODER (dec));
435
  gst_vp8_dec_send_tags (dec);
436

437 438 439 440
  cfg.w = stream_info.w;
  cfg.h = stream_info.h;
  cfg.threads = dec->threads;

441
  caps = vpx_codec_get_caps (&vpx_codec_vp8_dx_algo);
442

443 444 445 446 447
  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;
448
    }
449
  }
450

451
  status =
452
      vpx_codec_dec_init (&dec->decoder, &vpx_codec_vp8_dx_algo, &cfg, flags);
453 454 455 456 457 458
  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;
  }
459

460 461
  if ((caps & VPX_CODEC_CAP_POSTPROC) && dec->post_processing) {
    vp8_postproc_cfg_t pp_cfg = { 0, };
462

463 464 465
    pp_cfg.post_proc_flag = dec->post_processing_flags;
    pp_cfg.deblocking_level = dec->deblocking_level;
    pp_cfg.noise_level = dec->noise_level;
466

467
    status = vpx_codec_control (&dec->decoder, VP8_SET_POSTPROC, &pp_cfg);
468
    if (status != VPX_CODEC_OK) {
469 470
      GST_WARNING_OBJECT (dec, "Couldn't set postprocessing settings: %s",
          gst_vpx_error_name (status));
471
    }
472
  }
473

474
  dec->decoder_inited = TRUE;
475

476 477
  return GST_FLOW_OK;
}
478

479 480 481 482 483 484 485 486 487 488
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;
489
  GstMapInfo minfo;
490

491
  GST_DEBUG_OBJECT (decoder, "handle_frame");
492

493 494
  dec = GST_VP8_DEC (decoder);

495
  if (!dec->decoder_inited) {
496
    ret = open_codec (dec, frame);
497 498
    if (ret == GST_FLOW_CUSTOM_SUCCESS_1)
      return GST_FLOW_OK;
499 500
    else if (ret != GST_FLOW_OK)
      return ret;
501
  }
502

503
  deadline = gst_video_decoder_get_max_decode_time (decoder, frame);
504 505 506 507 508 509 510 511
  if (deadline < 0) {
    decoder_deadline = 1;
  } else if (deadline == G_MAXINT64) {
    decoder_deadline = 0;
  } else {
    decoder_deadline = MAX (1, deadline / GST_MSECOND);
  }

512 513 514 515 516
  if (!gst_buffer_map (frame->input_buffer, &minfo, GST_MAP_READ)) {
    GST_ERROR_OBJECT (dec, "Failed to map input buffer");
    return GST_FLOW_ERROR;
  }

517
  status = vpx_codec_decode (&dec->decoder,
518 519 520 521
      minfo.data, minfo.size, NULL, decoder_deadline);

  gst_buffer_unmap (frame->input_buffer, &minfo);

522
  if (status) {
523 524 525
    GST_VIDEO_DECODER_ERROR (decoder, 1, LIBRARY, ENCODE,
        ("Failed to decode frame"), ("%s", gst_vpx_error_name (status)), ret);
    return ret;
526 527
  }

528 529
  img = vpx_codec_get_frame (&dec->decoder, &iter);
  if (img) {
530 531 532
    if (deadline < 0) {
      GST_LOG_OBJECT (dec, "Skipping late frame (%f s past deadline)",
          (double) -deadline / GST_SECOND);
533
      gst_video_decoder_drop_frame (decoder, frame);
534
    } else {
535
      ret = gst_video_decoder_allocate_output_frame (decoder, frame);
536 537

      if (ret == GST_FLOW_OK) {
538 539
        gst_vp8_dec_image_to_buffer (dec, img, frame->output_buffer);
        ret = gst_video_decoder_finish_frame (decoder, frame);
540
      } else {
541
        gst_video_decoder_finish_frame (decoder, frame);
542
      }
543
    }
544

545 546 547 548
    vpx_img_free (img);

    while ((img = vpx_codec_get_frame (&dec->decoder, &iter))) {
      GST_WARNING_OBJECT (decoder, "Multiple decoded frames... dropping");
549
      vpx_img_free (img);
550
    }
551 552
  } else {
    /* Invisible frame */
553 554
    GST_VIDEO_CODEC_FRAME_SET_DECODE_ONLY (frame);
    gst_video_decoder_finish_frame (decoder, frame);
555
  }
556 557 558

  return ret;
}
559

560 561 562 563 564 565 566 567 568 569 570 571 572 573
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);
574
  if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
575 576 577 578 579 580 581 582 583
    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;
}

584
#endif /* HAVE_VP8_DECODER */