vaapi: plugin: Handle when no encoders/decoders available.
[platform/upstream/gstreamer.git] / subprojects / gstreamer-vaapi / gst / vaapi / gstvaapidecode.c
1 /*
2  *  gstvaapidecode.c - VA-API video decoder
3  *
4  *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5  *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
6  *  Copyright (C) 2011-2014 Intel Corporation
7  *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
8  *
9  *  This library is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU Lesser General Public License
11  *  as published by the Free Software Foundation; either version 2.1
12  *  of the License, or (at your option) any later version.
13  *
14  *  This library is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  Lesser General Public License for more details.
18  *
19  *  You should have received a copy of the GNU Lesser General Public
20  *  License along with this library; if not, write to the Free
21  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  *  Boston, MA 02110-1301 USA
23  */
24
25 #include "gstcompat.h"
26 #include <gst/vaapi/gstvaapidisplay.h>
27 #include <gst/vaapi/gstvaapiprofilecaps.h>
28
29 #include "gstvaapidecode.h"
30 #include "gstvaapidecode_props.h"
31 #include "gstvaapipluginutil.h"
32 #include "gstvaapivideobuffer.h"
33 #if (USE_GLX || USE_EGL)
34 #include "gstvaapivideometa_texture.h"
35 #endif
36 #include "gstvaapivideobufferpool.h"
37 #include "gstvaapivideomemory.h"
38
39 #include <gst/vaapi/gstvaapidecoder_h264.h>
40 #include <gst/vaapi/gstvaapidecoder_jpeg.h>
41 #include <gst/vaapi/gstvaapidecoder_mpeg2.h>
42 #include <gst/vaapi/gstvaapidecoder_mpeg4.h>
43 #include <gst/vaapi/gstvaapidecoder_vc1.h>
44 #include <gst/vaapi/gstvaapidecoder_vp8.h>
45 #include <gst/vaapi/gstvaapidecoder_h265.h>
46 #include <gst/vaapi/gstvaapidecoder_vp9.h>
47 #if USE_AV1_DECODER
48 #include <gst/vaapi/gstvaapidecoder_av1.h>
49 #endif
50
51 #define GST_PLUGIN_NAME "vaapidecode"
52 #define GST_PLUGIN_DESC "A VA-API based video decoder"
53
54 #define GST_VAAPI_DECODE_FLOW_PARSE_DATA        GST_FLOW_CUSTOM_SUCCESS_2
55
56 GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapidecode);
57 #ifndef GST_DISABLE_GST_DEBUG
58 #define GST_CAT_DEFAULT gst_debug_vaapidecode
59 #else
60 #define GST_CAT_DEFAULT NULL
61 #endif
62
63 #define GST_VAAPI_DECODE_PARAMS_QDATA \
64   g_quark_from_static_string("vaapidec-params")
65
66 /* Default templates */
67 #define GST_CAPS_CODEC(CODEC) CODEC "; "
68
69 /* *INDENT-OFF* */
70 char *gst_vaapidecode_sink_caps_str = NULL;
71
72 static const char gst_vaapidecode_src_caps_str[] =
73     GST_VAAPI_MAKE_SURFACE_CAPS "; "
74     GST_VIDEO_CAPS_MAKE_WITH_FEATURES(GST_CAPS_FEATURE_MEMORY_DMABUF, GST_VAAPI_FORMATS_ALL) " ;"
75 #if (USE_GLX || USE_EGL)
76     GST_VAAPI_MAKE_GLTEXUPLOAD_CAPS "; "
77 #endif
78     GST_VIDEO_CAPS_MAKE(GST_VAAPI_FORMATS_ALL);
79
80 static GstStaticPadTemplate gst_vaapidecode_src_factory =
81     GST_STATIC_PAD_TEMPLATE(
82         "src",
83         GST_PAD_SRC,
84         GST_PAD_ALWAYS,
85         GST_STATIC_CAPS(gst_vaapidecode_src_caps_str));
86 /* *INDENT-ON* */
87
88 typedef struct _GstVaapiDecoderMap GstVaapiDecoderMap;
89 struct _GstVaapiDecoderMap
90 {
91   guint codec;
92   guint rank;
93   const gchar *name;
94   const gchar *caps_str;
95
96   void (*install_properties) (GObjectClass * klass);
97 };
98
99 static const GstVaapiDecoderMap vaapi_decode_map[] = {
100   {GST_VAAPI_CODEC_JPEG, GST_RANK_MARGINAL, "jpeg", "image/jpeg", NULL},
101   {GST_VAAPI_CODEC_MPEG2, GST_RANK_PRIMARY, "mpeg2",
102       "video/mpeg, mpegversion=2, systemstream=(boolean)false", NULL},
103   {GST_VAAPI_CODEC_MPEG4, GST_RANK_PRIMARY, "mpeg4",
104       "video/mpeg, mpegversion=4", NULL},
105   {GST_VAAPI_CODEC_H263, GST_RANK_PRIMARY, "h263", "video/x-h263", NULL},
106   {GST_VAAPI_CODEC_H264, GST_RANK_PRIMARY, "h264", "video/x-h264",
107       gst_vaapi_decode_h264_install_properties},
108   {GST_VAAPI_CODEC_VC1, GST_RANK_PRIMARY, "vc1",
109       "video/x-wmv, wmvversion=3, format={WMV3,WVC1}", NULL},
110   {GST_VAAPI_CODEC_VP8, GST_RANK_PRIMARY, "vp8", "video/x-vp8", NULL},
111   {GST_VAAPI_CODEC_VP9, GST_RANK_PRIMARY, "vp9", "video/x-vp9", NULL},
112   {GST_VAAPI_CODEC_H265, GST_RANK_PRIMARY, "h265", "video/x-h265", NULL},
113   {GST_VAAPI_CODEC_AV1, GST_RANK_PRIMARY, "av1", "video/x-av1", NULL},
114   {0 /* the rest */ , GST_RANK_PRIMARY + 1, NULL, NULL, NULL},
115 };
116
117 static GstElementClass *parent_class = NULL;
118 GST_VAAPI_PLUGIN_BASE_DEFINE_SET_CONTEXT (parent_class);
119
120 static gboolean gst_vaapidecode_update_sink_caps (GstVaapiDecode * decode,
121     GstCaps * caps);
122 static gboolean gst_vaapi_decode_input_state_replace (GstVaapiDecode * decode,
123     const GstVideoCodecState * new_state);
124
125 /* invoked if actual VASurface size (not the cropped values)
126  * changed */
127 static void
128 gst_vaapi_decoder_state_changed (GstVaapiDecoder * decoder,
129     const GstVideoCodecState * codec_state, gpointer user_data)
130 {
131   GstVaapiDecode *const decode = GST_VAAPIDECODE (user_data);
132
133   g_assert (decode->decoder == decoder);
134
135   if (!gst_vaapi_decode_input_state_replace (decode, codec_state))
136     return;
137   if (!gst_vaapidecode_update_sink_caps (decode, decode->input_state->caps))
138     return;
139 }
140
141 static GstVideoCodecState *
142 copy_video_codec_state (const GstVideoCodecState * in_state)
143 {
144   GstVideoCodecState *state;
145
146   g_return_val_if_fail (in_state != NULL, NULL);
147
148   state = g_slice_new0 (GstVideoCodecState);
149   state->ref_count = 1;
150   state->info = in_state->info;
151   state->caps = gst_caps_copy (in_state->caps);
152   if (in_state->codec_data)
153     state->codec_data = gst_buffer_copy_deep (in_state->codec_data);
154
155   return state;
156 }
157
158 static gboolean
159 gst_vaapi_decode_input_state_replace (GstVaapiDecode * decode,
160     const GstVideoCodecState * new_state)
161 {
162   if (decode->input_state) {
163     if (new_state) {
164       const GstCaps *curcaps = decode->input_state->caps;
165       /* If existing caps are equal of the new state, keep the
166        * existing state without renegotiating. */
167       if (gst_caps_is_strictly_equal (curcaps, new_state->caps)) {
168         GST_DEBUG ("Ignoring new caps %" GST_PTR_FORMAT
169             " since are equal to current ones", new_state->caps);
170         return FALSE;
171       }
172     }
173     gst_video_codec_state_unref (decode->input_state);
174   }
175
176   if (new_state)
177     decode->input_state = copy_video_codec_state (new_state);
178   else
179     decode->input_state = NULL;
180
181   return TRUE;
182 }
183
184 static inline gboolean
185 gst_vaapidecode_update_sink_caps (GstVaapiDecode * decode, GstCaps * caps)
186 {
187   GST_INFO_OBJECT (decode, "new sink caps = %" GST_PTR_FORMAT, caps);
188   gst_caps_replace (&decode->sinkpad_caps, caps);
189   return TRUE;
190 }
191
192 static gboolean
193 gst_vaapidecode_ensure_allowed_srcpad_caps (GstVaapiDecode * decode)
194 {
195   GstVaapiDisplay *const display = GST_VAAPI_PLUGIN_BASE_DISPLAY (decode);
196   GstCaps *out_caps, *raw_caps, *va_caps, *dma_caps, *gltexup_caps, *base_caps;
197   GArray *formats;
198   gint min_width, min_height, max_width, max_height;
199   guint mem_types;
200   gboolean ret = FALSE;
201
202   if (decode->allowed_srcpad_caps)
203     return TRUE;
204
205   if (!display)
206     return FALSE;
207
208   if (!decode->decoder)
209     return FALSE;
210
211   dma_caps = gltexup_caps = NULL;
212
213   formats = gst_vaapi_decoder_get_surface_attributes (decode->decoder,
214       &min_width, &min_height, &max_width, &max_height, &mem_types);
215   if (!formats)
216     return FALSE;
217
218   base_caps = gst_vaapi_video_format_new_template_caps_from_list (formats);
219   if (!base_caps)
220     goto bail;
221   gst_vaapi_caps_set_width_and_height_range (base_caps, min_width, min_height,
222       max_width, max_height);
223
224   {
225     GArray *img_formats = gst_vaapi_display_get_image_formats (display);
226     GstVideoFormat decoded_format =
227         GST_VIDEO_INFO_FORMAT (&decode->decoded_info);
228
229     if (!img_formats)
230       img_formats = g_array_ref (formats);
231
232     if (decoded_format != GST_VIDEO_FORMAT_UNKNOWN) {
233       guint decoded_chroma =
234           gst_vaapi_video_format_get_chroma_type (decoded_format);
235       GArray *new_img_formats =
236           g_array_new (FALSE, FALSE, sizeof (GstVideoFormat));
237       gint i;
238
239       for (i = 0; i < img_formats->len; i++) {
240         const GstVideoFormat fmt =
241             g_array_index (img_formats, GstVideoFormat, i);
242         if (gst_vaapi_video_format_get_chroma_type (fmt) == decoded_chroma)
243           g_array_append_val (new_img_formats, fmt);
244       }
245
246       if (new_img_formats->len == 0) {
247         g_clear_pointer (&new_img_formats, g_array_unref);
248       } else {
249         g_clear_pointer (&img_formats, g_array_unref);
250         img_formats = new_img_formats;
251       }
252     }
253
254     raw_caps = gst_vaapi_video_format_new_template_caps_from_list (img_formats);
255     gst_vaapi_caps_set_width_and_height_range (raw_caps, min_width, min_height,
256         max_width, max_height);
257     g_array_unref (img_formats);
258   }
259
260   va_caps = gst_caps_copy (base_caps);
261   gst_caps_set_features_simple (va_caps,
262       gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE));
263
264   if (gst_vaapi_mem_type_supports (mem_types,
265           GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF) ||
266       gst_vaapi_mem_type_supports (mem_types,
267           GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF2)) {
268     dma_caps = gst_caps_copy (base_caps);
269     gst_caps_set_features_simple (dma_caps,
270         gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_DMABUF));
271   }
272 #if (USE_GLX || USE_EGL)
273   if (!GST_VAAPI_PLUGIN_BASE_SRC_PAD_CAN_DMABUF (decode)
274       && gst_vaapi_display_has_opengl (GST_VAAPI_PLUGIN_BASE_DISPLAY (decode))) {
275     gltexup_caps = gst_caps_from_string (GST_VAAPI_MAKE_GLTEXUPLOAD_CAPS);
276     if (gltexup_caps) {
277       gst_vaapi_caps_set_width_and_height_range (base_caps, min_width,
278           min_height, max_width, max_height);
279     }
280   }
281 #endif
282
283   out_caps = va_caps;
284   if (dma_caps)
285     gst_caps_append (out_caps, dma_caps);
286   if (gltexup_caps)
287     gst_caps_append (out_caps, gltexup_caps);
288   gst_caps_append (out_caps, raw_caps);
289   decode->allowed_srcpad_caps = out_caps;
290
291   GST_INFO_OBJECT (decode, "allowed srcpad caps: %" GST_PTR_FORMAT,
292       decode->allowed_srcpad_caps);
293
294   ret = TRUE;
295
296 bail:
297   if (formats)
298     g_array_unref (formats);
299   if (base_caps)
300     gst_caps_unref (base_caps);
301   return ret;
302 }
303
304 static GstCaps *
305 gst_vaapidecode_get_allowed_srcpad_caps (GstVaapiDecode * decode)
306 {
307   GstPad *const srcpad = GST_VIDEO_DECODER_SRC_PAD (decode);
308
309   if (gst_vaapidecode_ensure_allowed_srcpad_caps (decode))
310     return gst_caps_ref (decode->allowed_srcpad_caps);
311   return gst_pad_get_pad_template_caps (srcpad);
312 }
313
314 static gboolean
315 gst_vaapidecode_update_src_caps (GstVaapiDecode * decode)
316 {
317   GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode);
318   GstPad *const srcpad = GST_VIDEO_DECODER_SRC_PAD (vdec);
319   GstCaps *allowed;
320   GstVideoCodecState *state, *ref_state;
321   GstVaapiCapsFeature feature;
322   GstCapsFeatures *features;
323   GstCaps *allocation_caps;
324   GstVideoInfo *vi;
325   GstVideoFormat format;
326   GstClockTime latency;
327   gint fps_d, fps_n;
328   guint width, height;
329   const gchar *format_str, *feature_str;
330
331   if (!decode->input_state)
332     return FALSE;
333
334   ref_state = decode->input_state;
335
336   format = GST_VIDEO_INFO_FORMAT (&decode->decoded_info);
337   allowed = gst_vaapidecode_get_allowed_srcpad_caps (decode);
338   feature = gst_vaapi_find_preferred_caps_feature (srcpad, allowed, &format);
339   gst_caps_unref (allowed);
340
341   if (feature == GST_VAAPI_CAPS_FEATURE_NOT_NEGOTIATED)
342     return FALSE;
343
344 #if (!USE_GLX && !USE_EGL)
345   /* This is a very pathological situation. Should not happen. */
346   if (feature == GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META)
347     return FALSE;
348 #endif
349
350   if ((feature == GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY ||
351           feature == GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE)
352       && format != GST_VIDEO_INFO_FORMAT (&decode->decoded_info)) {
353     GST_FIXME_OBJECT (decode, "validate if driver can convert from %s to %s",
354         gst_video_format_to_string (GST_VIDEO_INFO_FORMAT
355             (&decode->decoded_info)), gst_video_format_to_string (format));
356   }
357
358   width = decode->display_width;
359   height = decode->display_height;
360
361   if (!width || !height) {
362     width = GST_VIDEO_INFO_WIDTH (&ref_state->info);
363     height = GST_VIDEO_INFO_HEIGHT (&ref_state->info);
364   }
365
366   state = gst_video_decoder_set_output_state (vdec, format, width, height,
367       ref_state);
368   if (!state)
369     return FALSE;
370
371   if (GST_VIDEO_INFO_WIDTH (&state->info) == 0
372       || GST_VIDEO_INFO_HEIGHT (&state->info) == 0) {
373     gst_video_codec_state_unref (state);
374     return FALSE;
375   }
376
377   vi = &state->info;
378   state->caps = gst_video_info_to_caps (vi);
379
380   switch (feature) {
381     case GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META:
382     case GST_VAAPI_CAPS_FEATURE_DMABUF:
383     case GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE:{
384       GstStructure *structure = gst_caps_get_structure (state->caps, 0);
385       if (!structure)
386         break;
387       feature_str = gst_vaapi_caps_feature_to_string (feature);
388       features = gst_caps_features_new (feature_str, NULL);
389       gst_caps_set_features (state->caps, 0, features);
390       break;
391     }
392     default:
393       break;
394   }
395
396   /* Allocation query is different from pad's caps */
397   allocation_caps = NULL;
398   if (GST_VIDEO_INFO_WIDTH (&decode->decoded_info) != width
399       || GST_VIDEO_INFO_HEIGHT (&decode->decoded_info) != height) {
400     allocation_caps = gst_caps_copy (state->caps);
401     format_str = gst_video_format_to_string (format);
402     gst_caps_set_simple (allocation_caps,
403         "width", G_TYPE_INT, GST_VIDEO_INFO_WIDTH (&decode->decoded_info),
404         "height", G_TYPE_INT, GST_VIDEO_INFO_HEIGHT (&decode->decoded_info),
405         "format", G_TYPE_STRING, format_str, NULL);
406     GST_INFO_OBJECT (decode, "new alloc caps = %" GST_PTR_FORMAT,
407         allocation_caps);
408   }
409   gst_caps_replace (&state->allocation_caps, allocation_caps);
410   if (allocation_caps)
411     gst_caps_unref (allocation_caps);
412
413   GST_INFO_OBJECT (decode, "new src caps = %" GST_PTR_FORMAT, state->caps);
414   gst_caps_replace (&decode->srcpad_caps, state->caps);
415   gst_video_codec_state_unref (state);
416
417   fps_n = GST_VIDEO_INFO_FPS_N (vi);
418   fps_d = GST_VIDEO_INFO_FPS_D (vi);
419   if (fps_n <= 0 || fps_d <= 0) {
420     GST_DEBUG_OBJECT (decode, "forcing 25/1 framerate for latency calculation");
421     fps_n = 25;
422     fps_d = 1;
423   }
424
425   /* For parsing/preparation purposes we'd need at least 1 frame
426    * latency in general, with perfectly known unit boundaries (NALU,
427    * AU), and up to 2 frames when we need to wait for the second frame
428    * start to determine the first frame is complete */
429   latency = gst_util_uint64_scale (2 * GST_SECOND, fps_d, fps_n);
430   gst_video_decoder_set_latency (vdec, latency, latency);
431
432   return TRUE;
433 }
434
435 /* check whether the decoded surface size has changed */
436 static gboolean
437 is_surface_resolution_changed (GstVaapiDecode * decode,
438     GstVaapiSurface * surface)
439 {
440   GstVideoInfo *vinfo = &decode->decoded_info;
441   GstVideoFormat surface_format;
442   guint surface_width, surface_height;
443
444   g_return_val_if_fail (surface != NULL, FALSE);
445
446   gst_vaapi_surface_get_size (surface, &surface_width, &surface_height);
447
448   if (GST_VIDEO_INFO_WIDTH (vinfo) == surface_width
449       && GST_VIDEO_INFO_HEIGHT (vinfo) == surface_height)
450     return FALSE;
451
452   /* doing gst_vaapi_surface_get_format() only if necessary since it
453    * execute vaDeriveImage in the background. This will usually get
454    * executed only once */
455   surface_format = GST_VIDEO_INFO_FORMAT (vinfo);
456   if (surface_format == GST_VIDEO_FORMAT_UNKNOWN) {
457     surface_format = gst_vaapi_surface_get_format (surface);
458
459     /* if the VA context delivers a currently unrecognized format
460      * (ICM3, e.g.), we can assume one according surface chroma
461      * type. If fail, then use NV12 "safely" */
462     if (surface_format == GST_VIDEO_FORMAT_UNKNOWN
463         || surface_format == GST_VIDEO_FORMAT_ENCODED)
464       surface_format =
465           gst_vaapi_video_format_from_chroma (gst_vaapi_surface_get_chroma_type
466           (surface));
467     if (surface_format == GST_VIDEO_FORMAT_UNKNOWN)
468       surface_format = GST_VIDEO_FORMAT_NV12;
469   }
470
471   /* reset allowed source caps since they are dependant of the decoded
472    * surface format */
473   gst_caps_replace (&decode->allowed_srcpad_caps, NULL);
474
475   gst_video_info_set_format (vinfo, surface_format, surface_width,
476       surface_height);
477
478   return TRUE;
479 }
480
481 /* check whether display resolution changed */
482 static gboolean
483 is_display_resolution_changed (GstVaapiDecode * decode,
484     const GstVaapiRectangle * crop_rect)
485 {
486   GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode);
487   GstVideoCodecState *state;
488   guint display_width, display_height;
489   guint negotiated_width, negotiated_height;
490
491   display_width = GST_VIDEO_INFO_WIDTH (&decode->decoded_info);
492   display_height = GST_VIDEO_INFO_HEIGHT (&decode->decoded_info);
493   if (crop_rect) {
494     display_width = crop_rect->width;
495     display_height = crop_rect->height;
496   }
497
498   state = gst_video_decoder_get_output_state (vdec);
499   if (G_UNLIKELY (!state))
500     goto set_display_res;
501
502   negotiated_width = GST_VIDEO_INFO_WIDTH (&state->info);
503   negotiated_height = GST_VIDEO_INFO_HEIGHT (&state->info);
504   gst_video_codec_state_unref (state);
505
506   if ((display_width == negotiated_width && display_height == negotiated_height)
507       && (decode->display_width == negotiated_width
508           && decode->display_height == negotiated_height))
509     return FALSE;
510
511 set_display_res:
512   decode->display_width = display_width;
513   decode->display_height = display_height;
514   return TRUE;
515 }
516
517 static gboolean
518 gst_vaapidecode_negotiate (GstVaapiDecode * decode)
519 {
520   GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode);
521   GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (vdec);
522
523   GST_DEBUG_OBJECT (decode, "input codec state changed: renegotiating");
524
525   GST_VIDEO_DECODER_STREAM_LOCK (vdec);
526   if (!gst_vaapidecode_update_src_caps (decode))
527     goto caps_negotiation_failed;
528   if (!gst_vaapi_plugin_base_set_caps (plugin, NULL, decode->srcpad_caps))
529     goto caps_negotiation_failed;
530   GST_VIDEO_DECODER_STREAM_UNLOCK (vdec);
531
532   if (!gst_video_decoder_negotiate (vdec))
533     return FALSE;
534
535   return TRUE;
536
537 caps_negotiation_failed:
538   {
539     GST_VIDEO_DECODER_STREAM_UNLOCK (vdec);
540     return FALSE;
541   }
542 }
543
544 static gboolean
545 is_src_allocator_dmabuf (GstVaapiDecode * decode)
546 {
547   GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (decode);
548
549   if (!GST_VAAPI_PLUGIN_BASE_SRC_PAD_CAN_DMABUF (plugin))
550     return FALSE;
551   return
552       gst_vaapi_is_dmabuf_allocator (GST_VAAPI_PLUGIN_BASE_SRC_PAD_ALLOCATOR
553       (plugin));
554 }
555
556 static GstFlowReturn
557 gst_vaapidecode_push_decoded_frame (GstVideoDecoder * vdec,
558     GstVideoCodecFrame * out_frame)
559 {
560   GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
561   GstVaapiSurfaceProxy *proxy;
562   GstVaapiSurface *surface;
563   GstFlowReturn ret;
564   const GstVaapiRectangle *crop_rect;
565   GstVaapiVideoMeta *meta;
566   GstBufferPoolAcquireParams *params = NULL;
567   GstVaapiVideoBufferPoolAcquireParams vaapi_params = { {0,}, };
568   guint flags, out_flags = 0;
569   gboolean alloc_renegotiate, caps_renegotiate;
570
571   if (!GST_VIDEO_CODEC_FRAME_IS_DECODE_ONLY (out_frame)) {
572     proxy = gst_video_codec_frame_get_user_data (out_frame);
573     surface = GST_VAAPI_SURFACE_PROXY_SURFACE (proxy);
574     crop_rect = gst_vaapi_surface_proxy_get_crop_rect (proxy);
575
576     /* in theory, we are not supposed to check the surface resolution
577      * change here since it should be advertised before from ligstvaapi.
578      * But there are issues with it especially for some vp9 streams where
579      * upstream element set un-cropped values in set_format() which make
580      * everything a mess. So better doing the explicit check here irrespective
581      * of what notification we get from upstream or libgstvaapi.Also, even if
582      * we received notification from libgstvaapi, the frame we are going to
583      * be pushed at this point might not have the notified resolution if there
584      * are queued frames in decoded picture buffer. */
585     alloc_renegotiate = is_surface_resolution_changed (decode, surface);
586     caps_renegotiate = is_display_resolution_changed (decode, crop_rect);
587
588     if (gst_pad_needs_reconfigure (GST_VIDEO_DECODER_SRC_PAD (vdec))
589         || alloc_renegotiate || caps_renegotiate || decode->do_renego) {
590
591       g_atomic_int_set (&decode->do_renego, FALSE);
592       if (!gst_vaapidecode_negotiate (decode))
593         return GST_FLOW_ERROR;
594     }
595
596     if (is_src_allocator_dmabuf (decode)) {
597       vaapi_params.proxy = gst_vaapi_surface_proxy_ref (proxy);
598       params = (GstBufferPoolAcquireParams *) & vaapi_params;
599     }
600
601     ret = gst_video_decoder_allocate_output_frame_with_params (vdec, out_frame,
602         params);
603     if (params)
604       gst_vaapi_surface_proxy_unref (vaapi_params.proxy);
605     if (ret != GST_FLOW_OK)
606       goto error_create_buffer;
607
608     /* if not dmabuf is negotiated set the vaapi video meta in the
609      * proxy */
610     if (!params) {
611       meta = gst_buffer_get_vaapi_video_meta (out_frame->output_buffer);
612       if (!meta)
613         goto error_get_meta;
614       gst_vaapi_video_meta_set_surface_proxy (meta, proxy);
615     }
616
617     flags = gst_vaapi_surface_proxy_get_flags (proxy);
618     if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_CORRUPTED)
619       out_flags |= GST_BUFFER_FLAG_CORRUPTED;
620     if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_INTERLACED) {
621       out_flags |= GST_VIDEO_BUFFER_FLAG_INTERLACED;
622       if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_TFF)
623         out_flags |= GST_VIDEO_BUFFER_FLAG_TFF;
624       if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_RFF)
625         out_flags |= GST_VIDEO_BUFFER_FLAG_RFF;
626       if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_ONEFIELD)
627         out_flags |= GST_VIDEO_BUFFER_FLAG_ONEFIELD;
628     }
629     GST_BUFFER_FLAG_SET (out_frame->output_buffer, out_flags);
630
631     if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_FFB) {
632       GST_BUFFER_FLAG_SET (out_frame->output_buffer,
633           GST_VIDEO_BUFFER_FLAG_FIRST_IN_BUNDLE);
634     }
635 #if (USE_GLX || USE_EGL)
636     if (decode->has_texture_upload_meta)
637       gst_buffer_ensure_texture_upload_meta (out_frame->output_buffer);
638 #endif
639
640     /* Generate a system allocated output buffer if downstream doesn't
641      * support GstVideoMeta */
642     if (GST_VAAPI_PLUGIN_BASE_COPY_OUTPUT_FRAME (vdec)) {
643       GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (vdec);
644       GstBuffer *sys_buf, *va_buf;
645
646       va_buf = out_frame->output_buffer;
647       sys_buf =
648           gst_buffer_new_allocate (GST_VAAPI_PLUGIN_BASE_OTHER_ALLOCATOR
649           (plugin),
650           GST_VIDEO_INFO_SIZE (GST_VAAPI_PLUGIN_BASE_SRC_PAD_INFO (plugin)),
651           &GST_VAAPI_PLUGIN_BASE_OTHER_ALLOCATOR_PARAMS (plugin));
652       if (!sys_buf)
653         goto error_no_sys_buffer;
654
655       if (!gst_vaapi_plugin_copy_va_buffer (plugin, va_buf, sys_buf)) {
656         gst_buffer_unref (sys_buf);
657         goto error_cannot_copy;
658       }
659
660       gst_buffer_replace (&out_frame->output_buffer, sys_buf);
661       gst_buffer_unref (sys_buf);
662     }
663   }
664
665   ret = gst_video_decoder_finish_frame (vdec, out_frame);
666   if (ret != GST_FLOW_OK)
667     goto error_commit_buffer;
668   return GST_FLOW_OK;
669
670   /* ERRORS */
671 error_create_buffer:
672   {
673     const GstVaapiID surface_id =
674         gst_vaapi_surface_get_id (GST_VAAPI_SURFACE_PROXY_SURFACE (proxy));
675
676     GST_ELEMENT_ERROR (vdec, STREAM, FAILED,
677         ("Failed to create sink buffer"),
678         ("video sink failed to create video buffer for proxy'ed "
679             "surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (surface_id)));
680     gst_video_decoder_drop_frame (vdec, out_frame);
681     return GST_FLOW_ERROR;
682   }
683 error_get_meta:
684   {
685     GST_ELEMENT_ERROR (vdec, STREAM, FAILED,
686         ("Failed to get vaapi video meta attached to video buffer"),
687         ("Failed to get vaapi video meta attached to video buffer"));
688     gst_video_decoder_drop_frame (vdec, out_frame);
689     return GST_FLOW_ERROR;
690   }
691 error_no_sys_buffer:
692   {
693     GST_ELEMENT_ERROR (vdec, STREAM, FAILED,
694         ("Failed to create system allocated buffer"),
695         ("Failed to create system allocated buffer"));
696     gst_video_decoder_drop_frame (vdec, out_frame);
697     return GST_FLOW_ERROR;
698   }
699 error_cannot_copy:
700   {
701     GST_ELEMENT_ERROR (vdec, STREAM, FAILED,
702         ("Failed to copy system allocated buffer"),
703         ("Failed to copy system allocated buffer"));
704     gst_video_decoder_drop_frame (vdec, out_frame);
705     return GST_FLOW_ERROR;
706   }
707 error_commit_buffer:
708   {
709     GST_LOG_OBJECT (decode, "downstream element rejected the frame (%s [%d])",
710         gst_flow_get_name (ret), ret);
711     return ret;
712   }
713 }
714
715 static GstFlowReturn
716 gst_vaapidecode_push_all_decoded_frames (GstVaapiDecode * decode)
717 {
718   GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode);
719   GstVaapiDecoderStatus status;
720   GstVideoCodecFrame *out_frame;
721   GstFlowReturn ret;
722
723   for (;;) {
724     status = gst_vaapi_decoder_get_frame (decode->decoder, &out_frame);
725
726     switch (status) {
727       case GST_VAAPI_DECODER_STATUS_SUCCESS:
728         /* GstVaapiDecode's queue adds an extra reference */
729         gst_video_codec_frame_unref (out_frame);
730         ret = gst_vaapidecode_push_decoded_frame (vdec, out_frame);
731         if (ret != GST_FLOW_OK)
732           return ret;
733         break;
734       case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
735         return GST_FLOW_OK;
736       default:
737         GST_VIDEO_DECODER_ERROR (vdec, 1, STREAM, DECODE, ("Decoding failed"),
738             ("Unknown decoding error"), ret);
739         return ret;
740     }
741   }
742   g_assert_not_reached ();
743 }
744
745 static GstFlowReturn
746 gst_vaapidecode_handle_frame (GstVideoDecoder * vdec,
747     GstVideoCodecFrame * frame)
748 {
749   GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
750   GstVaapiDecoderStatus status;
751
752   if (!decode->input_state)
753     goto not_negotiated;
754
755   /* Decode current frame */
756   for (;;) {
757     status = gst_vaapi_decoder_decode (decode->decoder, frame);
758     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
759       goto error_decode;
760     break;
761   }
762
763   /* Note that gst_vaapi_decoder_decode cannot return success without
764      completing the decode and pushing all decoded frames into the output
765      queue */
766   return gst_vaapidecode_push_all_decoded_frames (decode);
767
768   /* ERRORS */
769 error_decode:
770   {
771     GstFlowReturn ret = GST_FLOW_OK;
772
773     GST_WARNING_OBJECT (decode, "decode error %d", status);
774
775     switch (status) {
776       case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
777       case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
778       case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
779         ret = GST_FLOW_NOT_SUPPORTED;
780         break;
781       default:
782         GST_VIDEO_DECODER_ERROR (vdec, 1, STREAM, DECODE, ("Decoding error"),
783             ("Decode error %d", status), ret);
784         GST_INFO_OBJECT (decode, "requesting upstream a key unit");
785         gst_pad_push_event (GST_VIDEO_DECODER_SINK_PAD (decode),
786             gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE,
787                 FALSE, 0));
788         break;
789     }
790     gst_video_decoder_drop_frame (vdec, frame);
791     return ret;
792   }
793 not_negotiated:
794   {
795     GST_ERROR_OBJECT (decode, "not negotiated");
796     gst_video_decoder_drop_frame (vdec, frame);
797     return GST_FLOW_NOT_NEGOTIATED;
798   }
799 }
800
801 /* If there is something in GstVideoDecoder's output adapter, then
802    submit the frame for decoding */
803 static inline void
804 gst_vaapidecode_flush_output_adapter (GstVaapiDecode * decode)
805 {
806   if (decode->current_frame_size == 0)
807     return;
808   gst_video_decoder_have_frame (GST_VIDEO_DECODER (decode));
809   decode->current_frame_size = 0;
810 }
811
812 static GstFlowReturn
813 gst_vaapidecode_drain (GstVideoDecoder * vdec)
814 {
815   GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
816
817   if (!decode->decoder)
818     return GST_FLOW_NOT_NEGOTIATED;
819
820   GST_LOG_OBJECT (decode, "drain");
821
822   gst_vaapidecode_flush_output_adapter (decode);
823   return gst_vaapidecode_push_all_decoded_frames (decode);
824 }
825
826 static GstFlowReturn
827 gst_vaapidecode_finish (GstVideoDecoder * vdec)
828 {
829   GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
830   GstVaapiDecoderStatus status;
831   GstFlowReturn ret;
832
833   if (!decode->decoder)
834     return GST_FLOW_OK;
835
836   gst_vaapidecode_flush_output_adapter (decode);
837   status = gst_vaapi_decoder_flush (decode->decoder);
838   ret = gst_vaapidecode_push_all_decoded_frames (decode);
839   if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
840     goto error_decoder_flush;
841   return ret;
842
843   /* ERRORS: */
844 error_decoder_flush:
845   {
846     GST_WARNING_OBJECT (decode, "failed to flush decoder (status %d)", status);
847     return GST_FLOW_ERROR;
848   }
849 }
850
851 static gboolean
852 gst_vaapidecode_decide_allocation (GstVideoDecoder * vdec, GstQuery * query)
853 {
854   GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
855   GstCaps *caps = NULL;
856
857   gst_query_parse_allocation (query, &caps, NULL);
858   if (!caps)
859     goto error_no_caps;
860
861   decode->has_texture_upload_meta = FALSE;
862
863 #if (USE_GLX || USE_EGL)
864   decode->has_texture_upload_meta =
865       gst_query_find_allocation_meta (query,
866       GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, NULL) &&
867       gst_vaapi_caps_feature_contains (caps,
868       GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META);
869 #endif
870
871   return gst_vaapi_plugin_base_decide_allocation (GST_VAAPI_PLUGIN_BASE (vdec),
872       query);
873
874   /* ERRORS */
875 error_no_caps:
876   {
877     GST_ERROR_OBJECT (decode, "no caps specified");
878     return FALSE;
879   }
880 }
881
882 static inline gboolean
883 gst_vaapidecode_ensure_display (GstVaapiDecode * decode)
884 {
885   return gst_vaapi_plugin_base_ensure_display (GST_VAAPI_PLUGIN_BASE (decode));
886 }
887
888 static gboolean
889 gst_vaapidecode_create (GstVaapiDecode * decode, GstCaps * caps)
890 {
891   GstVaapiDisplay *dpy;
892
893   if (!gst_vaapidecode_ensure_display (decode))
894     return FALSE;
895   dpy = GST_VAAPI_PLUGIN_BASE_DISPLAY (decode);
896
897   switch (gst_vaapi_get_codec_from_caps (caps)) {
898     case GST_VAAPI_CODEC_MPEG2:
899       decode->decoder = gst_vaapi_decoder_mpeg2_new (dpy, caps);
900       break;
901     case GST_VAAPI_CODEC_MPEG4:
902     case GST_VAAPI_CODEC_H263:
903       decode->decoder = gst_vaapi_decoder_mpeg4_new (dpy, caps);
904       break;
905     case GST_VAAPI_CODEC_H264:
906       decode->decoder = gst_vaapi_decoder_h264_new (dpy, caps);
907
908       /* Set the stream buffer alignment for better optimizations */
909       if (decode->decoder && caps) {
910         GstVaapiDecodeH264Private *priv =
911             gst_vaapi_decode_h264_get_instance_private (decode);
912         GstStructure *const structure = gst_caps_get_structure (caps, 0);
913         const gchar *str = NULL;
914
915         if (!structure)
916           break;
917
918         if ((str = gst_structure_get_string (structure, "alignment"))) {
919           GstVaapiStreamAlignH264 alignment;
920           if (g_strcmp0 (str, "au") == 0)
921             alignment = GST_VAAPI_STREAM_ALIGN_H264_AU;
922           else if (g_strcmp0 (str, "nal") == 0)
923             alignment = GST_VAAPI_STREAM_ALIGN_H264_NALU;
924           else
925             alignment = GST_VAAPI_STREAM_ALIGN_H264_NONE;
926           gst_vaapi_decoder_h264_set_alignment (GST_VAAPI_DECODER_H264
927               (decode->decoder), alignment);
928         }
929
930         if (priv) {
931           gst_vaapi_decoder_h264_set_low_latency (GST_VAAPI_DECODER_H264
932               (decode->decoder), priv->is_low_latency);
933           gst_vaapi_decoder_h264_set_base_only (GST_VAAPI_DECODER_H264
934               (decode->decoder), priv->base_only);
935         }
936       }
937       break;
938     case GST_VAAPI_CODEC_H265:
939       decode->decoder = gst_vaapi_decoder_h265_new (dpy, caps);
940
941       /* Set the stream buffer alignment for better optimizations */
942       if (decode->decoder && caps) {
943         GstStructure *const structure = gst_caps_get_structure (caps, 0);
944         const gchar *str = NULL;
945
946         if (!structure)
947           break;
948
949         if ((str = gst_structure_get_string (structure, "alignment"))) {
950           GstVaapiStreamAlignH265 alignment;
951           if (g_strcmp0 (str, "au") == 0)
952             alignment = GST_VAAPI_STREAM_ALIGN_H265_AU;
953           else if (g_strcmp0 (str, "nal") == 0)
954             alignment = GST_VAAPI_STREAM_ALIGN_H265_NALU;
955           else
956             alignment = GST_VAAPI_STREAM_ALIGN_H265_NONE;
957           gst_vaapi_decoder_h265_set_alignment (GST_VAAPI_DECODER_H265
958               (decode->decoder), alignment);
959         }
960       }
961       break;
962     case GST_VAAPI_CODEC_WMV3:
963     case GST_VAAPI_CODEC_VC1:
964       decode->decoder = gst_vaapi_decoder_vc1_new (dpy, caps);
965       break;
966     case GST_VAAPI_CODEC_JPEG:
967       decode->decoder = gst_vaapi_decoder_jpeg_new (dpy, caps);
968       break;
969     case GST_VAAPI_CODEC_VP8:
970       decode->decoder = gst_vaapi_decoder_vp8_new (dpy, caps);
971       break;
972     case GST_VAAPI_CODEC_VP9:
973       decode->decoder = gst_vaapi_decoder_vp9_new (dpy, caps);
974       break;
975 #if USE_AV1_DECODER
976     case GST_VAAPI_CODEC_AV1:
977       decode->decoder = gst_vaapi_decoder_av1_new (dpy, caps);
978       break;
979 #endif
980     default:
981       decode->decoder = NULL;
982       break;
983   }
984   if (!decode->decoder)
985     return FALSE;
986
987   gst_vaapi_decoder_set_codec_state_changed_func (decode->decoder,
988       gst_vaapi_decoder_state_changed, decode);
989
990   return TRUE;
991 }
992
993 static void
994 gst_vaapidecode_purge (GstVaapiDecode * decode)
995 {
996   GstVaapiDecoderStatus status;
997
998   if (!decode->decoder)
999     return;
1000
1001   status = gst_vaapi_decoder_flush (decode->decoder);
1002   if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
1003     GST_INFO_OBJECT (decode, "failed to flush decoder (status %d)", status);
1004
1005   /* Purge all decoded frames as we don't need them (e.g. flush and close)
1006    * Releasing the frames is important, otherwise the frames are not
1007    * freed. */
1008   do {
1009     GstVideoCodecFrame *frame = NULL;
1010
1011     status =
1012         gst_vaapi_decoder_get_frame_with_timeout (decode->decoder, &frame, 0);
1013     if (frame) {
1014       gst_video_decoder_release_frame (GST_VIDEO_DECODER (decode), frame);
1015       gst_video_codec_frame_unref (frame);
1016     }
1017   } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS);
1018 }
1019
1020 static void
1021 gst_vaapidecode_destroy (GstVaapiDecode * decode)
1022 {
1023   gst_vaapidecode_purge (decode);
1024
1025   gst_vaapi_decoder_replace (&decode->decoder, NULL);
1026   /* srcpad caps are decoder's context dependant */
1027   gst_caps_replace (&decode->allowed_srcpad_caps, NULL);
1028 }
1029
1030 static gboolean
1031 gst_vaapidecode_reset (GstVaapiDecode * decode, GstCaps * caps,
1032     gboolean force_reset)
1033 {
1034   /* Reset tracked frame size */
1035   decode->current_frame_size = 0;
1036
1037   if (decode->decoder) {
1038     if (!gst_caps_is_equal (caps, gst_vaapi_decoder_get_caps (decode->decoder))) {
1039       if (gst_vaapi_decoder_update_caps (decode->decoder, caps)) {
1040         g_atomic_int_set (&decode->do_renego, TRUE);
1041         if (!force_reset)
1042           return TRUE;
1043       }
1044     }
1045     return (gst_vaapi_decoder_reset (decode->decoder) ==
1046         GST_VAAPI_DECODER_STATUS_SUCCESS);
1047   }
1048
1049   return gst_vaapidecode_create (decode, caps);
1050 }
1051
1052 static void
1053 gst_vaapidecode_finalize (GObject * object)
1054 {
1055   gst_vaapi_plugin_base_finalize (GST_VAAPI_PLUGIN_BASE (object));
1056   G_OBJECT_CLASS (parent_class)->finalize (object);
1057 }
1058
1059 static gboolean
1060 gst_vaapidecode_open (GstVideoDecoder * vdec)
1061 {
1062   GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
1063
1064   if (!gst_vaapi_plugin_base_open (GST_VAAPI_PLUGIN_BASE (decode)))
1065     return FALSE;
1066
1067   decode->display_width = 0;
1068   decode->display_height = 0;
1069   gst_video_info_init (&decode->decoded_info);
1070
1071   return TRUE;
1072 }
1073
1074 static gboolean
1075 gst_vaapidecode_close (GstVideoDecoder * vdec)
1076 {
1077   GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
1078
1079   gst_vaapidecode_destroy (decode);
1080   gst_caps_replace (&decode->allowed_srcpad_caps, NULL);
1081   gst_caps_replace (&decode->allowed_sinkpad_caps, NULL);
1082   gst_vaapi_plugin_base_close (GST_VAAPI_PLUGIN_BASE (decode));
1083   return TRUE;
1084 }
1085
1086 static gboolean
1087 gst_vaapidecode_start (GstVideoDecoder * vdec)
1088 {
1089   GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
1090   GstVaapiDisplay *const old_display = GST_VAAPI_PLUGIN_BASE_DISPLAY (decode);
1091   gboolean success;
1092
1093   /* Let GstVideoContext ask for a proper display to its neighbours */
1094   /* Note: steal old display that may be allocated from get_caps()
1095      so that to retain a reference to it, thus avoiding extra
1096      initialization steps if we turn out to simply re-use the
1097      existing (cached) VA display */
1098   GST_VAAPI_PLUGIN_BASE_DISPLAY (decode) = NULL;
1099   success =
1100       gst_vaapi_plugin_base_ensure_display (GST_VAAPI_PLUGIN_BASE (decode));
1101   if (old_display)
1102     gst_object_unref (old_display);
1103
1104   /* Disable errors on decode errors */
1105   gst_video_decoder_set_max_errors (vdec, -1);
1106
1107   return success;
1108 }
1109
1110 static gboolean
1111 gst_vaapidecode_stop (GstVideoDecoder * vdec)
1112 {
1113   GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
1114
1115   gst_vaapidecode_purge (decode);
1116   gst_vaapi_decode_input_state_replace (decode, NULL);
1117   gst_vaapi_decoder_replace (&decode->decoder, NULL);
1118   gst_caps_replace (&decode->sinkpad_caps, NULL);
1119   gst_caps_replace (&decode->srcpad_caps, NULL);
1120   return TRUE;
1121 }
1122
1123 static gboolean
1124 gst_vaapidecode_flush (GstVideoDecoder * vdec)
1125 {
1126   GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
1127   if (!decode->decoder)
1128     return FALSE;
1129
1130   GST_LOG_OBJECT (vdec, "flushing");
1131
1132   gst_vaapidecode_purge (decode);
1133
1134   /* There could be issues if we avoid the reset() while doing
1135    * seeking: we have to reset the internal state */
1136   return gst_vaapidecode_reset (decode, decode->sinkpad_caps, TRUE);
1137 }
1138
1139 static gboolean
1140 gst_vaapidecode_set_format (GstVideoDecoder * vdec, GstVideoCodecState * state)
1141 {
1142   GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (vdec);
1143   GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
1144
1145   if (!gst_vaapi_decode_input_state_replace (decode, state))
1146     return TRUE;
1147   if (gst_vaapidecode_drain (vdec) == GST_FLOW_ERROR)
1148     return FALSE;
1149   if (!gst_vaapidecode_update_sink_caps (decode, state->caps))
1150     return FALSE;
1151   if (!gst_vaapi_plugin_base_set_caps (plugin, decode->sinkpad_caps, NULL))
1152     return FALSE;
1153   if (!gst_vaapidecode_reset (decode, decode->sinkpad_caps, FALSE))
1154     return FALSE;
1155
1156   return TRUE;
1157 }
1158
1159 static GstFlowReturn
1160 gst_vaapidecode_parse_frame (GstVideoDecoder * vdec,
1161     GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos)
1162 {
1163   GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
1164   GstVaapiDecoderStatus status;
1165   GstFlowReturn ret;
1166   guint got_unit_size;
1167   gboolean got_frame;
1168
1169   status = gst_vaapi_decoder_parse (decode->decoder, frame,
1170       adapter, at_eos, &got_unit_size, &got_frame);
1171
1172   switch (status) {
1173     case GST_VAAPI_DECODER_STATUS_SUCCESS:
1174       if (got_unit_size > 0) {
1175         gst_video_decoder_add_to_frame (vdec, got_unit_size);
1176         decode->current_frame_size += got_unit_size;
1177       }
1178       if (got_frame) {
1179         ret = gst_video_decoder_have_frame (vdec);
1180         decode->current_frame_size = 0;
1181       } else
1182         ret = GST_VAAPI_DECODE_FLOW_PARSE_DATA;
1183       break;
1184     case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
1185       ret = GST_VIDEO_DECODER_FLOW_NEED_DATA;
1186       break;
1187     case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
1188     case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
1189     case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
1190       GST_WARNING ("parse error %d", status);
1191       ret = GST_FLOW_NOT_SUPPORTED;
1192       decode->current_frame_size = 0;
1193       break;
1194     default:
1195       GST_WARNING ("parse error %d", status);
1196       /* just keep parsing, the decoder should have flushed the broken unit */
1197       ret = GST_VAAPI_DECODE_FLOW_PARSE_DATA;
1198       decode->current_frame_size = 0;
1199
1200       GST_INFO ("requesting upstream a key unit");
1201       gst_pad_push_event (GST_VIDEO_DECODER_SINK_PAD (decode),
1202           gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE,
1203               FALSE, 0));
1204       break;
1205   }
1206   return ret;
1207 }
1208
1209 static GstFlowReturn
1210 gst_vaapidecode_parse (GstVideoDecoder * vdec,
1211     GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos)
1212 {
1213   GstFlowReturn ret;
1214
1215   do {
1216     ret = gst_vaapidecode_parse_frame (vdec, frame, adapter, at_eos);
1217   } while (ret == GST_VAAPI_DECODE_FLOW_PARSE_DATA);
1218   return ret;
1219 }
1220
1221 static gboolean
1222 is_mvc_profile (GstVaapiProfile profile)
1223 {
1224   return profile == GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH
1225       || profile == GST_VAAPI_PROFILE_H264_STEREO_HIGH;
1226 }
1227
1228 static gboolean
1229 is_svc_profile (GstVaapiProfile profile)
1230 {
1231   return profile == GST_VAAPI_PROFILE_H264_SCALABLE_BASELINE
1232       || profile == GST_VAAPI_PROFILE_H264_SCALABLE_HIGH;
1233 }
1234
1235 static void
1236 find_mvc_and_svc (GArray * profiles, gboolean * have_mvc, gboolean * have_svc)
1237 {
1238   guint i;
1239
1240   for (i = 0; i < profiles->len; i++) {
1241     const GstVaapiProfile profile =
1242         g_array_index (profiles, GstVaapiProfile, i);
1243
1244     *have_mvc |= is_mvc_profile (profile);
1245     *have_svc |= is_svc_profile (profile);
1246   }
1247 }
1248
1249 static gboolean
1250 gst_vaapidecode_ensure_allowed_sinkpad_caps (GstVaapiDecode * decode)
1251 {
1252   GstCaps *caps, *allowed_sinkpad_caps;
1253   GstPad *const sinkpad = GST_VIDEO_DECODER_SINK_PAD (decode);
1254   GArray *profiles;
1255   GstVaapiDisplay *const display = GST_VAAPI_PLUGIN_BASE_DISPLAY (decode);
1256   guint i;
1257   gboolean base_only = FALSE;
1258   gboolean have_mvc = FALSE;
1259   gboolean have_svc = FALSE;
1260
1261   profiles = gst_vaapi_display_get_decode_profiles (display);
1262   if (!profiles)
1263     goto error_no_profiles;
1264
1265   allowed_sinkpad_caps = gst_caps_new_empty ();
1266   if (!allowed_sinkpad_caps)
1267     goto error_no_memory;
1268
1269   if (g_object_class_find_property (G_OBJECT_GET_CLASS (decode), "base-only")) {
1270     g_object_get (decode, "base-only", &base_only, NULL);
1271   }
1272
1273   find_mvc_and_svc (profiles, &have_mvc, &have_svc);
1274
1275   for (i = 0; i < profiles->len; i++) {
1276     const GstVaapiProfile profile =
1277         g_array_index (profiles, GstVaapiProfile, i);
1278     const gchar *media_type_name;
1279     const gchar *profile_name;
1280     GstStructure *structure;
1281
1282     media_type_name = gst_vaapi_profile_get_media_type_name (profile);
1283     if (!media_type_name)
1284       continue;
1285
1286     caps = gst_caps_from_string (media_type_name);
1287     if (!caps)
1288       continue;
1289     structure = gst_caps_get_structure (caps, 0);
1290     if (!structure)
1291       continue;
1292
1293     profile_name = gst_vaapi_profile_get_name (profile);
1294     if (!profile_name)
1295       goto merge_caps;
1296
1297     /* Add all according -intra profile for HEVC */
1298     if (profile == GST_VAAPI_PROFILE_H265_MAIN
1299         || profile == GST_VAAPI_PROFILE_H265_MAIN10
1300         || profile == GST_VAAPI_PROFILE_H265_MAIN_422_10
1301         || profile == GST_VAAPI_PROFILE_H265_MAIN_444
1302         || profile == GST_VAAPI_PROFILE_H265_MAIN_444_10
1303         || profile == GST_VAAPI_PROFILE_H265_MAIN12
1304         || profile == GST_VAAPI_PROFILE_H265_MAIN_444_12
1305         || profile == GST_VAAPI_PROFILE_H265_MAIN_422_12) {
1306       gchar *profiles[3], *intra_name;
1307
1308       intra_name = g_strdup_printf ("%s-intra", profile_name);
1309
1310       profiles[0] = (gchar *) profile_name;
1311       profiles[1] = intra_name;
1312       profiles[2] = NULL;
1313
1314       gst_vaapi_structure_set_profiles (structure, profiles);
1315       g_free (intra_name);
1316
1317     } else if (profile == GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE) {
1318       /* XXX: artificially adding baseline if constrained_baseline is
1319        * available. */
1320       gchar *profiles[] = { (gchar *) profile_name, "baseline", NULL };
1321
1322       gst_vaapi_structure_set_profiles (structure, profiles);
1323     } else if (profile == GST_VAAPI_PROFILE_H264_HIGH) {
1324       gchar *profiles[11] = { (gchar *) profile_name, "progressive-high",
1325         "constrained-high"
1326       };
1327       gint i = 3;
1328
1329       if (base_only && !have_mvc) {
1330         GST_DEBUG ("base_only: force adding MVC profiles in caps");
1331
1332         profiles[i++] = "multiview-high";
1333         profiles[i++] = "stereo-high";
1334       }
1335
1336       if (base_only && !have_svc) {
1337         GST_DEBUG ("base_only: force adding SVC profiles in caps");
1338
1339         profiles[i++] = "scalable-constrained-baseline";
1340         profiles[i++] = "scalable-baseline";
1341         profiles[i++] = "scalable-high-intra";
1342         profiles[i++] = "scalable-constrained-high";
1343         profiles[i++] = "scalable-high";
1344       }
1345
1346       profiles[i++] = NULL;
1347
1348       gst_vaapi_structure_set_profiles (structure, profiles);
1349     } else {
1350       gst_structure_set (structure, "profile", G_TYPE_STRING,
1351           profile_name, NULL);
1352     }
1353
1354   merge_caps:
1355     gst_vaapi_profile_caps_append_decoder (display, profile, structure);
1356     allowed_sinkpad_caps = gst_caps_merge (allowed_sinkpad_caps, caps);
1357   }
1358
1359   caps = gst_pad_get_pad_template_caps (sinkpad);
1360   decode->allowed_sinkpad_caps =
1361       gst_caps_intersect (allowed_sinkpad_caps, caps);
1362   gst_caps_unref (caps);
1363   gst_caps_unref (allowed_sinkpad_caps);
1364   decode->allowed_sinkpad_caps =
1365       gst_caps_simplify (decode->allowed_sinkpad_caps);
1366   GST_DEBUG_OBJECT (decode, "allowed sink caps %" GST_PTR_FORMAT,
1367       decode->allowed_sinkpad_caps);
1368
1369   g_array_unref (profiles);
1370   return TRUE;
1371
1372   /* ERRORS */
1373 error_no_profiles:
1374   {
1375     GST_ERROR ("failed to retrieve VA decode profiles");
1376     return FALSE;
1377   }
1378 error_no_memory:
1379   {
1380     GST_ERROR ("failed to allocate allowed-caps set");
1381     g_array_unref (profiles);
1382     return FALSE;
1383   }
1384 }
1385
1386 static GstCaps *
1387 gst_vaapidecode_sink_getcaps (GstVideoDecoder * vdec, GstCaps * filter)
1388 {
1389   GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
1390   GstCaps *result;
1391
1392   if (decode->allowed_sinkpad_caps)
1393     goto bail;
1394
1395   /* if we haven't a display yet, return our pad's template caps */
1396   if (!GST_VAAPI_PLUGIN_BASE_DISPLAY (decode))
1397     goto bail;
1398
1399   /* if the allowed caps calculation fails, return an empty caps, so
1400    * the auto-plug can try other decoder */
1401   if (!gst_vaapidecode_ensure_allowed_sinkpad_caps (decode))
1402     return gst_caps_new_empty ();
1403
1404 bail:
1405   result = gst_video_decoder_proxy_getcaps (vdec, decode->allowed_sinkpad_caps,
1406       filter);
1407
1408   GST_DEBUG_OBJECT (decode, "Returning sink caps %" GST_PTR_FORMAT, result);
1409
1410   return result;
1411 }
1412
1413 static gboolean
1414 gst_vaapidecode_sink_query (GstVideoDecoder * vdec, GstQuery * query)
1415 {
1416   gboolean ret = TRUE;
1417   GstElement *const element = GST_ELEMENT (vdec);
1418
1419   switch (GST_QUERY_TYPE (query)) {
1420     case GST_QUERY_CONTEXT:{
1421       ret = gst_vaapi_handle_context_query (element, query);
1422       break;
1423     }
1424     default:{
1425       ret = GST_VIDEO_DECODER_CLASS (parent_class)->sink_query (vdec, query);
1426       break;
1427     }
1428   }
1429
1430   return ret;
1431 }
1432
1433 static gboolean
1434 gst_vaapidecode_src_query (GstVideoDecoder * vdec, GstQuery * query)
1435 {
1436   gboolean ret = TRUE;
1437   GstElement *const element = GST_ELEMENT (vdec);
1438
1439   switch (GST_QUERY_TYPE (query)) {
1440     case GST_QUERY_CONTEXT:{
1441       ret = gst_vaapi_handle_context_query (element, query);
1442       break;
1443     }
1444     case GST_QUERY_CAPS:{
1445       GstCaps *caps, *filter = NULL;
1446       gboolean fixed_caps;
1447
1448       fixed_caps = GST_PAD_IS_FIXED_CAPS (GST_VIDEO_DECODER_SRC_PAD (vdec));
1449       if (!fixed_caps) {
1450         gst_query_parse_caps (query, &filter);
1451         caps = gst_vaapidecode_get_allowed_srcpad_caps (GST_VAAPIDECODE (vdec));
1452
1453         if (filter) {
1454           GstCaps *tmp = caps;
1455           caps =
1456               gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
1457           gst_caps_unref (tmp);
1458         }
1459
1460         gst_query_set_caps_result (query, caps);
1461         gst_caps_unref (caps);
1462         break;
1463       }
1464       /* else jump to default */
1465     }
1466     default:{
1467       ret = GST_VIDEO_DECODER_CLASS (parent_class)->src_query (vdec, query);
1468       break;
1469     }
1470   }
1471
1472   return ret;
1473 }
1474
1475 static gboolean
1476 gst_vaapidecode_transform_meta (GstVideoDecoder *
1477     vdec, GstVideoCodecFrame * frame, GstMeta * meta)
1478 {
1479   const GstMetaInfo *info = meta->info;
1480
1481   if (GST_VIDEO_DECODER_CLASS (parent_class)->transform_meta (vdec, frame,
1482           meta))
1483     return TRUE;
1484
1485   if (!g_strcmp0 (g_type_name (info->type), "GstVideoRegionOfInterestMeta"))
1486     return TRUE;
1487
1488   return FALSE;
1489 }
1490
1491 static void
1492 gst_vaapidecode_class_init (GstVaapiDecodeClass * klass)
1493 {
1494   GObjectClass *const object_class = G_OBJECT_CLASS (klass);
1495   GstElementClass *const element_class = GST_ELEMENT_CLASS (klass);
1496   GstVideoDecoderClass *const vdec_class = GST_VIDEO_DECODER_CLASS (klass);
1497   GstPadTemplate *pad_template;
1498   GstVaapiDecoderMap *map;
1499   gchar *name, *longname, *description;
1500   GstCaps *caps;
1501
1502   GST_DEBUG_CATEGORY_INIT (gst_debug_vaapidecode,
1503       GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
1504
1505   parent_class = g_type_class_peek_parent (klass);
1506
1507   gst_vaapi_plugin_base_class_init (GST_VAAPI_PLUGIN_BASE_CLASS (klass));
1508
1509   object_class->finalize = gst_vaapidecode_finalize;
1510
1511   vdec_class->open = GST_DEBUG_FUNCPTR (gst_vaapidecode_open);
1512   vdec_class->close = GST_DEBUG_FUNCPTR (gst_vaapidecode_close);
1513   vdec_class->start = GST_DEBUG_FUNCPTR (gst_vaapidecode_start);
1514   vdec_class->stop = GST_DEBUG_FUNCPTR (gst_vaapidecode_stop);
1515   vdec_class->set_format = GST_DEBUG_FUNCPTR (gst_vaapidecode_set_format);
1516   vdec_class->flush = GST_DEBUG_FUNCPTR (gst_vaapidecode_flush);
1517   vdec_class->parse = GST_DEBUG_FUNCPTR (gst_vaapidecode_parse);
1518   vdec_class->handle_frame = GST_DEBUG_FUNCPTR (gst_vaapidecode_handle_frame);
1519   vdec_class->finish = GST_DEBUG_FUNCPTR (gst_vaapidecode_finish);
1520   vdec_class->drain = GST_DEBUG_FUNCPTR (gst_vaapidecode_drain);
1521   vdec_class->decide_allocation =
1522       GST_DEBUG_FUNCPTR (gst_vaapidecode_decide_allocation);
1523   vdec_class->src_query = GST_DEBUG_FUNCPTR (gst_vaapidecode_src_query);
1524   vdec_class->sink_query = GST_DEBUG_FUNCPTR (gst_vaapidecode_sink_query);
1525   vdec_class->getcaps = GST_DEBUG_FUNCPTR (gst_vaapidecode_sink_getcaps);
1526   vdec_class->transform_meta =
1527       GST_DEBUG_FUNCPTR (gst_vaapidecode_transform_meta);
1528
1529   map = (GstVaapiDecoderMap *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
1530       GST_VAAPI_DECODE_PARAMS_QDATA);
1531
1532   if (map->codec) {
1533     name = g_ascii_strup (map->name, -1);
1534     longname = g_strdup_printf ("VA-API %s decoder", name);
1535     description = g_strdup_printf ("A VA-API based %s video decoder", name);
1536     g_free (name);
1537   } else {
1538     longname = g_strdup ("VA-API decoder");
1539     description = g_strdup (GST_PLUGIN_DESC);
1540   }
1541
1542   element_class->set_context = gst_vaapi_base_set_context;
1543   gst_element_class_set_static_metadata (element_class, longname,
1544       "Codec/Decoder/Video/Hardware", description,
1545       "Gwenole Beauchesne <gwenole.beauchesne@intel.com>, "
1546       "Halley Zhao <halley.zhao@intel.com>, "
1547       "Sreerenj Balachandran <sreerenj.balachandran@intel.com>, "
1548       "Wind Yuan <feng.yuan@intel.com>, Junyan He <junyan.he@intel.com>");
1549
1550   g_free (longname);
1551   g_free (description);
1552
1553   if (map->install_properties)
1554     map->install_properties (object_class);
1555
1556   /* sink pad */
1557   if (map->caps_str) {
1558     caps = gst_caps_from_string (map->caps_str);
1559   } else {
1560     caps = gst_caps_from_string (gst_vaapidecode_sink_caps_str);
1561     g_free (gst_vaapidecode_sink_caps_str);
1562   }
1563   pad_template = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
1564       caps);
1565   gst_caps_unref (caps);
1566   gst_element_class_add_pad_template (element_class, pad_template);
1567
1568   /* src pad */
1569   gst_element_class_add_static_pad_template (element_class,
1570       &gst_vaapidecode_src_factory);
1571 }
1572
1573 static void
1574 gst_vaapidecode_init (GstVaapiDecode * decode)
1575 {
1576   GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode);
1577
1578   gst_vaapi_plugin_base_init (GST_VAAPI_PLUGIN_BASE (decode), GST_CAT_DEFAULT);
1579
1580   gst_video_decoder_set_packetized (vdec, FALSE);
1581 }
1582
1583 gboolean
1584 gst_vaapidecode_register (GstPlugin * plugin, GArray * decoders)
1585 {
1586   gboolean ret = FALSE;
1587   guint i, codec, rank;
1588   gchar *type_name, *element_name, *sink_caps_str;
1589   const gchar *name;
1590   GType type;
1591   GTypeInfo typeinfo = {
1592     sizeof (GstVaapiDecodeClass),
1593     NULL,
1594     NULL,
1595     (GClassInitFunc) gst_vaapidecode_class_init,
1596     NULL,
1597     NULL,
1598     sizeof (GstVaapiDecode),
1599     0,
1600     (GInstanceInitFunc) gst_vaapidecode_init,
1601   };
1602
1603   for (i = 0; i < G_N_ELEMENTS (vaapi_decode_map); i++) {
1604     codec = vaapi_decode_map[i].codec;
1605     rank = vaapi_decode_map[i].rank;
1606     name = vaapi_decode_map[i].name;
1607
1608     if (codec && !gst_vaapi_codecs_has_codec (decoders, codec))
1609       continue;
1610
1611     if (!gst_vaapidecode_sink_caps_str) {
1612       gst_vaapidecode_sink_caps_str = g_strdup (vaapi_decode_map[i].caps_str);
1613     } else {
1614       sink_caps_str = g_strconcat (gst_vaapidecode_sink_caps_str, "; ",
1615           vaapi_decode_map[i].caps_str, NULL);
1616       g_clear_pointer (&gst_vaapidecode_sink_caps_str, g_free);
1617       if (!sink_caps_str)
1618         break;
1619       gst_vaapidecode_sink_caps_str = sink_caps_str;
1620     }
1621
1622     if (codec) {
1623       type_name = g_strdup_printf ("GstVaapiDecode_%s", name);
1624       element_name = g_strdup_printf ("vaapi%sdec", name);
1625     } else {
1626       type_name = g_strdup ("GstVaapiDecode");
1627       element_name = g_strdup_printf ("vaapidecode");
1628     }
1629
1630     type = g_type_from_name (type_name);
1631     if (!type) {
1632       /* create the gtype now */
1633       type = g_type_register_static (GST_TYPE_VIDEO_DECODER, type_name,
1634           &typeinfo, 0);
1635       gst_vaapi_plugin_base_init_interfaces (type);
1636       g_type_set_qdata (type, GST_VAAPI_DECODE_PARAMS_QDATA,
1637           (gpointer) & vaapi_decode_map[i]);
1638     }
1639
1640     /* Register GstVaapiDecode as GObject type, but not in GStreamer, so
1641      * vaapidecodebin can use it internally, but no exposed as a plugin
1642      * feature */
1643     if (codec)
1644       ret |= gst_element_register (plugin, element_name, rank, type);
1645
1646     g_free (element_name);
1647     g_free (type_name);
1648   }
1649
1650   return ret;
1651 }