v4l2src: Try to avoid TRY_FMT when camera is streaming
[platform/upstream/gst-plugins-good.git] / ext / vpx / gstvpxdec.c
1 /* VPX
2  * Copyright (C) 2006 David Schleef <ds@schleef.org>
3  * Copyright (C) 2008,2009,2010 Entropy Wave Inc
4  * Copyright (C) 2010-2012 Sebastian Dröge <sebastian.droege@collabora.co.uk>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #if defined(HAVE_VP8_DECODER) || defined(HAVE_VP9_DECODER)
26
27 #include <string.h>
28
29 #include "gstvpxdec.h"
30 #include "gstvp8utils.h"
31
32 #include <gst/video/gstvideometa.h>
33 #include <gst/video/gstvideopool.h>
34
35 GST_DEBUG_CATEGORY_STATIC (gst_vpxdec_debug);
36 #define GST_CAT_DEFAULT gst_vpxdec_debug
37
38 #define DEFAULT_POST_PROCESSING FALSE
39 #define DEFAULT_POST_PROCESSING_FLAGS (VP8_DEBLOCK | VP8_DEMACROBLOCK | VP8_MFQE)
40 #define DEFAULT_DEBLOCKING_LEVEL 4
41 #define DEFAULT_NOISE_LEVEL 0
42 #define DEFAULT_THREADS 0
43 #define DEFAULT_VIDEO_CODEC_TAG NULL
44 #define DEFAULT_CODEC_ALGO NULL
45
46 enum
47 {
48   PROP_0,
49   PROP_POST_PROCESSING,
50   PROP_POST_PROCESSING_FLAGS,
51   PROP_DEBLOCKING_LEVEL,
52   PROP_NOISE_LEVEL,
53   PROP_THREADS
54 };
55
56 #define C_FLAGS(v) ((guint) v)
57 #define GST_VPX_DEC_TYPE_POST_PROCESSING_FLAGS (gst_vpx_dec_post_processing_flags_get_type())
58 static GType
59 gst_vpx_dec_post_processing_flags_get_type (void)
60 {
61   static const GFlagsValue values[] = {
62     {C_FLAGS (VP8_DEBLOCK), "Deblock", "deblock"},
63     {C_FLAGS (VP8_DEMACROBLOCK), "Demacroblock", "demacroblock"},
64     {C_FLAGS (VP8_ADDNOISE), "Add noise", "addnoise"},
65     {C_FLAGS (VP8_DEBUG_TXT_FRAME_INFO),
66           "Print frame information",
67         "visualize-frame-info"},
68     {C_FLAGS (VP8_DEBUG_TXT_MBLK_MODES),
69           "Show macroblock mode selection overlaid on image",
70         "visualize-macroblock-modes"},
71     {C_FLAGS (VP8_DEBUG_TXT_DC_DIFF),
72           "Show dc diff for each macro block overlaid on image",
73         "visualize-dc-diff"},
74     {C_FLAGS (VP8_DEBUG_TXT_RATE_INFO),
75           "Print video rate info",
76         "visualize-rate-info"},
77     {C_FLAGS (VP8_MFQE), "Multi-frame quality enhancement", "mfqe"},
78     {0, NULL, NULL}
79   };
80   static volatile GType id = 0;
81
82   if (g_once_init_enter ((gsize *) & id)) {
83     GType _id;
84
85     _id = g_flags_register_static ("GstVPXDecPostProcessingFlags", values);
86
87     g_once_init_leave ((gsize *) & id, _id);
88   }
89
90   return id;
91 }
92
93 #undef C_FLAGS
94
95 static void gst_vpx_dec_set_property (GObject * object, guint prop_id,
96     const GValue * value, GParamSpec * pspec);
97 static void gst_vpx_dec_get_property (GObject * object, guint prop_id,
98     GValue * value, GParamSpec * pspec);
99
100 static gboolean gst_vpx_dec_start (GstVideoDecoder * decoder);
101 static gboolean gst_vpx_dec_stop (GstVideoDecoder * decoder);
102 static gboolean gst_vpx_dec_set_format (GstVideoDecoder * decoder,
103     GstVideoCodecState * state);
104 static gboolean gst_vpx_dec_flush (GstVideoDecoder * decoder);
105 static GstFlowReturn
106 gst_vpx_dec_handle_frame (GstVideoDecoder * decoder,
107     GstVideoCodecFrame * frame);
108 static gboolean gst_vpx_dec_decide_allocation (GstVideoDecoder * decoder,
109     GstQuery * query);
110
111 static void gst_vpx_dec_image_to_buffer (GstVPXDec * dec,
112     const vpx_image_t * img, GstBuffer * buffer);
113 static GstFlowReturn gst_vpx_dec_open_codec (GstVPXDec * dec,
114     GstVideoCodecFrame * frame);
115 static void gst_vpx_dec_default_send_tags (GstVPXDec * dec);
116 static void gst_vpx_dec_set_stream_info (GstVPXDec * dec,
117     vpx_codec_stream_info_t * stream_info);
118 static void gst_vpx_dec_set_default_format (GstVPXDec * dec, GstVideoFormat fmt,
119     int width, int height);
120 static gboolean gst_vpx_dec_default_frame_format (GstVPXDec * dec,
121     vpx_image_t * img, GstVideoFormat * fmt);
122 static void gst_vpx_dec_handle_resolution_change (GstVPXDec * dec,
123     vpx_image_t * img, GstVideoFormat fmt);
124
125 #define parent_class gst_vpx_dec_parent_class
126 G_DEFINE_TYPE (GstVPXDec, gst_vpx_dec, GST_TYPE_VIDEO_DECODER);
127
128 static void
129 gst_vpx_dec_class_init (GstVPXDecClass * klass)
130 {
131   GObjectClass *gobject_class;
132   GstVideoDecoderClass *base_video_decoder_class;
133
134   gobject_class = G_OBJECT_CLASS (klass);
135   base_video_decoder_class = GST_VIDEO_DECODER_CLASS (klass);
136
137   gobject_class->set_property = gst_vpx_dec_set_property;
138   gobject_class->get_property = gst_vpx_dec_get_property;
139
140   g_object_class_install_property (gobject_class, PROP_POST_PROCESSING,
141       g_param_spec_boolean ("post-processing", "Post Processing",
142           "Enable post processing", DEFAULT_POST_PROCESSING,
143           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
144
145   g_object_class_install_property (gobject_class, PROP_POST_PROCESSING_FLAGS,
146       g_param_spec_flags ("post-processing-flags", "Post Processing Flags",
147           "Flags to control post processing",
148           GST_VPX_DEC_TYPE_POST_PROCESSING_FLAGS, DEFAULT_POST_PROCESSING_FLAGS,
149           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
150
151   g_object_class_install_property (gobject_class, PROP_DEBLOCKING_LEVEL,
152       g_param_spec_uint ("deblocking-level", "Deblocking Level",
153           "Deblocking level",
154           0, 16, DEFAULT_DEBLOCKING_LEVEL,
155           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
156
157   g_object_class_install_property (gobject_class, PROP_NOISE_LEVEL,
158       g_param_spec_uint ("noise-level", "Noise Level",
159           "Noise level",
160           0, 16, DEFAULT_NOISE_LEVEL,
161           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
162
163   g_object_class_install_property (gobject_class, PROP_THREADS,
164       g_param_spec_uint ("threads", "Max Threads",
165           "Maximum number of decoding threads",
166           0, 16, DEFAULT_THREADS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
167
168   base_video_decoder_class->start = GST_DEBUG_FUNCPTR (gst_vpx_dec_start);
169   base_video_decoder_class->stop = GST_DEBUG_FUNCPTR (gst_vpx_dec_stop);
170   base_video_decoder_class->flush = GST_DEBUG_FUNCPTR (gst_vpx_dec_flush);
171   base_video_decoder_class->set_format =
172       GST_DEBUG_FUNCPTR (gst_vpx_dec_set_format);
173   base_video_decoder_class->handle_frame =
174       GST_DEBUG_FUNCPTR (gst_vpx_dec_handle_frame);;
175   base_video_decoder_class->decide_allocation =
176       GST_DEBUG_FUNCPTR (gst_vpx_dec_decide_allocation);
177
178   klass->video_codec_tag = DEFAULT_VIDEO_CODEC_TAG;
179   klass->codec_algo = DEFAULT_CODEC_ALGO;
180   klass->open_codec = GST_DEBUG_FUNCPTR (gst_vpx_dec_open_codec);
181   klass->send_tags = GST_DEBUG_FUNCPTR (gst_vpx_dec_default_send_tags);
182   klass->set_stream_info = NULL;
183   klass->set_default_format = NULL;
184   klass->handle_resolution_change = NULL;
185   klass->get_frame_format =
186       GST_DEBUG_FUNCPTR (gst_vpx_dec_default_frame_format);
187
188   GST_DEBUG_CATEGORY_INIT (gst_vpxdec_debug, "vpxdec", 0, "VPX Decoder");
189 }
190
191 static void
192 gst_vpx_dec_init (GstVPXDec * gst_vpx_dec)
193 {
194   GstVideoDecoder *decoder = (GstVideoDecoder *) gst_vpx_dec;
195
196   GST_DEBUG_OBJECT (gst_vpx_dec, "gst_vpx_dec_init");
197   gst_video_decoder_set_packetized (decoder, TRUE);
198   gst_vpx_dec->post_processing = DEFAULT_POST_PROCESSING;
199   gst_vpx_dec->post_processing_flags = DEFAULT_POST_PROCESSING_FLAGS;
200   gst_vpx_dec->deblocking_level = DEFAULT_DEBLOCKING_LEVEL;
201   gst_vpx_dec->noise_level = DEFAULT_NOISE_LEVEL;
202
203   gst_video_decoder_set_needs_format (decoder, TRUE);
204   gst_video_decoder_set_use_default_pad_acceptcaps (decoder, TRUE);
205   GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_DECODER_SINK_PAD (decoder));
206 }
207
208 static void
209 gst_vpx_dec_set_property (GObject * object, guint prop_id,
210     const GValue * value, GParamSpec * pspec)
211 {
212   GstVPXDec *dec;
213
214   g_return_if_fail (GST_IS_VPX_DEC (object));
215   dec = GST_VPX_DEC (object);
216
217   GST_DEBUG_OBJECT (object, "gst_vpx_dec_set_property");
218   switch (prop_id) {
219     case PROP_POST_PROCESSING:
220       dec->post_processing = g_value_get_boolean (value);
221       break;
222     case PROP_POST_PROCESSING_FLAGS:
223       dec->post_processing_flags = g_value_get_flags (value);
224       break;
225     case PROP_DEBLOCKING_LEVEL:
226       dec->deblocking_level = g_value_get_uint (value);
227       break;
228     case PROP_NOISE_LEVEL:
229       dec->noise_level = g_value_get_uint (value);
230       break;
231     case PROP_THREADS:
232       dec->threads = g_value_get_uint (value);
233       break;
234     default:
235       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
236       break;
237   }
238 }
239
240 static void
241 gst_vpx_dec_get_property (GObject * object, guint prop_id, GValue * value,
242     GParamSpec * pspec)
243 {
244   GstVPXDec *dec;
245
246   g_return_if_fail (GST_IS_VPX_DEC (object));
247   dec = GST_VPX_DEC (object);
248
249   switch (prop_id) {
250     case PROP_POST_PROCESSING:
251       g_value_set_boolean (value, dec->post_processing);
252       break;
253     case PROP_POST_PROCESSING_FLAGS:
254       g_value_set_flags (value, dec->post_processing_flags);
255       break;
256     case PROP_DEBLOCKING_LEVEL:
257       g_value_set_uint (value, dec->deblocking_level);
258       break;
259     case PROP_NOISE_LEVEL:
260       g_value_set_uint (value, dec->noise_level);
261       break;
262     case PROP_THREADS:
263       g_value_set_uint (value, dec->threads);
264       break;
265     default:
266       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
267       break;
268   }
269 }
270
271 static gboolean
272 gst_vpx_dec_start (GstVideoDecoder * decoder)
273 {
274   GstVPXDec *gst_vpx_dec = GST_VPX_DEC (decoder);
275
276   GST_DEBUG_OBJECT (gst_vpx_dec, "start");
277   gst_vpx_dec->decoder_inited = FALSE;
278
279   return TRUE;
280 }
281
282 static gboolean
283 gst_vpx_dec_stop (GstVideoDecoder * base_video_decoder)
284 {
285   GstVPXDec *gst_vpx_dec = GST_VPX_DEC (base_video_decoder);
286
287   GST_DEBUG_OBJECT (gst_vpx_dec, "stop");
288
289   if (gst_vpx_dec->output_state) {
290     gst_video_codec_state_unref (gst_vpx_dec->output_state);
291     gst_vpx_dec->output_state = NULL;
292   }
293
294   if (gst_vpx_dec->input_state) {
295     gst_video_codec_state_unref (gst_vpx_dec->input_state);
296     gst_vpx_dec->input_state = NULL;
297   }
298
299   if (gst_vpx_dec->decoder_inited)
300     vpx_codec_destroy (&gst_vpx_dec->decoder);
301   gst_vpx_dec->decoder_inited = FALSE;
302
303   if (gst_vpx_dec->pool) {
304     gst_buffer_pool_set_active (gst_vpx_dec->pool, FALSE);
305     gst_object_unref (gst_vpx_dec->pool);
306     gst_vpx_dec->pool = NULL;
307     gst_vpx_dec->buf_size = 0;
308   }
309
310   return TRUE;
311 }
312
313 static gboolean
314 gst_vpx_dec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state)
315 {
316   GstVPXDec *gst_vpx_dec = GST_VPX_DEC (decoder);
317
318   GST_DEBUG_OBJECT (gst_vpx_dec, "set_format");
319
320   if (gst_vpx_dec->decoder_inited)
321     vpx_codec_destroy (&gst_vpx_dec->decoder);
322   gst_vpx_dec->decoder_inited = FALSE;
323
324   if (gst_vpx_dec->output_state) {
325     gst_video_codec_state_unref (gst_vpx_dec->output_state);
326     gst_vpx_dec->output_state = NULL;
327   }
328
329   if (gst_vpx_dec->input_state) {
330     gst_video_codec_state_unref (gst_vpx_dec->input_state);
331   }
332
333   gst_vpx_dec->input_state = gst_video_codec_state_ref (state);
334
335   return TRUE;
336 }
337
338 static gboolean
339 gst_vpx_dec_flush (GstVideoDecoder * base_video_decoder)
340 {
341   GstVPXDec *decoder;
342
343   GST_DEBUG_OBJECT (base_video_decoder, "flush");
344
345   decoder = GST_VPX_DEC (base_video_decoder);
346
347   if (decoder->output_state) {
348     gst_video_codec_state_unref (decoder->output_state);
349     decoder->output_state = NULL;
350   }
351
352   if (decoder->decoder_inited)
353     vpx_codec_destroy (&decoder->decoder);
354   decoder->decoder_inited = FALSE;
355
356   return TRUE;
357 }
358
359 static void
360 gst_vpx_dec_default_send_tags (GstVPXDec * dec)
361 {
362   GstTagList *list;
363   GstVPXDecClass *vpxclass = GST_VPX_DEC_GET_CLASS (dec);
364
365   if (vpxclass->video_codec_tag == NULL)
366     return;
367
368   list = gst_tag_list_new_empty ();
369   gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
370       GST_TAG_VIDEO_CODEC, vpxclass->video_codec_tag, NULL);
371
372   gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (dec),
373       gst_event_new_tag (list));
374 }
375
376 #ifdef HAVE_VPX_1_4
377 struct Frame
378 {
379   GstMapInfo info;
380   GstBuffer *buffer;
381 };
382
383 static GstBuffer *
384 gst_vpx_dec_prepare_image (GstVPXDec * dec, const vpx_image_t * img)
385 {
386   gint comp;
387   GstVideoMeta *vmeta;
388   GstBuffer *buffer;
389   struct Frame *frame = img->fb_priv;
390   GstVideoInfo *info = &dec->output_state->info;
391
392   buffer = gst_buffer_ref (frame->buffer);
393
394   vmeta = gst_buffer_get_video_meta (buffer);
395   vmeta->format = GST_VIDEO_INFO_FORMAT (info);
396   vmeta->width = GST_VIDEO_INFO_WIDTH (info);
397   vmeta->height = GST_VIDEO_INFO_HEIGHT (info);
398   vmeta->n_planes = GST_VIDEO_INFO_N_PLANES (info);
399
400   for (comp = 0; comp < 4; comp++) {
401     vmeta->stride[comp] = img->stride[comp];
402     vmeta->offset[comp] =
403         img->planes[comp] ? img->planes[comp] - frame->info.data : 0;
404   }
405
406   /* FIXME This is a READ/WRITE mapped buffer see bug #754826 */
407
408   return buffer;
409 }
410
411 static int
412 gst_vpx_dec_get_buffer_cb (gpointer priv, gsize min_size,
413     vpx_codec_frame_buffer_t * fb)
414 {
415   GstVPXDec *dec = priv;
416   GstBuffer *buffer = NULL;
417   struct Frame *frame;
418   GstFlowReturn ret;
419
420   if (!dec->pool || dec->buf_size != min_size) {
421     GstBufferPool *pool;
422     GstStructure *config;
423     GstCaps *caps;
424     GstAllocator *allocator;
425     GstAllocationParams params;
426
427     if (dec->pool) {
428       gst_buffer_pool_set_active (dec->pool, FALSE);
429       gst_object_unref (dec->pool);
430       dec->pool = NULL;
431       dec->buf_size = 0;
432     }
433
434     gst_video_decoder_get_allocator (GST_VIDEO_DECODER (dec), &allocator,
435         &params);
436
437     if (allocator &&
438         GST_OBJECT_FLAG_IS_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC)) {
439       gst_object_unref (allocator);
440       allocator = NULL;
441     }
442
443     pool = gst_buffer_pool_new ();
444     config = gst_buffer_pool_get_config (pool);
445     gst_buffer_pool_config_set_allocator (config, allocator, &params);
446     caps = gst_caps_from_string ("video/internal");
447     gst_buffer_pool_config_set_params (config, caps, min_size, 2, 0);
448     gst_caps_unref (caps);
449     gst_buffer_pool_set_config (pool, config);
450
451     if (allocator)
452       gst_object_unref (allocator);
453
454     if (!gst_buffer_pool_set_active (pool, TRUE)) {
455       GST_WARNING ("Failed to create internal pool");
456       gst_object_unref (pool);
457       return -1;
458     }
459
460     dec->pool = pool;
461     dec->buf_size = min_size;
462   }
463
464   ret = gst_buffer_pool_acquire_buffer (dec->pool, &buffer, NULL);
465   if (ret != GST_FLOW_OK) {
466     GST_WARNING ("Failed to acquire buffer from internal pool.");
467     return -1;
468   }
469
470   /* Add it now, while the buffer is writable */
471   gst_buffer_add_video_meta (buffer, GST_VIDEO_FRAME_FLAG_NONE,
472       GST_VIDEO_FORMAT_ENCODED, 0, 0);
473
474   frame = g_new0 (struct Frame, 1);
475   if (!gst_buffer_map (buffer, &frame->info, GST_MAP_READWRITE)) {
476     gst_buffer_unref (buffer);
477     g_free (frame);
478     GST_WARNING ("Failed to map buffer from internal pool.");
479     return -1;
480   }
481
482   fb->size = frame->info.size;
483   fb->data = frame->info.data;
484   frame->buffer = buffer;
485   fb->priv = frame;
486
487   GST_TRACE_OBJECT (priv, "Allocated buffer %p", frame->buffer);
488
489   return 0;
490 }
491
492 static int
493 gst_vpx_dec_release_buffer_cb (gpointer priv, vpx_codec_frame_buffer_t * fb)
494 {
495   struct Frame *frame = fb->priv;
496
497   /* We're sometimes called without a frame */
498   if (!frame)
499     return 0;
500
501   GST_TRACE_OBJECT (priv, "Release buffer %p", frame->buffer);
502
503   gst_buffer_unmap (frame->buffer, &frame->info);
504   gst_buffer_unref (frame->buffer);
505   g_free (frame);
506   fb->priv = NULL;
507
508   return 0;
509 }
510 #endif
511
512 static void
513 gst_vpx_dec_image_to_buffer (GstVPXDec * dec, const vpx_image_t * img,
514     GstBuffer * buffer)
515 {
516   int deststride, srcstride, height, width, line, comp;
517   guint8 *dest, *src;
518   GstVideoFrame frame;
519   GstVideoInfo *info = &dec->output_state->info;
520
521   if (!gst_video_frame_map (&frame, info, buffer, GST_MAP_WRITE)) {
522     GST_ERROR_OBJECT (dec, "Could not map video buffer");
523     return;
524   }
525
526   for (comp = 0; comp < 3; comp++) {
527     dest = GST_VIDEO_FRAME_COMP_DATA (&frame, comp);
528     src = img->planes[comp];
529     width = GST_VIDEO_FRAME_COMP_WIDTH (&frame, comp)
530         * GST_VIDEO_FRAME_COMP_PSTRIDE (&frame, comp);
531     height = GST_VIDEO_FRAME_COMP_HEIGHT (&frame, comp);
532     deststride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, comp);
533     srcstride = img->stride[comp];
534
535     if (srcstride == deststride) {
536       GST_TRACE_OBJECT (dec, "Stride matches. Comp %d: %d, copying full plane",
537           comp, srcstride);
538       memcpy (dest, src, srcstride * height);
539     } else {
540       GST_TRACE_OBJECT (dec, "Stride mismatch. Comp %d: %d != %d, copying "
541           "line by line.", comp, srcstride, deststride);
542       for (line = 0; line < height; line++) {
543         memcpy (dest, src, width);
544         dest += deststride;
545         src += srcstride;
546       }
547     }
548   }
549
550   gst_video_frame_unmap (&frame);
551 }
552
553 static GstFlowReturn
554 gst_vpx_dec_open_codec (GstVPXDec * dec, GstVideoCodecFrame * frame)
555 {
556   int flags = 0;
557   vpx_codec_stream_info_t stream_info;
558   vpx_codec_caps_t caps;
559   vpx_codec_dec_cfg_t cfg;
560   vpx_codec_err_t status;
561   GstMapInfo minfo;
562   GstVPXDecClass *vpxclass = GST_VPX_DEC_GET_CLASS (dec);
563
564   g_return_val_if_fail (vpxclass->codec_algo != NULL, GST_FLOW_ERROR);
565
566   memset (&stream_info, 0, sizeof (stream_info));
567   memset (&cfg, 0, sizeof (cfg));
568   stream_info.sz = sizeof (stream_info);
569
570   if (!gst_buffer_map (frame->input_buffer, &minfo, GST_MAP_READ)) {
571     GST_ERROR_OBJECT (dec, "Failed to map input buffer");
572     return GST_FLOW_ERROR;
573   }
574
575   status = vpx_codec_peek_stream_info (vpxclass->codec_algo,
576       minfo.data, minfo.size, &stream_info);
577
578   gst_buffer_unmap (frame->input_buffer, &minfo);
579
580   if (status != VPX_CODEC_OK) {
581     GST_WARNING_OBJECT (dec, "VPX preprocessing error: %s",
582         gst_vpx_error_name (status));
583     return GST_FLOW_CUSTOM_SUCCESS_1;
584   }
585   if (!stream_info.is_kf) {
586     GST_WARNING_OBJECT (dec, "No keyframe, skipping");
587     return GST_FLOW_CUSTOM_SUCCESS_1;
588   }
589
590   gst_vpx_dec_set_stream_info (dec, &stream_info);
591   gst_vpx_dec_set_default_format (dec, GST_VIDEO_FORMAT_I420, stream_info.w,
592       stream_info.h);
593
594   cfg.w = stream_info.w;
595   cfg.h = stream_info.h;
596
597   if (dec->threads > 0)
598     cfg.threads = dec->threads;
599   else
600     cfg.threads = g_get_num_processors ();
601
602   caps = vpx_codec_get_caps (vpxclass->codec_algo);
603
604   if (dec->post_processing) {
605     if (!(caps & VPX_CODEC_CAP_POSTPROC)) {
606       GST_WARNING_OBJECT (dec, "Decoder does not support post processing");
607     } else {
608       flags |= VPX_CODEC_USE_POSTPROC;
609     }
610   }
611
612   status =
613       vpx_codec_dec_init (&dec->decoder, vpxclass->codec_algo, &cfg, flags);
614   if (status != VPX_CODEC_OK) {
615     GST_ELEMENT_ERROR (dec, LIBRARY, INIT,
616         ("Failed to initialize VP8 decoder"), ("%s",
617             gst_vpx_error_name (status)));
618     return GST_FLOW_ERROR;
619   }
620
621   if ((caps & VPX_CODEC_CAP_POSTPROC) && dec->post_processing) {
622     vp8_postproc_cfg_t pp_cfg = { 0, };
623
624     pp_cfg.post_proc_flag = dec->post_processing_flags;
625     pp_cfg.deblocking_level = dec->deblocking_level;
626     pp_cfg.noise_level = dec->noise_level;
627
628     status = vpx_codec_control (&dec->decoder, VP8_SET_POSTPROC, &pp_cfg);
629     if (status != VPX_CODEC_OK) {
630       GST_WARNING_OBJECT (dec, "Couldn't set postprocessing settings: %s",
631           gst_vpx_error_name (status));
632     }
633   }
634 #ifdef HAVE_VPX_1_4
635   vpx_codec_set_frame_buffer_functions (&dec->decoder,
636       gst_vpx_dec_get_buffer_cb, gst_vpx_dec_release_buffer_cb, dec);
637 #endif
638
639   dec->decoder_inited = TRUE;
640
641   return GST_FLOW_OK;
642 }
643
644 static GstFlowReturn
645 gst_vpx_dec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
646 {
647   GstVPXDec *dec;
648   GstFlowReturn ret = GST_FLOW_OK;
649   vpx_codec_err_t status;
650   vpx_codec_iter_t iter = NULL;
651   vpx_image_t *img;
652   long decoder_deadline = 0;
653   GstClockTimeDiff deadline;
654   GstMapInfo minfo;
655   GstVPXDecClass *vpxclass;
656   GstVideoFormat fmt;
657
658   GST_LOG_OBJECT (decoder, "handle_frame");
659
660   dec = GST_VPX_DEC (decoder);
661   vpxclass = GST_VPX_DEC_GET_CLASS (dec);
662
663   if (!dec->decoder_inited) {
664     ret = vpxclass->open_codec (dec, frame);
665     if (ret == GST_FLOW_CUSTOM_SUCCESS_1) {
666       gst_video_decoder_drop_frame (decoder, frame);
667       return GST_FLOW_OK;
668     } else if (ret != GST_FLOW_OK) {
669       gst_video_codec_frame_unref (frame);
670       return ret;
671     }
672   }
673
674   deadline = gst_video_decoder_get_max_decode_time (decoder, frame);
675   if (deadline < 0) {
676     decoder_deadline = 1;
677   } else if (deadline == G_MAXINT64) {
678     decoder_deadline = 0;
679   } else {
680     decoder_deadline = MAX (1, deadline / GST_MSECOND);
681   }
682
683   if (!gst_buffer_map (frame->input_buffer, &minfo, GST_MAP_READ)) {
684     GST_ERROR_OBJECT (dec, "Failed to map input buffer");
685     gst_video_codec_frame_unref (frame);
686     return GST_FLOW_ERROR;
687   }
688
689   status = vpx_codec_decode (&dec->decoder,
690       minfo.data, minfo.size, NULL, decoder_deadline);
691
692   gst_buffer_unmap (frame->input_buffer, &minfo);
693
694   if (status) {
695     GST_VIDEO_DECODER_ERROR (decoder, 1, LIBRARY, ENCODE,
696         ("Failed to decode frame"), ("%s", gst_vpx_error_name (status)), ret);
697     gst_video_codec_frame_unref (frame);
698     return ret;
699   }
700
701   img = vpx_codec_get_frame (&dec->decoder, &iter);
702   if (img) {
703     if (vpxclass->get_frame_format (dec, img, &fmt) == FALSE) {
704       vpx_img_free (img);
705       GST_ELEMENT_ERROR (decoder, LIBRARY, ENCODE,
706           ("Failed to decode frame"), ("Unsupported color format %d",
707               img->fmt));
708       gst_video_codec_frame_unref (frame);
709       return GST_FLOW_ERROR;
710     }
711
712     if (deadline < 0) {
713       GST_LOG_OBJECT (dec, "Skipping late frame (%f s past deadline)",
714           (double) -deadline / GST_SECOND);
715       gst_video_decoder_drop_frame (decoder, frame);
716     } else {
717       gst_vpx_dec_handle_resolution_change (dec, img, fmt);
718 #ifdef HAVE_VPX_1_4
719       if (img->fb_priv && dec->have_video_meta) {
720         frame->output_buffer = gst_vpx_dec_prepare_image (dec, img);
721         ret = gst_video_decoder_finish_frame (decoder, frame);
722       } else
723 #endif
724       {
725         ret = gst_video_decoder_allocate_output_frame (decoder, frame);
726
727         if (ret == GST_FLOW_OK) {
728           gst_vpx_dec_image_to_buffer (dec, img, frame->output_buffer);
729           ret = gst_video_decoder_finish_frame (decoder, frame);
730         } else {
731           gst_video_decoder_drop_frame (decoder, frame);
732         }
733       }
734     }
735
736     vpx_img_free (img);
737
738     while ((img = vpx_codec_get_frame (&dec->decoder, &iter))) {
739       GST_WARNING_OBJECT (decoder, "Multiple decoded frames... dropping");
740       vpx_img_free (img);
741     }
742   } else {
743     /* Invisible frame */
744     GST_VIDEO_CODEC_FRAME_SET_DECODE_ONLY (frame);
745     gst_video_decoder_finish_frame (decoder, frame);
746   }
747
748   return ret;
749 }
750
751 static gboolean
752 gst_vpx_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query)
753 {
754   GstVPXDec *dec = GST_VPX_DEC (bdec);
755   GstBufferPool *pool;
756   GstStructure *config;
757
758   if (!GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (bdec, query))
759     return FALSE;
760
761   g_assert (gst_query_get_n_allocation_pools (query) > 0);
762   gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL);
763   g_assert (pool != NULL);
764
765   config = gst_buffer_pool_get_config (pool);
766   if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
767     gst_buffer_pool_config_add_option (config,
768         GST_BUFFER_POOL_OPTION_VIDEO_META);
769     dec->have_video_meta = TRUE;
770   }
771   gst_buffer_pool_set_config (pool, config);
772   gst_object_unref (pool);
773
774   return TRUE;
775 }
776
777 static void
778 gst_vpx_dec_set_stream_info (GstVPXDec * dec,
779     vpx_codec_stream_info_t * stream_info)
780 {
781   GstVPXDecClass *vpxclass = GST_VPX_DEC_GET_CLASS (dec);
782   if (vpxclass->set_stream_info != NULL) {
783     vpxclass->set_stream_info (dec, stream_info);
784   }
785 }
786
787 static void
788 gst_vpx_dec_set_default_format (GstVPXDec * dec, GstVideoFormat fmt, int width,
789     int height)
790 {
791   GstVPXDecClass *vpxclass = GST_VPX_DEC_GET_CLASS (dec);
792   if (vpxclass->set_default_format != NULL) {
793     vpxclass->set_default_format (dec, fmt, width, height);
794   }
795 }
796
797 static gboolean
798 gst_vpx_dec_default_frame_format (GstVPXDec * dec, vpx_image_t * img,
799     GstVideoFormat * fmt)
800 {
801   if (img->fmt == VPX_IMG_FMT_I420) {
802     *fmt = GST_VIDEO_FORMAT_I420;
803     return TRUE;
804   } else {
805     return FALSE;
806   }
807
808 }
809
810 static void
811 gst_vpx_dec_handle_resolution_change (GstVPXDec * dec, vpx_image_t * img,
812     GstVideoFormat fmt)
813 {
814   GstVPXDecClass *vpxclass = GST_VPX_DEC_GET_CLASS (dec);
815   if (vpxclass->handle_resolution_change != NULL) {
816     vpxclass->handle_resolution_change (dec, img, fmt);
817   }
818 }
819
820 #endif /* HAVE_VP8_DECODER ||  HAVE_VP9_DECODER */