gstvp8dec.c 17.9 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
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);
109
static gboolean gst_vp8_dec_flush (GstVideoDecoder * decoder);
110 111
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
  base_video_decoder_class->start = GST_DEBUG_FUNCPTR (gst_vp8_dec_start);
  base_video_decoder_class->stop = GST_DEBUG_FUNCPTR (gst_vp8_dec_stop);
187
  base_video_decoder_class->flush = GST_DEBUG_FUNCPTR (gst_vp8_dec_flush);
188 189 190 191
  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

  gst_video_decoder_set_needs_format (decoder, TRUE);
210 211 212 213 214 215
}

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

218
  g_return_if_fail (GST_IS_VP8_DEC (object));
219
  dec = GST_VP8_DEC (object);
220

221
  GST_DEBUG_OBJECT (object, "gst_vp8_dec_set_property");
222
  switch (prop_id) {
223 224 225 226 227 228 229 230 231 232 233 234
    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;
235 236 237
    case PROP_THREADS:
      dec->threads = g_value_get_uint (value);
      break;
238
    default:
239
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
240 241 242 243 244 245 246 247
      break;
  }
}

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

250
  g_return_if_fail (GST_IS_VP8_DEC (object));
251
  dec = GST_VP8_DEC (object);
252 253

  switch (prop_id) {
254 255 256 257 258 259 260 261 262 263 264 265
    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;
266 267 268
    case PROP_THREADS:
      g_value_set_uint (value, dec->threads);
      break;
269 270 271 272 273 274 275
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

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

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

  return TRUE;
}

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

291
  GST_DEBUG_OBJECT (gst_vp8_dec, "stop");
292 293 294 295 296

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

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

303 304 305
  if (gst_vp8_dec->decoder_inited)
    vpx_codec_destroy (&gst_vp8_dec->decoder);
  gst_vp8_dec->decoder_inited = FALSE;
306

307 308 309
  return TRUE;
}

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

  GST_DEBUG_OBJECT (gst_vp8_dec, "set_format");
316

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

321 322 323 324 325 326
  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) {
327
    gst_video_codec_state_unref (gst_vp8_dec->input_state);
328 329 330
    gst_vp8_dec->input_state = NULL;
  }

331 332
  gst_vp8_dec->input_state = gst_video_codec_state_ref (state);

333 334 335
  return TRUE;
}

336
static gboolean
337
gst_vp8_dec_flush (GstVideoDecoder * base_video_decoder)
338 339 340
{
  GstVP8Dec *decoder;

341
  GST_DEBUG_OBJECT (base_video_decoder, "flush");
342 343 344

  decoder = GST_VP8_DEC (base_video_decoder);

345 346 347 348
  if (decoder->output_state) {
    gst_video_codec_state_unref (decoder->output_state);
    decoder->output_state = NULL;
  }
349

350 351
  if (decoder->decoder_inited)
    vpx_codec_destroy (&decoder->decoder);
352 353 354 355 356 357 358 359 360 361
  decoder->decoder_inited = FALSE;

  return TRUE;
}

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

362
  list = gst_tag_list_new_empty ();
363 364 365
  gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
      GST_TAG_VIDEO_CODEC, "VP8 video", NULL);

366
  gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (dec),
367
      gst_event_new_tag (list));
368 369
}

370 371 372 373
static void
gst_vp8_dec_image_to_buffer (GstVP8Dec * dec, const vpx_image_t * img,
    GstBuffer * buffer)
{
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
  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);
401 402
}

403
static GstFlowReturn
404
open_codec (GstVP8Dec * dec, GstVideoCodecFrame * frame)
405
{
406 407 408
  int flags = 0;
  vpx_codec_stream_info_t stream_info;
  vpx_codec_caps_t caps;
409
  vpx_codec_dec_cfg_t cfg;
410
  GstVideoCodecState *state = dec->input_state;
411
  vpx_codec_err_t status;
412
  GstMapInfo minfo;
413

414
  memset (&stream_info, 0, sizeof (stream_info));
415
  memset (&cfg, 0, sizeof (cfg));
416
  stream_info.sz = sizeof (stream_info);
417

418 419 420 421 422
  if (!gst_buffer_map (frame->input_buffer, &minfo, GST_MAP_READ)) {
    GST_ERROR_OBJECT (dec, "Failed to map input buffer");
    return GST_FLOW_ERROR;
  }

423
  status = vpx_codec_peek_stream_info (&vpx_codec_vp8_dx_algo,
424 425 426
      minfo.data, minfo.size, &stream_info);

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

428 429 430 431 432 433 434
  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) {
435 436
    GST_WARNING_OBJECT (dec, "No keyframe, skipping");
    gst_video_decoder_finish_frame (GST_VIDEO_DECODER (dec), frame);
437
    return GST_FLOW_CUSTOM_SUCCESS_1;
438
  }
439

440 441 442
  g_assert (dec->output_state == NULL);
  dec->output_state =
      gst_video_decoder_set_output_state (GST_VIDEO_DECODER (dec),
443
      GST_VIDEO_FORMAT_I420, stream_info.w, stream_info.h, state);
444
  gst_video_decoder_negotiate (GST_VIDEO_DECODER (dec));
445
  gst_vp8_dec_send_tags (dec);
446

447 448 449 450
  cfg.w = stream_info.w;
  cfg.h = stream_info.h;
  cfg.threads = dec->threads;

451
  caps = vpx_codec_get_caps (&vpx_codec_vp8_dx_algo);
452

453 454 455 456 457
  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;
458
    }
459
  }
460

461
  status =
462
      vpx_codec_dec_init (&dec->decoder, &vpx_codec_vp8_dx_algo, &cfg, flags);
463 464 465 466 467 468
  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;
  }
469

470 471
  if ((caps & VPX_CODEC_CAP_POSTPROC) && dec->post_processing) {
    vp8_postproc_cfg_t pp_cfg = { 0, };
472

473 474 475
    pp_cfg.post_proc_flag = dec->post_processing_flags;
    pp_cfg.deblocking_level = dec->deblocking_level;
    pp_cfg.noise_level = dec->noise_level;
476

477
    status = vpx_codec_control (&dec->decoder, VP8_SET_POSTPROC, &pp_cfg);
478
    if (status != VPX_CODEC_OK) {
479 480
      GST_WARNING_OBJECT (dec, "Couldn't set postprocessing settings: %s",
          gst_vpx_error_name (status));
481
    }
482
  }
483

484
  dec->decoder_inited = TRUE;
485

486 487
  return GST_FLOW_OK;
}
488

489 490 491 492 493 494 495 496 497 498
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;
499
  GstMapInfo minfo;
500

501
  GST_DEBUG_OBJECT (decoder, "handle_frame");
502

503 504
  dec = GST_VP8_DEC (decoder);

505
  if (!dec->decoder_inited) {
506
    ret = open_codec (dec, frame);
507 508
    if (ret == GST_FLOW_CUSTOM_SUCCESS_1)
      return GST_FLOW_OK;
509 510
    else if (ret != GST_FLOW_OK)
      return ret;
511
  }
512

513
  deadline = gst_video_decoder_get_max_decode_time (decoder, frame);
514 515 516 517 518 519 520 521
  if (deadline < 0) {
    decoder_deadline = 1;
  } else if (deadline == G_MAXINT64) {
    decoder_deadline = 0;
  } else {
    decoder_deadline = MAX (1, deadline / GST_MSECOND);
  }

522 523 524 525 526
  if (!gst_buffer_map (frame->input_buffer, &minfo, GST_MAP_READ)) {
    GST_ERROR_OBJECT (dec, "Failed to map input buffer");
    return GST_FLOW_ERROR;
  }

527
  status = vpx_codec_decode (&dec->decoder,
528 529 530 531
      minfo.data, minfo.size, NULL, decoder_deadline);

  gst_buffer_unmap (frame->input_buffer, &minfo);

532
  if (status) {
533 534 535
    GST_VIDEO_DECODER_ERROR (decoder, 1, LIBRARY, ENCODE,
        ("Failed to decode frame"), ("%s", gst_vpx_error_name (status)), ret);
    return ret;
536 537
  }

538 539
  img = vpx_codec_get_frame (&dec->decoder, &iter);
  if (img) {
540 541 542 543 544 545 546 547
    if (img->fmt != VPX_IMG_FMT_I420) {
      vpx_img_free (img);
      GST_ELEMENT_ERROR (decoder, LIBRARY, ENCODE,
          ("Failed to decode frame"), ("Unsupported color format %d",
              img->fmt));
      return GST_FLOW_ERROR;
    }

548 549 550
    if (deadline < 0) {
      GST_LOG_OBJECT (dec, "Skipping late frame (%f s past deadline)",
          (double) -deadline / GST_SECOND);
551
      gst_video_decoder_drop_frame (decoder, frame);
552
    } else {
553
      ret = gst_video_decoder_allocate_output_frame (decoder, frame);
554 555

      if (ret == GST_FLOW_OK) {
556 557
        gst_vp8_dec_image_to_buffer (dec, img, frame->output_buffer);
        ret = gst_video_decoder_finish_frame (decoder, frame);
558
      } else {
559
        gst_video_decoder_finish_frame (decoder, frame);
560
      }
561
    }
562

563 564 565 566
    vpx_img_free (img);

    while ((img = vpx_codec_get_frame (&dec->decoder, &iter))) {
      GST_WARNING_OBJECT (decoder, "Multiple decoded frames... dropping");
567
      vpx_img_free (img);
568
    }
569 570
  } else {
    /* Invisible frame */
571 572
    GST_VIDEO_CODEC_FRAME_SET_DECODE_ONLY (frame);
    gst_video_decoder_finish_frame (decoder, frame);
573
  }
574 575 576

  return ret;
}
577

578 579 580 581 582 583 584 585 586 587 588 589 590 591
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);
592
  if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
593 594 595 596 597 598 599 600 601
    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;
}

602
#endif /* HAVE_VP8_DECODER */