vavp8dec, vampeg2dec: Fix type name.
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / va / gstvavp8dec.c
1 /* GStreamer
2  *  Copyright (C) 2020 Intel Corporation
3  *     Author: He Junyan <junyan.he@intel.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the0
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 /**
22  * SECTION:element-vavp8dec
23  * @title: vavp8dec
24  * @short_description: A VA-API based VP8 video decoder
25  *
26  * vavp8dec decodes VP8 bitstreams to VA surfaces using the
27  * installed and chosen [VA-API](https://01.org/linuxmedia/vaapi)
28  * driver.
29  *
30  * The decoding surfaces can be mapped onto main memory as video
31  * frames.
32  *
33  * ## Example launch line
34  * ```
35  * gst-launch-1.0 filesrc location=sample.webm ! parsebin ! vavp8dec ! autovideosink
36  * ```
37  *
38  * Since: 1.20
39  *
40  */
41
42 #ifdef HAVE_CONFIG_H
43 #include "config.h"
44 #endif
45
46 #include "gstvavp8dec.h"
47
48 #include "gstvabasedec.h"
49
50 GST_DEBUG_CATEGORY_STATIC (gst_va_vp8dec_debug);
51 #ifndef GST_DISABLE_GST_DEBUG
52 #define GST_CAT_DEFAULT gst_va_vp8dec_debug
53 #else
54 #define GST_CAT_DEFAULT NULL
55 #endif
56
57 #define GST_VA_VP8_DEC(obj)           ((GstVaVp8Dec *) obj)
58 #define GST_VA_VP8_DEC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), G_TYPE_FROM_INSTANCE (obj), GstVaVp8DecClass))
59 #define GST_VA_VP8_DEC_CLASS(klass)   ((GstVaVp8DecClass *) klass)
60
61 typedef struct _GstVaVp8Dec GstVaVp8Dec;
62 typedef struct _GstVaVp8DecClass GstVaVp8DecClass;
63
64 struct _GstVaVp8DecClass
65 {
66   GstVaBaseDecClass parent_class;
67 };
68
69 struct _GstVaVp8Dec
70 {
71   GstVaBaseDec parent;
72
73   GstFlowReturn last_ret;
74 };
75
76 static GstElementClass *parent_class = NULL;
77
78 /* *INDENT-OFF* */
79 static const gchar *src_caps_str =
80     GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_VA,
81         "{ NV12 }") " ;"
82     GST_VIDEO_CAPS_MAKE ("{ NV12 }");
83 /* *INDENT-ON* */
84
85 static const gchar *sink_caps_str = "video/x-vp8";
86
87 static gboolean
88 gst_va_vp8_dec_negotiate (GstVideoDecoder * decoder)
89 {
90   GstCapsFeatures *capsfeatures = NULL;
91   GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
92   GstVaVp8Dec *self = GST_VA_VP8_DEC (decoder);
93   GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
94   GstVp8Decoder *vp8dec = GST_VP8_DECODER (decoder);
95
96   /* Ignore downstream renegotiation request. */
97   if (!base->need_negotiation)
98     return TRUE;
99
100   base->need_negotiation = FALSE;
101
102   if (gst_va_decoder_is_open (base->decoder)
103       && !gst_va_decoder_close (base->decoder))
104     return FALSE;
105
106   if (!gst_va_decoder_open (base->decoder, base->profile, base->rt_format))
107     return FALSE;
108
109   if (!gst_va_decoder_set_frame_size (base->decoder, base->width, base->height))
110     return FALSE;
111
112   if (base->output_state)
113     gst_video_codec_state_unref (base->output_state);
114
115   gst_va_base_dec_get_preferred_format_and_caps_features (base, &format,
116       &capsfeatures);
117   if (format == GST_VIDEO_FORMAT_UNKNOWN)
118     return FALSE;
119
120   base->output_state =
121       gst_video_decoder_set_output_state (decoder, format,
122       base->width, base->height, vp8dec->input_state);
123
124   base->output_state->caps = gst_video_info_to_caps (&base->output_state->info);
125   if (capsfeatures)
126     gst_caps_set_features_simple (base->output_state->caps, capsfeatures);
127
128   GST_INFO_OBJECT (self, "Negotiated caps %" GST_PTR_FORMAT,
129       base->output_state->caps);
130
131   return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder);
132 }
133
134 static VAProfile
135 _get_profile (GstVaVp8Dec * self, const GstVp8FrameHdr * frame_hdr)
136 {
137
138   if (frame_hdr->version > 3) {
139     GST_ERROR_OBJECT (self, "Unsupported vp8 version: %d", frame_hdr->version);
140     return VAProfileNone;
141   }
142
143   return VAProfileVP8Version0_3;
144 }
145
146 static GstFlowReturn
147 gst_va_vp8_dec_new_sequence (GstVp8Decoder * decoder,
148     const GstVp8FrameHdr * frame_hdr, gint max_dpb_size)
149 {
150   GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
151   GstVaVp8Dec *self = GST_VA_VP8_DEC (decoder);
152   VAProfile profile;
153   guint rt_format;
154   gboolean negotiation_needed = FALSE;
155
156   GST_LOG_OBJECT (self, "new sequence");
157
158   profile = _get_profile (self, frame_hdr);
159   if (profile == VAProfileNone)
160     return GST_FLOW_NOT_NEGOTIATED;
161
162   if (!gst_va_decoder_has_profile (base->decoder, profile)) {
163     GST_ERROR_OBJECT (self, "Profile %s is not supported",
164         gst_va_profile_name (profile));
165     return GST_FLOW_NOT_NEGOTIATED;
166   }
167
168   /* VP8 always use 8 bits 4:2:0 */
169   rt_format = VA_RT_FORMAT_YUV420;
170
171   if (!gst_va_decoder_config_is_equal (base->decoder, profile,
172           rt_format, frame_hdr->width, frame_hdr->height)) {
173     base->profile = profile;
174     base->width = frame_hdr->width;
175     base->height = frame_hdr->height;
176     base->rt_format = rt_format;
177     negotiation_needed = TRUE;
178   }
179
180   base->min_buffers = 3 + 4;    /* max num pic references + scratch surfaces */
181
182   base->need_negotiation = negotiation_needed;
183
184   return GST_FLOW_OK;
185 }
186
187 static GstFlowReturn
188 gst_va_vp8_dec_new_picture (GstVp8Decoder * decoder,
189     GstVideoCodecFrame * frame, GstVp8Picture * picture)
190 {
191   GstVaVp8Dec *self = GST_VA_VP8_DEC (decoder);
192   GstVaDecodePicture *pic;
193   GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder);
194   GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
195
196   if (base->need_negotiation) {
197     if (!gst_video_decoder_negotiate (vdec)) {
198       GST_ERROR_OBJECT (self, "Failed to negotiate with downstream");
199       return GST_FLOW_NOT_NEGOTIATED;
200     }
201   }
202
203   self->last_ret = gst_video_decoder_allocate_output_frame (vdec, frame);
204   if (self->last_ret != GST_FLOW_OK)
205     goto error;
206
207   pic = gst_va_decode_picture_new (base->decoder, frame->output_buffer);
208
209   gst_vp8_picture_set_user_data (picture, pic,
210       (GDestroyNotify) gst_va_decode_picture_free);
211
212   GST_LOG_OBJECT (self, "New va decode picture %p - %#x", pic,
213       gst_va_decode_picture_get_surface (pic));
214
215   return GST_FLOW_OK;
216
217 error:
218   {
219     GST_WARNING_OBJECT (self,
220         "Failed to allocated output buffer, return %s",
221         gst_flow_get_name (self->last_ret));
222     return self->last_ret;
223   }
224 }
225
226 static gboolean
227 _fill_quant_matrix (GstVp8Decoder * decoder, GstVp8Picture * picture,
228     GstVp8Parser * parser)
229 {
230   GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
231   GstVp8FrameHdr const *frame_hdr = &picture->frame_hdr;
232   GstVp8Segmentation *const seg = &parser->segmentation;
233   VAIQMatrixBufferVP8 iq_matrix = { };
234   const gint8 QI_MAX = 127;
235   gint16 qi, qi_base;
236   gint i;
237
238   /* Fill in VAIQMatrixBufferVP8 */
239   for (i = 0; i < 4; i++) {
240     if (seg->segmentation_enabled) {
241       qi_base = seg->quantizer_update_value[i];
242       if (!seg->segment_feature_mode)   /* 0 means delta update */
243         qi_base += frame_hdr->quant_indices.y_ac_qi;
244     } else
245       qi_base = frame_hdr->quant_indices.y_ac_qi;
246
247     qi = qi_base;
248     iq_matrix.quantization_index[i][0] = CLAMP (qi, 0, QI_MAX);
249     qi = qi_base + frame_hdr->quant_indices.y_dc_delta;
250     iq_matrix.quantization_index[i][1] = CLAMP (qi, 0, QI_MAX);
251     qi = qi_base + frame_hdr->quant_indices.y2_dc_delta;
252     iq_matrix.quantization_index[i][2] = CLAMP (qi, 0, QI_MAX);
253     qi = qi_base + frame_hdr->quant_indices.y2_ac_delta;
254     iq_matrix.quantization_index[i][3] = CLAMP (qi, 0, QI_MAX);
255     qi = qi_base + frame_hdr->quant_indices.uv_dc_delta;
256     iq_matrix.quantization_index[i][4] = CLAMP (qi, 0, QI_MAX);
257     qi = qi_base + frame_hdr->quant_indices.uv_ac_delta;
258     iq_matrix.quantization_index[i][5] = CLAMP (qi, 0, QI_MAX);
259   }
260
261   return gst_va_decoder_add_param_buffer (base->decoder,
262       gst_vp8_picture_get_user_data (picture), VAIQMatrixBufferType, &iq_matrix,
263       sizeof (iq_matrix));
264 }
265
266 static gboolean
267 _fill_probability_table (GstVp8Decoder * decoder, GstVp8Picture * picture)
268 {
269   GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
270   GstVp8FrameHdr const *frame_hdr = &picture->frame_hdr;
271   VAProbabilityDataBufferVP8 prob_table = { };
272
273   /* Fill in VAProbabilityDataBufferVP8 */
274   memcpy (prob_table.dct_coeff_probs, frame_hdr->token_probs.prob,
275       sizeof (frame_hdr->token_probs.prob));
276
277   return gst_va_decoder_add_param_buffer (base->decoder,
278       gst_vp8_picture_get_user_data (picture), VAProbabilityBufferType,
279       &prob_table, sizeof (prob_table));
280 }
281
282 static gboolean
283 _fill_picture (GstVp8Decoder * decoder, GstVp8Picture * picture,
284     GstVp8Parser * parser)
285 {
286   GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
287   GstVaDecodePicture *va_pic;
288   VAPictureParameterBufferVP8 pic_param;
289   GstVp8FrameHdr const *frame_hdr = &picture->frame_hdr;
290   GstVp8Segmentation *const seg = &parser->segmentation;
291   guint i;
292
293   if (!_fill_quant_matrix (decoder, picture, parser))
294     return FALSE;
295
296   if (!_fill_probability_table (decoder, picture))
297     return FALSE;
298
299   /* *INDENT-OFF* */
300   pic_param = (VAPictureParameterBufferVP8) {
301     .frame_width = base->width,
302     .frame_height = base->height,
303     .last_ref_frame = VA_INVALID_SURFACE,
304     .golden_ref_frame = VA_INVALID_SURFACE,
305     .alt_ref_frame = VA_INVALID_SURFACE,
306     .out_of_loop_frame = VA_INVALID_SURFACE, // not used currently
307     .pic_fields.bits.key_frame = !frame_hdr->key_frame,
308     .pic_fields.bits.version = frame_hdr->version,
309     .pic_fields.bits.segmentation_enabled = seg->segmentation_enabled,
310     .pic_fields.bits.update_mb_segmentation_map =
311         seg->update_mb_segmentation_map,
312     .pic_fields.bits.update_segment_feature_data =
313         seg->update_segment_feature_data,
314     .pic_fields.bits.filter_type = frame_hdr->filter_type,
315     .pic_fields.bits.sharpness_level = frame_hdr->sharpness_level,
316     .pic_fields.bits.loop_filter_adj_enable =
317         parser->mb_lf_adjust.loop_filter_adj_enable,
318     .pic_fields.bits.mode_ref_lf_delta_update =
319         parser->mb_lf_adjust.mode_ref_lf_delta_update,
320     .pic_fields.bits.sign_bias_golden = frame_hdr->sign_bias_golden,
321     .pic_fields.bits.sign_bias_alternate = frame_hdr->sign_bias_alternate,
322     .pic_fields.bits.mb_no_coeff_skip = frame_hdr->mb_no_skip_coeff,
323     /* In decoding, the only loop filter settings that matter are those
324        in the frame header (9.1) */
325     .pic_fields.bits.loop_filter_disable = frame_hdr->loop_filter_level == 0,
326     .prob_skip_false = frame_hdr->prob_skip_false,
327     .prob_intra = frame_hdr->prob_intra,
328     .prob_last = frame_hdr->prob_last,
329     .prob_gf = frame_hdr->prob_gf,
330     .bool_coder_ctx.range = frame_hdr->rd_range,
331     .bool_coder_ctx.value = frame_hdr->rd_value,
332     .bool_coder_ctx.count = frame_hdr->rd_count,
333   };
334   /* *INDENT-ON* */
335
336   if (!frame_hdr->key_frame) {
337     if (decoder->last_picture) {
338       va_pic = gst_vp8_picture_get_user_data (decoder->last_picture);
339       pic_param.last_ref_frame = gst_va_decode_picture_get_surface (va_pic);
340     }
341     if (decoder->golden_ref_picture) {
342       va_pic = gst_vp8_picture_get_user_data (decoder->golden_ref_picture);
343       pic_param.golden_ref_frame = gst_va_decode_picture_get_surface (va_pic);
344     }
345     if (decoder->alt_ref_picture) {
346       va_pic = gst_vp8_picture_get_user_data (decoder->alt_ref_picture);
347       pic_param.alt_ref_frame = gst_va_decode_picture_get_surface (va_pic);
348     }
349   }
350
351   for (i = 0; i < 3; i++)
352     pic_param.mb_segment_tree_probs[i] = seg->segment_prob[i];
353
354   for (i = 0; i < 4; i++) {
355     gint8 level;
356     if (seg->segmentation_enabled) {
357       level = seg->lf_update_value[i];
358       /* 0 means delta update */
359       if (!seg->segment_feature_mode)
360         level += frame_hdr->loop_filter_level;
361     } else
362       level = frame_hdr->loop_filter_level;
363     pic_param.loop_filter_level[i] = CLAMP (level, 0, 63);
364
365     pic_param.loop_filter_deltas_ref_frame[i] =
366         parser->mb_lf_adjust.ref_frame_delta[i];
367     pic_param.loop_filter_deltas_mode[i] =
368         parser->mb_lf_adjust.mb_mode_delta[i];
369   }
370
371   memcpy (pic_param.y_mode_probs, frame_hdr->mode_probs.y_prob,
372       sizeof (frame_hdr->mode_probs.y_prob));
373   memcpy (pic_param.uv_mode_probs, frame_hdr->mode_probs.uv_prob,
374       sizeof (frame_hdr->mode_probs.uv_prob));
375   memcpy (pic_param.mv_probs, frame_hdr->mv_probs.prob,
376       sizeof (frame_hdr->mv_probs));
377
378   va_pic = gst_vp8_picture_get_user_data (picture);
379   return gst_va_decoder_add_param_buffer (base->decoder, va_pic,
380       VAPictureParameterBufferType, &pic_param, sizeof (pic_param));
381 }
382
383 static gboolean
384 _add_slice (GstVp8Decoder * decoder, GstVp8Picture * picture,
385     GstVp8Parser * parser)
386 {
387   GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
388   GstVp8FrameHdr const *frame_hdr = &picture->frame_hdr;
389   VASliceParameterBufferVP8 slice_param;
390   GstVaDecodePicture *va_pic;
391   gint i;
392
393   /* *INDENT-OFF* */
394   slice_param = (VASliceParameterBufferVP8) {
395     .slice_data_size = picture->size,
396     .slice_data_offset = frame_hdr->data_chunk_size,
397     .macroblock_offset = frame_hdr->header_size,
398     .num_of_partitions = (1 << frame_hdr->log2_nbr_of_dct_partitions) + 1,
399   };
400   /* *INDENT-ON* */
401
402   slice_param.partition_size[0] =
403       frame_hdr->first_part_size - ((slice_param.macroblock_offset + 7) >> 3);
404   for (i = 1; i < slice_param.num_of_partitions; i++)
405     slice_param.partition_size[i] = frame_hdr->partition_size[i - 1];
406   for (; i < G_N_ELEMENTS (slice_param.partition_size); i++)
407     slice_param.partition_size[i] = 0;
408
409   va_pic = gst_vp8_picture_get_user_data (picture);
410   return gst_va_decoder_add_slice_buffer (base->decoder, va_pic, &slice_param,
411       sizeof (slice_param), (gpointer) picture->data, picture->size);
412 }
413
414 static gboolean
415 gst_va_vp8_dec_decode_picture (GstVp8Decoder * decoder, GstVp8Picture * picture,
416     GstVp8Parser * parser)
417 {
418   if (_fill_picture (decoder, picture, parser) &&
419       _add_slice (decoder, picture, parser))
420     return GST_FLOW_OK;
421
422   return GST_FLOW_ERROR;
423 }
424
425 static GstFlowReturn
426 gst_va_vp8_dec_end_picture (GstVp8Decoder * decoder, GstVp8Picture * picture)
427 {
428   GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
429   GstVaDecodePicture *va_pic;
430
431   GST_LOG_OBJECT (base, "end picture %p, (system_frame_number %d)",
432       picture, picture->system_frame_number);
433
434   va_pic = gst_vp8_picture_get_user_data (picture);
435
436   if (!gst_va_decoder_decode (base->decoder, va_pic))
437     return GST_FLOW_ERROR;
438
439   return GST_FLOW_OK;
440 }
441
442 static GstFlowReturn
443 gst_va_vp8_dec_output_picture (GstVp8Decoder * decoder,
444     GstVideoCodecFrame * frame, GstVp8Picture * picture)
445 {
446   GstVaBaseDec *base = GST_VA_BASE_DEC (decoder);
447   GstVaVp8Dec *self = GST_VA_VP8_DEC (decoder);
448
449   GST_LOG_OBJECT (self,
450       "Outputting picture %p (system_frame_number %d)",
451       picture, picture->system_frame_number);
452
453   if (self->last_ret != GST_FLOW_OK) {
454     gst_vp8_picture_unref (picture);
455     gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
456     return self->last_ret;
457   }
458
459   if (base->copy_frames)
460     gst_va_base_dec_copy_output_buffer (base, frame);
461
462   gst_vp8_picture_unref (picture);
463
464   return gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
465 }
466
467 static void
468 gst_va_vp8_dec_init (GTypeInstance * instance, gpointer g_class)
469 {
470   gst_va_base_dec_init (GST_VA_BASE_DEC (instance), GST_CAT_DEFAULT);
471 }
472
473 static void
474 gst_va_vp8_dec_dispose (GObject * object)
475 {
476   gst_va_base_dec_close (GST_VIDEO_DECODER (object));
477   G_OBJECT_CLASS (parent_class)->dispose (object);
478 }
479
480 static void
481 gst_va_vp8_dec_class_init (gpointer g_class, gpointer class_data)
482 {
483   GstCaps *src_doc_caps, *sink_doc_caps;
484   GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
485   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
486   GstVp8DecoderClass *vp8decoder_class = GST_VP8_DECODER_CLASS (g_class);
487   GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (g_class);
488   struct CData *cdata = class_data;
489   gchar *long_name;
490
491   if (cdata->description) {
492     long_name = g_strdup_printf ("VA-API VP8 Decoder in %s",
493         cdata->description);
494   } else {
495     long_name = g_strdup ("VA-API VP8 Decoder");
496   }
497
498   gst_element_class_set_metadata (element_class, long_name,
499       "Codec/Decoder/Video/Hardware",
500       "VA-API based VP8 video decoder", "He Junyan <junyan.he@intel.com>");
501
502   sink_doc_caps = gst_caps_from_string (sink_caps_str);
503   src_doc_caps = gst_caps_from_string (src_caps_str);
504
505   parent_class = g_type_class_peek_parent (g_class);
506
507   gst_va_base_dec_class_init (GST_VA_BASE_DEC_CLASS (g_class), VP8,
508       cdata->render_device_path, cdata->sink_caps, cdata->src_caps,
509       src_doc_caps, sink_doc_caps);
510
511   gobject_class->dispose = gst_va_vp8_dec_dispose;
512
513   decoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_va_vp8_dec_negotiate);
514
515   vp8decoder_class->new_sequence =
516       GST_DEBUG_FUNCPTR (gst_va_vp8_dec_new_sequence);
517   vp8decoder_class->new_picture =
518       GST_DEBUG_FUNCPTR (gst_va_vp8_dec_new_picture);
519   vp8decoder_class->decode_picture =
520       GST_DEBUG_FUNCPTR (gst_va_vp8_dec_decode_picture);
521   vp8decoder_class->end_picture =
522       GST_DEBUG_FUNCPTR (gst_va_vp8_dec_end_picture);
523   vp8decoder_class->output_picture =
524       GST_DEBUG_FUNCPTR (gst_va_vp8_dec_output_picture);
525
526   g_free (long_name);
527   g_free (cdata->description);
528   g_free (cdata->render_device_path);
529   gst_caps_unref (cdata->src_caps);
530   gst_caps_unref (cdata->sink_caps);
531   g_free (cdata);
532 }
533
534 static gpointer
535 _register_debug_category (gpointer data)
536 {
537   GST_DEBUG_CATEGORY_INIT (gst_va_vp8dec_debug, "vavp8dec", 0,
538       "VA VP8 decoder");
539
540   return NULL;
541 }
542
543 gboolean
544 gst_va_vp8_dec_register (GstPlugin * plugin, GstVaDevice * device,
545     GstCaps * sink_caps, GstCaps * src_caps, guint rank)
546 {
547   static GOnce debug_once = G_ONCE_INIT;
548   GType type;
549   GTypeInfo type_info = {
550     .class_size = sizeof (GstVaVp8DecClass),
551     .class_init = gst_va_vp8_dec_class_init,
552     .instance_size = sizeof (GstVaVp8Dec),
553     .instance_init = gst_va_vp8_dec_init,
554   };
555   struct CData *cdata;
556   gboolean ret;
557   gchar *type_name, *feature_name;
558
559   g_return_val_if_fail (GST_IS_PLUGIN (plugin), FALSE);
560   g_return_val_if_fail (GST_IS_VA_DEVICE (device), FALSE);
561   g_return_val_if_fail (GST_IS_CAPS (sink_caps), FALSE);
562   g_return_val_if_fail (GST_IS_CAPS (src_caps), FALSE);
563
564   cdata = g_new (struct CData, 1);
565   cdata->description = NULL;
566   cdata->render_device_path = g_strdup (device->render_device_path);
567   cdata->sink_caps = gst_caps_ref (sink_caps);
568   cdata->src_caps = gst_caps_ref (src_caps);
569
570   /* class data will be leaked if the element never gets instantiated */
571   GST_MINI_OBJECT_FLAG_SET (cdata->sink_caps,
572       GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
573   GST_MINI_OBJECT_FLAG_SET (src_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
574
575   type_info.class_data = cdata;
576
577   type_name = g_strdup ("GstVaVp8Dec");
578   feature_name = g_strdup ("vavp8dec");
579
580   /* The first decoder to be registered should use a constant name,
581    * like vavp8dec, for any additional decoders, we create unique
582    * names, using inserting the render device name. */
583   if (g_type_from_name (type_name)) {
584     gchar *basename = g_path_get_basename (device->render_device_path);
585     g_free (type_name);
586     g_free (feature_name);
587     type_name = g_strdup_printf ("GstVa%sVp8Dec", basename);
588     feature_name = g_strdup_printf ("va%svp8dec", basename);
589     cdata->description = basename;
590
591     /* lower rank for non-first device */
592     if (rank > 0)
593       rank--;
594   }
595
596   g_once (&debug_once, _register_debug_category, NULL);
597
598   type = g_type_register_static (GST_TYPE_VP8_DECODER,
599       type_name, &type_info, 0);
600
601   ret = gst_element_register (plugin, feature_name, rank, type);
602
603   g_free (type_name);
604   g_free (feature_name);
605
606   return ret;
607 }