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, ¶ms_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