• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) 2020 Igalia, S.L.
3  *     Author: Víctor Jáquez <vjaquez@igalia.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 the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include "gstvadecoder.h"
26 
27 #include "gstvaallocator.h"
28 #include "gstvacaps.h"
29 #include "gstvadisplay_priv.h"
30 #include "gstvavideoformat.h"
31 #include <gst/va/gstvadisplay_wrapped.h>
32 
33 struct _GstVaDecoder
34 {
35   GstObject parent;
36 
37   GArray *available_profiles;
38   GstCaps *srcpad_caps;
39   GstCaps *sinkpad_caps;
40   GstVaDisplay *display;
41   VAConfigID config;
42   VAContextID context;
43   VAProfile profile;
44   guint rt_format;
45   gint coded_width;
46   gint coded_height;
47 };
48 
49 GST_DEBUG_CATEGORY_STATIC (gst_va_decoder_debug);
50 #define GST_CAT_DEFAULT gst_va_decoder_debug
51 
52 #define gst_va_decoder_parent_class parent_class
53 G_DEFINE_TYPE_WITH_CODE (GstVaDecoder, gst_va_decoder, GST_TYPE_OBJECT,
54     GST_DEBUG_CATEGORY_INIT (gst_va_decoder_debug, "vadecoder", 0,
55         "VA Decoder"));
56 
57 enum
58 {
59   PROP_DISPLAY = 1,
60   PROP_PROFILE,
61   PROP_WIDTH,
62   PROP_HEIGHT,
63   PROP_CHROMA,
64   N_PROPERTIES
65 };
66 
67 static GParamSpec *g_properties[N_PROPERTIES];
68 
69 static gboolean _destroy_buffers (GstVaDecodePicture * pic);
70 
71 static void
gst_va_decoder_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)72 gst_va_decoder_set_property (GObject * object, guint prop_id,
73     const GValue * value, GParamSpec * pspec)
74 {
75   GstVaDecoder *self = GST_VA_DECODER (object);
76 
77   switch (prop_id) {
78     case PROP_DISPLAY:{
79       g_assert (!self->display);
80       self->display = g_value_dup_object (value);
81       break;
82     }
83     default:
84       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
85       break;
86   }
87 }
88 
89 static void
gst_va_decoder_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)90 gst_va_decoder_get_property (GObject * object, guint prop_id, GValue * value,
91     GParamSpec * pspec)
92 {
93   GstVaDecoder *self = GST_VA_DECODER (object);
94 
95   switch (prop_id) {
96     case PROP_DISPLAY:
97       g_value_set_object (value, self->display);
98       break;
99     case PROP_PROFILE:
100       g_value_set_int (value, self->profile);
101       break;
102     case PROP_CHROMA:
103       g_value_set_uint (value, self->rt_format);
104       break;
105     case PROP_WIDTH:
106       g_value_set_int (value, self->coded_width);
107       break;
108     case PROP_HEIGHT:
109       g_value_set_int (value, self->coded_height);
110       break;
111     default:
112       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
113       break;
114   }
115 }
116 
117 static void
gst_va_decoder_dispose(GObject * object)118 gst_va_decoder_dispose (GObject * object)
119 {
120   GstVaDecoder *self = GST_VA_DECODER (object);
121 
122   if (!gst_va_decoder_close (self))
123     GST_WARNING_OBJECT (self, "VaDecoder is not successfully closed");
124 
125   g_clear_pointer (&self->available_profiles, g_array_unref);
126   gst_clear_object (&self->display);
127 
128   G_OBJECT_CLASS (parent_class)->dispose (object);
129 }
130 
131 static void
gst_va_decoder_class_init(GstVaDecoderClass * klass)132 gst_va_decoder_class_init (GstVaDecoderClass * klass)
133 {
134   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
135 
136   gobject_class->set_property = gst_va_decoder_set_property;
137   gobject_class->get_property = gst_va_decoder_get_property;
138   gobject_class->dispose = gst_va_decoder_dispose;
139 
140   g_properties[PROP_DISPLAY] =
141       g_param_spec_object ("display", "GstVaDisplay", "GstVADisplay object",
142       GST_TYPE_VA_DISPLAY,
143       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
144 
145   g_properties[PROP_PROFILE] =
146       g_param_spec_int ("va-profile", "VAProfile", "VA Profile",
147       VAProfileNone, 50, VAProfileNone,
148       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
149 
150   g_properties[PROP_CHROMA] =
151       g_param_spec_uint ("va-rt-format", "VARTFormat", "VA RT Fromat or chroma",
152       VA_RT_FORMAT_YUV420, VA_RT_FORMAT_PROTECTED, VA_RT_FORMAT_YUV420,
153       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
154 
155   g_properties[PROP_WIDTH] =
156       g_param_spec_int ("coded-width", "coded-picture-width",
157       "coded picture width", 0, G_MAXINT, 0,
158       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
159 
160   g_properties[PROP_HEIGHT] =
161       g_param_spec_int ("coded-height", "coded-picture-height",
162       "coded picture height", 0, G_MAXINT, 0,
163       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
164 
165   g_object_class_install_properties (gobject_class, N_PROPERTIES, g_properties);
166 }
167 
168 static void
gst_va_decoder_init(GstVaDecoder * self)169 gst_va_decoder_init (GstVaDecoder * self)
170 {
171   self->profile = VAProfileNone;
172   self->config = VA_INVALID_ID;
173   self->context = VA_INVALID_ID;
174   self->rt_format = 0;
175   self->coded_width = 0;
176   self->coded_height = 0;
177 }
178 
179 static gboolean
gst_va_decoder_initialize(GstVaDecoder * self,guint32 codec)180 gst_va_decoder_initialize (GstVaDecoder * self, guint32 codec)
181 {
182   if (self->available_profiles)
183     return FALSE;
184 
185   self->available_profiles = gst_va_display_get_profiles (self->display, codec,
186       VAEntrypointVLD);
187 
188   return (self->available_profiles != NULL);
189 }
190 
191 GstVaDecoder *
gst_va_decoder_new(GstVaDisplay * display,guint32 codec)192 gst_va_decoder_new (GstVaDisplay * display, guint32 codec)
193 {
194   GstVaDecoder *self;
195 
196   g_return_val_if_fail (GST_IS_VA_DISPLAY (display), NULL);
197 
198   self = g_object_new (GST_TYPE_VA_DECODER, "display", display, NULL);
199   if (!gst_va_decoder_initialize (self, codec))
200     gst_clear_object (&self);
201 
202   return self;
203 }
204 
205 gboolean
gst_va_decoder_is_open(GstVaDecoder * self)206 gst_va_decoder_is_open (GstVaDecoder * self)
207 {
208   gboolean ret;
209 
210   g_return_val_if_fail (GST_IS_VA_DECODER (self), FALSE);
211 
212   GST_OBJECT_LOCK (self);
213   ret = (self->config != VA_INVALID_ID && self->profile != VAProfileNone);
214   GST_OBJECT_UNLOCK (self);
215   return ret;
216 }
217 
218 gboolean
gst_va_decoder_open(GstVaDecoder * self,VAProfile profile,guint rt_format)219 gst_va_decoder_open (GstVaDecoder * self, VAProfile profile, guint rt_format)
220 {
221   VAConfigAttrib attrib = {
222     .type = VAConfigAttribRTFormat,
223     .value = rt_format,
224   };
225   VAConfigID config;
226   VADisplay dpy;
227   VAStatus status;
228 
229   g_return_val_if_fail (GST_IS_VA_DECODER (self), FALSE);
230 
231   if (gst_va_decoder_is_open (self))
232     return TRUE;
233 
234   if (!gst_va_decoder_has_profile (self, profile)) {
235     GST_ERROR_OBJECT (self, "Unsupported profile: %d", profile);
236     return FALSE;
237   }
238 
239   dpy = gst_va_display_get_va_dpy (self->display);
240   gst_va_display_lock (self->display);
241   status = vaCreateConfig (dpy, profile, VAEntrypointVLD, &attrib, 1, &config);
242   gst_va_display_unlock (self->display);
243   if (status != VA_STATUS_SUCCESS) {
244     GST_ERROR_OBJECT (self, "vaCreateConfig: %s", vaErrorStr (status));
245     return FALSE;
246   }
247 
248   GST_OBJECT_LOCK (self);
249   self->config = config;
250   self->profile = profile;
251   self->rt_format = rt_format;
252   GST_OBJECT_UNLOCK (self);
253 
254   /* now we should return now only this profile's caps */
255   gst_caps_replace (&self->srcpad_caps, NULL);
256 
257   return TRUE;
258 }
259 
260 gboolean
gst_va_decoder_close(GstVaDecoder * self)261 gst_va_decoder_close (GstVaDecoder * self)
262 {
263   VADisplay dpy;
264   VAStatus status;
265 
266   g_return_val_if_fail (GST_IS_VA_DECODER (self), FALSE);
267 
268   if (!gst_va_decoder_is_open (self))
269     return TRUE;
270 
271   dpy = gst_va_display_get_va_dpy (self->display);
272 
273   if (self->context != VA_INVALID_ID) {
274     gst_va_display_lock (self->display);
275     status = vaDestroyContext (dpy, self->context);
276     gst_va_display_unlock (self->display);
277     if (status != VA_STATUS_SUCCESS)
278       GST_ERROR_OBJECT (self, "vaDestroyContext: %s", vaErrorStr (status));
279   }
280 
281   gst_va_display_lock (self->display);
282   status = vaDestroyConfig (dpy, self->config);
283   gst_va_display_unlock (self->display);
284   if (status != VA_STATUS_SUCCESS) {
285     GST_ERROR_OBJECT (self, "vaDestroyConfig: %s", vaErrorStr (status));
286     return FALSE;
287   }
288 
289   GST_OBJECT_LOCK (self);
290   gst_va_decoder_init (self);
291   GST_OBJECT_UNLOCK (self);
292 
293   gst_caps_replace (&self->srcpad_caps, NULL);
294   gst_caps_replace (&self->sinkpad_caps, NULL);
295 
296   return TRUE;
297 }
298 
299 gboolean
gst_va_decoder_set_frame_size_with_surfaces(GstVaDecoder * self,gint coded_width,gint coded_height,GArray * surfaces)300 gst_va_decoder_set_frame_size_with_surfaces (GstVaDecoder * self,
301     gint coded_width, gint coded_height, GArray * surfaces)
302 {
303   VAContextID context;
304   VADisplay dpy;
305   VAStatus status;
306   VASurfaceID *render_targets = NULL;
307   gint num_render_targets = 0;
308 
309   g_return_val_if_fail (GST_IS_VA_DECODER (self), FALSE);
310 
311   GST_OBJECT_LOCK (self);
312   if (self->context != VA_INVALID_ID) {
313     GST_OBJECT_UNLOCK (self);
314     GST_INFO_OBJECT (self, "decoder already has a context");
315     return TRUE;
316   }
317   GST_OBJECT_UNLOCK (self);
318 
319   if (!gst_va_decoder_is_open (self)) {
320     GST_ERROR_OBJECT (self, "decoder has not been opened yet");
321     return FALSE;
322   }
323 
324   if (surfaces) {
325     num_render_targets = surfaces->len;
326     render_targets = (VASurfaceID *) surfaces->data;
327   }
328 
329   dpy = gst_va_display_get_va_dpy (self->display);
330 
331   gst_va_display_lock (self->display);
332   status = vaCreateContext (dpy, self->config, coded_width, coded_height,
333       VA_PROGRESSIVE, render_targets, num_render_targets, &context);
334   gst_va_display_unlock (self->display);
335 
336   if (status != VA_STATUS_SUCCESS) {
337     GST_ERROR_OBJECT (self, "vaDestroyConfig: %s", vaErrorStr (status));
338     return FALSE;
339   }
340 
341   GST_OBJECT_LOCK (self);
342   self->context = context;
343   self->coded_width = coded_width;
344   self->coded_height = coded_height;
345   GST_OBJECT_UNLOCK (self);
346 
347   return TRUE;
348 }
349 
350 gboolean
gst_va_decoder_set_frame_size(GstVaDecoder * self,gint coded_width,gint coded_height)351 gst_va_decoder_set_frame_size (GstVaDecoder * self, gint coded_width,
352     gint coded_height)
353 {
354   return gst_va_decoder_set_frame_size_with_surfaces (self, coded_width,
355       coded_height, NULL);
356 }
357 
358 /* This function is only used by codecs where frame size can change
359  * without a context reset, as for example VP9 */
360 gboolean
gst_va_decoder_update_frame_size(GstVaDecoder * self,gint coded_width,gint coded_height)361 gst_va_decoder_update_frame_size (GstVaDecoder * self, gint coded_width,
362     gint coded_height)
363 {
364   g_return_val_if_fail (GST_IS_VA_DECODER (self), FALSE);
365 
366   if (!gst_va_decoder_is_open (self)) {
367     GST_ERROR_OBJECT (self, "decoder has not been opened yet");
368     return FALSE;
369   }
370 
371   GST_OBJECT_LOCK (self);
372   if (self->context == VA_INVALID_ID) {
373     GST_OBJECT_UNLOCK (self);
374     GST_INFO_OBJECT (self, "decoder does not have a context");
375     return FALSE;
376   }
377   GST_OBJECT_UNLOCK (self);
378 
379 
380   GST_OBJECT_LOCK (self);
381   self->coded_width = coded_width;
382   self->coded_height = coded_height;
383   GST_OBJECT_UNLOCK (self);
384 
385   return TRUE;
386 }
387 
388 static gboolean
_get_codec_caps(GstVaDecoder * self)389 _get_codec_caps (GstVaDecoder * self)
390 {
391   GstCaps *sinkpad_caps = NULL, *srcpad_caps = NULL;
392 
393   if (!gst_va_decoder_is_open (self)
394       && GST_IS_VA_DISPLAY_WRAPPED (self->display)) {
395     if (gst_va_caps_from_profiles (self->display, self->available_profiles,
396             VAEntrypointVLD, &sinkpad_caps, &srcpad_caps)) {
397       gst_caps_replace (&self->sinkpad_caps, sinkpad_caps);
398       gst_caps_replace (&self->srcpad_caps, srcpad_caps);
399       gst_caps_unref (srcpad_caps);
400       gst_caps_unref (sinkpad_caps);
401 
402       return TRUE;
403     }
404   }
405 
406   return FALSE;
407 }
408 
409 GstCaps *
gst_va_decoder_get_srcpad_caps(GstVaDecoder * self)410 gst_va_decoder_get_srcpad_caps (GstVaDecoder * self)
411 {
412   GstCaps *srcpad_caps = NULL;
413 
414   g_return_val_if_fail (GST_IS_VA_DECODER (self), FALSE);
415 
416   if (g_atomic_pointer_get (&self->srcpad_caps))
417     return gst_caps_ref (self->srcpad_caps);
418 
419   if (_get_codec_caps (self))
420     return gst_caps_ref (self->srcpad_caps);
421 
422   if (gst_va_decoder_is_open (self)) {
423     srcpad_caps = gst_va_create_raw_caps_from_config (self->display,
424         self->config);
425     gst_caps_replace (&self->srcpad_caps, srcpad_caps);
426     gst_caps_unref (srcpad_caps);
427 
428     return gst_caps_ref (self->srcpad_caps);
429   }
430 
431   return NULL;
432 }
433 
434 GstCaps *
gst_va_decoder_get_sinkpad_caps(GstVaDecoder * self)435 gst_va_decoder_get_sinkpad_caps (GstVaDecoder * self)
436 {
437   g_return_val_if_fail (GST_IS_VA_DECODER (self), FALSE);
438 
439   if (g_atomic_pointer_get (&self->sinkpad_caps))
440     return gst_caps_ref (self->sinkpad_caps);
441 
442   if (_get_codec_caps (self))
443     return gst_caps_ref (self->sinkpad_caps);
444 
445   return NULL;
446 }
447 
448 gboolean
gst_va_decoder_has_profile(GstVaDecoder * self,VAProfile profile)449 gst_va_decoder_has_profile (GstVaDecoder * self, VAProfile profile)
450 {
451   gint i;
452 
453   g_return_val_if_fail (GST_IS_VA_DECODER (self), FALSE);
454 
455   if (profile == VAProfileNone)
456     return FALSE;
457 
458   for (i = 0; i < self->available_profiles->len; i++) {
459     if (g_array_index (self->available_profiles, VAProfile, i) == profile)
460       return TRUE;
461   }
462 
463   return FALSE;
464 }
465 
466 gint
gst_va_decoder_get_mem_types(GstVaDecoder * self)467 gst_va_decoder_get_mem_types (GstVaDecoder * self)
468 {
469   VASurfaceAttrib *attribs;
470   guint i, attrib_count;
471   gint ret = 0;
472 
473   g_return_val_if_fail (GST_IS_VA_DECODER (self), 0);
474 
475   if (!gst_va_decoder_is_open (self))
476     return 0;
477 
478   attribs = gst_va_get_surface_attribs (self->display, self->config,
479       &attrib_count);
480   if (!attribs)
481     return 0;
482 
483   for (i = 0; i < attrib_count; i++) {
484     if (attribs[i].value.type != VAGenericValueTypeInteger)
485       continue;
486     switch (attribs[i].type) {
487       case VASurfaceAttribMemoryType:
488         ret = attribs[i].value.value.i;
489         break;
490       default:
491         break;
492     }
493   }
494 
495   g_free (attribs);
496 
497   return ret;
498 }
499 
500 GArray *
gst_va_decoder_get_surface_formats(GstVaDecoder * self)501 gst_va_decoder_get_surface_formats (GstVaDecoder * self)
502 {
503   GArray *formats;
504   GstVideoFormat format;
505   VASurfaceAttrib *attribs;
506   guint i, attrib_count;
507 
508   g_return_val_if_fail (GST_IS_VA_DECODER (self), NULL);
509 
510   if (!gst_va_decoder_is_open (self))
511     return NULL;
512 
513   attribs = gst_va_get_surface_attribs (self->display, self->config,
514       &attrib_count);
515   if (!attribs)
516     return NULL;
517 
518   formats = g_array_new (FALSE, FALSE, sizeof (GstVideoFormat));
519 
520   for (i = 0; i < attrib_count; i++) {
521     if (attribs[i].value.type != VAGenericValueTypeInteger)
522       continue;
523     switch (attribs[i].type) {
524       case VASurfaceAttribPixelFormat:
525         format = gst_va_video_format_from_va_fourcc (attribs[i].value.value.i);
526         if (format != GST_VIDEO_FORMAT_UNKNOWN)
527           g_array_append_val (formats, format);
528         break;
529       default:
530         break;
531     }
532   }
533 
534   g_free (attribs);
535 
536   if (formats->len == 0) {
537     g_array_unref (formats);
538     return NULL;
539   }
540 
541   return formats;
542 }
543 
544 gboolean
gst_va_decoder_add_param_buffer(GstVaDecoder * self,GstVaDecodePicture * pic,gint type,gpointer data,gsize size)545 gst_va_decoder_add_param_buffer (GstVaDecoder * self, GstVaDecodePicture * pic,
546     gint type, gpointer data, gsize size)
547 {
548   VABufferID buffer;
549   VADisplay dpy;
550   VAStatus status;
551 
552   g_return_val_if_fail (GST_IS_VA_DECODER (self), FALSE);
553   g_return_val_if_fail (self->context != VA_INVALID_ID, FALSE);
554   g_return_val_if_fail (pic && data && size > 0, FALSE);
555 
556   dpy = gst_va_display_get_va_dpy (self->display);
557   gst_va_display_lock (self->display);
558   status = vaCreateBuffer (dpy, self->context, type, size, 1, data, &buffer);
559   gst_va_display_unlock (self->display);
560   if (status != VA_STATUS_SUCCESS) {
561     GST_ERROR_OBJECT (self, "vaCreateBuffer: %s", vaErrorStr (status));
562     return FALSE;
563   }
564 
565   g_array_append_val (pic->buffers, buffer);
566   return TRUE;
567 }
568 
569 gboolean
gst_va_decoder_add_slice_buffer_with_n_params(GstVaDecoder * self,GstVaDecodePicture * pic,gpointer params_data,gsize params_size,guint params_num,gpointer slice_data,gsize slice_size)570 gst_va_decoder_add_slice_buffer_with_n_params (GstVaDecoder * self,
571     GstVaDecodePicture * pic, gpointer params_data, gsize params_size,
572     guint params_num, gpointer slice_data, gsize slice_size)
573 {
574   VABufferID params_buffer, slice_buffer;
575   VADisplay dpy;
576   VAStatus status;
577 
578   g_return_val_if_fail (GST_IS_VA_DECODER (self), FALSE);
579   g_return_val_if_fail (self->context != VA_INVALID_ID, FALSE);
580   g_return_val_if_fail (pic && slice_data && slice_size > 0
581       && params_data && params_size > 0, FALSE);
582 
583   dpy = gst_va_display_get_va_dpy (self->display);
584   gst_va_display_lock (self->display);
585   status = vaCreateBuffer (dpy, self->context, VASliceParameterBufferType,
586       params_size, params_num, params_data, &params_buffer);
587   gst_va_display_unlock (self->display);
588   if (status != VA_STATUS_SUCCESS) {
589     GST_ERROR_OBJECT (self, "vaCreateBuffer: %s", vaErrorStr (status));
590     return FALSE;
591   }
592 
593   gst_va_display_lock (self->display);
594   status = vaCreateBuffer (dpy, self->context, VASliceDataBufferType,
595       slice_size, 1, slice_data, &slice_buffer);
596   gst_va_display_unlock (self->display);
597   if (status != VA_STATUS_SUCCESS) {
598     GST_ERROR_OBJECT (self, "vaCreateBuffer: %s", vaErrorStr (status));
599     return FALSE;
600   }
601 
602   g_array_append_val (pic->slices, params_buffer);
603   g_array_append_val (pic->slices, slice_buffer);
604 
605   return TRUE;
606 }
607 
608 gboolean
gst_va_decoder_add_slice_buffer(GstVaDecoder * self,GstVaDecodePicture * pic,gpointer params_data,gsize params_size,gpointer slice_data,gsize slice_size)609 gst_va_decoder_add_slice_buffer (GstVaDecoder * self, GstVaDecodePicture * pic,
610     gpointer params_data, gsize params_size, gpointer slice_data,
611     gsize slice_size)
612 {
613   return gst_va_decoder_add_slice_buffer_with_n_params (self, pic, params_data,
614       params_size, 1, slice_data, slice_size);
615 }
616 
617 gboolean
gst_va_decoder_decode_with_aux_surface(GstVaDecoder * self,GstVaDecodePicture * pic,gboolean use_aux)618 gst_va_decoder_decode_with_aux_surface (GstVaDecoder * self,
619     GstVaDecodePicture * pic, gboolean use_aux)
620 {
621   VADisplay dpy;
622   VAStatus status;
623   VASurfaceID surface = VA_INVALID_ID;
624   gboolean ret = FALSE;
625 
626   g_return_val_if_fail (GST_IS_VA_DECODER (self), FALSE);
627   g_return_val_if_fail (self->context != VA_INVALID_ID, FALSE);
628   g_return_val_if_fail (pic, FALSE);
629 
630   if (use_aux) {
631     surface = gst_va_decode_picture_get_aux_surface (pic);
632   } else {
633     surface = gst_va_decode_picture_get_surface (pic);
634   }
635   if (surface == VA_INVALID_ID) {
636     GST_ERROR_OBJECT (self, "Decode picture without VASurfaceID");
637     return FALSE;
638   }
639 
640   GST_TRACE_OBJECT (self, "Decode to surface %#x", surface);
641 
642   dpy = gst_va_display_get_va_dpy (self->display);
643 
644   gst_va_display_lock (self->display);
645   status = vaBeginPicture (dpy, self->context, surface);
646   gst_va_display_unlock (self->display);
647   if (status != VA_STATUS_SUCCESS) {
648     GST_WARNING_OBJECT (self, "vaBeginPicture: %s", vaErrorStr (status));
649     goto fail_end_pic;
650   }
651 
652   if (pic->buffers->len > 0) {
653     gst_va_display_lock (self->display);
654     status = vaRenderPicture (dpy, self->context,
655         (VABufferID *) pic->buffers->data, pic->buffers->len);
656     gst_va_display_unlock (self->display);
657     if (status != VA_STATUS_SUCCESS) {
658       GST_WARNING_OBJECT (self, "vaRenderPicture: %s", vaErrorStr (status));
659       goto fail_end_pic;
660     }
661   }
662 
663   if (pic->slices->len > 0) {
664     gst_va_display_lock (self->display);
665     status = vaRenderPicture (dpy, self->context,
666         (VABufferID *) pic->slices->data, pic->slices->len);
667     gst_va_display_unlock (self->display);
668     if (status != VA_STATUS_SUCCESS) {
669       GST_WARNING_OBJECT (self, "vaRenderPicture: %s", vaErrorStr (status));
670       goto fail_end_pic;
671     }
672   }
673 
674   gst_va_display_lock (self->display);
675   status = vaEndPicture (dpy, self->context);
676   gst_va_display_unlock (self->display);
677   if (status != VA_STATUS_SUCCESS)
678     GST_WARNING_OBJECT (self, "vaEndPicture: %s", vaErrorStr (status));
679   else
680     ret = TRUE;
681 
682 bail:
683   _destroy_buffers (pic);
684 
685   return ret;
686 
687 fail_end_pic:
688   {
689     gst_va_display_lock (self->display);
690     status = vaEndPicture (dpy, self->context);
691     gst_va_display_unlock (self->display);
692     goto bail;
693   }
694 }
695 
696 gboolean
gst_va_decoder_decode(GstVaDecoder * self,GstVaDecodePicture * pic)697 gst_va_decoder_decode (GstVaDecoder * self, GstVaDecodePicture * pic)
698 {
699   return gst_va_decoder_decode_with_aux_surface (self, pic, FALSE);
700 }
701 
702 gboolean
gst_va_decoder_config_is_equal(GstVaDecoder * self,VAProfile new_profile,guint new_rtformat,gint new_width,gint new_height)703 gst_va_decoder_config_is_equal (GstVaDecoder * self, VAProfile new_profile,
704     guint new_rtformat, gint new_width, gint new_height)
705 {
706   gboolean ret;
707 
708   g_return_val_if_fail (GST_IS_VA_DECODER (self), FALSE);
709 
710   /* @TODO: Check if current buffers are large enough, and reuse
711    * them */
712   GST_OBJECT_LOCK (self);
713   ret = (self->profile == new_profile && self->rt_format == new_rtformat
714       && self->coded_width == new_width && self->coded_height == new_height);
715   GST_OBJECT_UNLOCK (self);
716 
717   return ret;
718 }
719 
720 gboolean
gst_va_decoder_get_config(GstVaDecoder * self,VAProfile * profile,guint * rt_format,gint * width,gint * height)721 gst_va_decoder_get_config (GstVaDecoder * self, VAProfile * profile,
722     guint * rt_format, gint * width, gint * height)
723 {
724   g_return_val_if_fail (GST_IS_VA_DECODER (self), FALSE);
725 
726   if (!gst_va_decoder_is_open (self))
727     return FALSE;
728 
729   GST_OBJECT_LOCK (self);
730   if (profile)
731     *profile = self->profile;
732   if (rt_format)
733     *rt_format = self->rt_format;
734   if (width)
735     *width = self->coded_width;
736   if (height)
737     *height = self->coded_height;
738   GST_OBJECT_UNLOCK (self);
739 
740   return TRUE;
741 }
742 
743 static gboolean
_destroy_buffers(GstVaDecodePicture * pic)744 _destroy_buffers (GstVaDecodePicture * pic)
745 {
746   VABufferID buffer;
747   VADisplay dpy;
748   VAStatus status;
749   guint i;
750   gboolean ret = TRUE;
751 
752   g_return_val_if_fail (GST_IS_VA_DISPLAY (pic->display), FALSE);
753 
754   dpy = gst_va_display_get_va_dpy (pic->display);
755 
756   if (pic->buffers) {
757     for (i = 0; i < pic->buffers->len; i++) {
758       buffer = g_array_index (pic->buffers, VABufferID, i);
759       gst_va_display_lock (pic->display);
760       status = vaDestroyBuffer (dpy, buffer);
761       gst_va_display_unlock (pic->display);
762       if (status != VA_STATUS_SUCCESS) {
763         ret = FALSE;
764         GST_WARNING ("Failed to destroy parameter buffer: %s",
765             vaErrorStr (status));
766       }
767     }
768 
769     pic->buffers = g_array_set_size (pic->buffers, 0);
770   }
771 
772   if (pic->slices) {
773     for (i = 0; i < pic->slices->len; i++) {
774       buffer = g_array_index (pic->slices, VABufferID, i);
775       gst_va_display_lock (pic->display);
776       status = vaDestroyBuffer (dpy, buffer);
777       gst_va_display_unlock (pic->display);
778       if (status != VA_STATUS_SUCCESS) {
779         ret = FALSE;
780         GST_WARNING ("Failed to destroy slice buffer: %s", vaErrorStr (status));
781       }
782     }
783 
784     pic->slices = g_array_set_size (pic->slices, 0);
785   }
786 
787   return ret;
788 }
789 
790 GstVaDecodePicture *
gst_va_decode_picture_new(GstVaDecoder * self,GstBuffer * buffer)791 gst_va_decode_picture_new (GstVaDecoder * self, GstBuffer * buffer)
792 {
793   GstVaDecodePicture *pic;
794 
795   g_return_val_if_fail (buffer && GST_IS_BUFFER (buffer), NULL);
796   g_return_val_if_fail (self && GST_IS_VA_DECODER (self), NULL);
797 
798   pic = g_slice_new (GstVaDecodePicture);
799   pic->gstbuffer = gst_buffer_ref (buffer);
800   pic->buffers = g_array_sized_new (FALSE, FALSE, sizeof (VABufferID), 16);
801   pic->slices = g_array_sized_new (FALSE, FALSE, sizeof (VABufferID), 64);
802   pic->display = gst_object_ref (self->display);
803 
804   return pic;
805 }
806 
807 VASurfaceID
gst_va_decode_picture_get_surface(GstVaDecodePicture * pic)808 gst_va_decode_picture_get_surface (GstVaDecodePicture * pic)
809 {
810   g_return_val_if_fail (pic, VA_INVALID_ID);
811   g_return_val_if_fail (pic->gstbuffer, VA_INVALID_ID);
812 
813   return gst_va_buffer_get_surface (pic->gstbuffer);
814 }
815 
816 VASurfaceID
gst_va_decode_picture_get_aux_surface(GstVaDecodePicture * pic)817 gst_va_decode_picture_get_aux_surface (GstVaDecodePicture * pic)
818 {
819   g_return_val_if_fail (pic, VA_INVALID_ID);
820   g_return_val_if_fail (pic->gstbuffer, VA_INVALID_ID);
821 
822   return gst_va_buffer_get_aux_surface (pic->gstbuffer);
823 }
824 
825 void
gst_va_decode_picture_free(GstVaDecodePicture * pic)826 gst_va_decode_picture_free (GstVaDecodePicture * pic)
827 {
828   g_return_if_fail (pic);
829 
830   _destroy_buffers (pic);
831 
832   gst_buffer_unref (pic->gstbuffer);
833   g_clear_pointer (&pic->buffers, g_array_unref);
834   g_clear_pointer (&pic->slices, g_array_unref);
835   gst_clear_object (&pic->display);
836 
837   g_slice_free (GstVaDecodePicture, pic);
838 }
839 
840 GstVaDecodePicture *
gst_va_decode_picture_dup(GstVaDecodePicture * pic)841 gst_va_decode_picture_dup (GstVaDecodePicture * pic)
842 {
843   GstVaDecodePicture *dup;
844 
845   g_return_val_if_fail (pic, NULL);
846 
847   dup = g_slice_new0 (GstVaDecodePicture);
848 
849   dup->display = gst_object_ref (pic->display);
850   /* dups only need gstbuffer */
851   dup->gstbuffer = gst_buffer_ref (pic->gstbuffer);
852   return dup;
853 }
854