Add initial infrastructure for video processing.
[platform/upstream/gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapifilter.c
1 /*
2  *  gstvaapifilter.c - Video processing abstraction
3  *
4  *  Copyright (C) 2013 Intel Corporation
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public License
8  *  as published by the Free Software Foundation; either version 2.1
9  *  of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free
18  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  *  Boston, MA 02110-1301 USA
20  */
21
22 #include "sysdeps.h"
23 #include "gstvaapifilter.h"
24 #include "gstvaapiutils.h"
25 #include "gstvaapiminiobject.h"
26 #include "gstvaapidisplay_priv.h"
27 #include "gstvaapisurface_priv.h"
28
29 #if USE_VA_VPP
30 # include <va/va_vpp.h>
31 #endif
32
33 #define DEBUG 1
34 #include "gstvaapidebug.h"
35
36 #define GST_VAAPI_FILTER(obj) \
37     ((GstVaapiFilter *)(obj))
38
39 typedef struct _GstVaapiFilterOpData GstVaapiFilterOpData;
40 struct _GstVaapiFilterOpData {
41     GstVaapiFilterOp    op;
42     GParamSpec         *pspec;
43     volatile gint       ref_count;
44     guint               va_type;
45     guint               va_subtype;
46     gpointer            va_caps;
47     guint               va_num_caps;
48     guint               va_cap_size;
49     VABufferID          va_buffer;
50     guint               va_buffer_size;
51     guint               is_enabled      : 1;
52 };
53
54 struct _GstVaapiFilter {
55     /*< private >*/
56     GstVaapiMiniObject  parent_instance;
57
58     GstVaapiDisplay    *display;
59     VADisplay           va_display;
60     VAConfigID          va_config;
61     VAContextID         va_context;
62     GPtrArray          *operations;
63     GstVideoFormat      format;
64     GArray             *formats;
65 };
66
67 /* ------------------------------------------------------------------------- */
68 /* --- VPP Helpers                                                       --- */
69 /* ------------------------------------------------------------------------- */
70
71 #if USE_VA_VPP
72 static VAProcFilterType *
73 vpp_get_filters_unlocked(GstVaapiFilter *filter, guint *num_filters_ptr)
74 {
75     VAProcFilterType *filters = NULL;
76     guint num_filters = 0;
77     VAStatus va_status;
78
79     num_filters = VAProcFilterCount;
80     filters = g_malloc_n(num_filters, sizeof(*filters));
81     if (!filters)
82         goto error;
83
84     va_status = vaQueryVideoProcFilters(filter->va_display, filter->va_context,
85         filters, &num_filters);
86
87     // Try to reallocate to the expected number of filters
88     if (va_status == VA_STATUS_ERROR_MAX_NUM_EXCEEDED) {
89         VAProcFilterType * const new_filters =
90             g_try_realloc_n(filters, num_filters, sizeof(*new_filters));
91         if (!new_filters)
92             goto error;
93         filters = new_filters;
94
95         va_status = vaQueryVideoProcFilters(filter->va_display,
96             filter->va_context, filters, &num_filters);
97     }
98     if (!vaapi_check_status(va_status, "vaQueryVideoProcFilters()"))
99         goto error;
100
101     *num_filters_ptr = num_filters;
102     return filters;
103
104 error:
105     g_free(filters);
106     return NULL;
107 }
108
109 static VAProcFilterType *
110 vpp_get_filters(GstVaapiFilter *filter, guint *num_filters_ptr)
111 {
112     VAProcFilterType *filters;
113
114     GST_VAAPI_DISPLAY_LOCK(filter->display);
115     filters = vpp_get_filters_unlocked(filter, num_filters_ptr);
116     GST_VAAPI_DISPLAY_UNLOCK(filter->display);
117     return filters;
118 }
119 #endif
120
121 /* ------------------------------------------------------------------------- */
122 /* --- VPP Operations                                                   --- */
123 /* ------------------------------------------------------------------------- */
124
125 #if USE_VA_VPP
126 #define DEFAULT_FORMAT  GST_VIDEO_FORMAT_UNKNOWN
127
128 enum {
129     PROP_0,
130
131     PROP_FORMAT         = GST_VAAPI_FILTER_OP_FORMAT,
132
133     N_PROPERTIES
134 };
135
136 static GParamSpec *g_properties[N_PROPERTIES] = { NULL, };
137 static gsize g_properties_initialized = FALSE;
138
139 static void
140 init_properties(void)
141 {
142     /**
143      * GstVaapiFilter:format:
144      *
145      * The forced output pixel format, expressed as a #GstVideoFormat.
146      */
147     g_properties[PROP_FORMAT] =
148         g_param_spec_enum("format",
149                           "Format",
150                           "The forced output pixel format",
151                           GST_TYPE_VIDEO_FORMAT,
152                           DEFAULT_FORMAT,
153                           G_PARAM_READWRITE);
154 }
155
156 static void
157 ensure_properties(void)
158 {
159     if (g_once_init_enter(&g_properties_initialized)) {
160         init_properties();
161         g_once_init_leave(&g_properties_initialized, TRUE);
162     }
163 }
164
165 static void
166 op_data_free(GstVaapiFilterOpData *op_data)
167 {
168     g_free(op_data->va_caps);
169     g_slice_free(GstVaapiFilterOpData, op_data);
170 }
171
172 static inline gpointer
173 op_data_new(GstVaapiFilterOp op, GParamSpec *pspec)
174 {
175     GstVaapiFilterOpData *op_data;
176
177     op_data = g_slice_new0(GstVaapiFilterOpData);
178     if (!op_data)
179         return NULL;
180
181     op_data->op         = op;
182     op_data->pspec      = pspec;
183     op_data->ref_count  = 1;
184     op_data->va_buffer  = VA_INVALID_ID;
185
186     switch (op) {
187     case GST_VAAPI_FILTER_OP_FORMAT:
188         op_data->va_type = VAProcFilterNone;
189         break;
190     default:
191         g_assert(0 && "unsupported operation");
192         goto error;
193     }
194     return op_data;
195
196 error:
197     op_data_free(op_data);
198     return NULL;
199 }
200
201 static inline gpointer
202 op_data_ref(gpointer data)
203 {
204     GstVaapiFilterOpData * const op_data = data;
205
206     g_return_val_if_fail(op_data != NULL, NULL);
207
208     g_atomic_int_inc(&op_data->ref_count);
209     return op_data;
210 }
211
212 static void
213 op_data_unref(gpointer data)
214 {
215     GstVaapiFilterOpData * const op_data = data;
216
217     g_return_if_fail(op_data != NULL);
218     g_return_if_fail(op_data->ref_count > 0);
219
220     if (g_atomic_int_dec_and_test(&op_data->ref_count))
221         op_data_free(op_data);
222 }
223
224 /* Get default list of operations supported by the library */
225 static GPtrArray *
226 get_operations_default(void)
227 {
228     GPtrArray *ops;
229     guint i;
230
231     ops = g_ptr_array_new_full(N_PROPERTIES, op_data_unref);
232     if (!ops)
233         return NULL;
234
235     ensure_properties();
236
237     for (i = 0; i < N_PROPERTIES; i++) {
238         GParamSpec * const pspec = g_properties[i];
239         if (!pspec)
240             continue;
241
242         GstVaapiFilterOpData * const op_data = op_data_new(i, pspec);
243         if (!op_data)
244             goto error;
245         g_ptr_array_add(ops, op_data);
246     }
247     return ops;
248
249 error:
250     g_ptr_array_unref(ops);
251     return NULL;
252 }
253
254 /* Get the ordered list of operations, based on VA/VPP queries */
255 static GPtrArray *
256 get_operations_ordered(GstVaapiFilter *filter, GPtrArray *default_ops)
257 {
258     GPtrArray *ops;
259     VAProcFilterType *filters;
260     guint i, j, num_filters;
261
262     ops = g_ptr_array_new_full(default_ops->len, op_data_unref);
263     if (!ops)
264         return NULL;
265
266     filters = vpp_get_filters(filter, &num_filters);
267     if (!filters)
268         goto error;
269
270     // Append virtual ops first, i.e. those without an associated VA filter
271     for (i = 0; i < default_ops->len; i++) {
272         GstVaapiFilterOpData * const op_data =
273             g_ptr_array_index(default_ops, i);
274         if (op_data->va_type == VAProcFilterNone)
275             g_ptr_array_add(ops, op_data_ref(op_data));
276     }
277
278     // Append ops, while preserving the VA filters ordering
279     for (i = 0; i < num_filters; i++) {
280         const VAProcFilterType va_type = filters[i];
281         if (va_type == VAProcFilterNone)
282             continue;
283
284         for (j = 0; j < default_ops->len; j++) {
285             GstVaapiFilterOpData * const op_data =
286                 g_ptr_array_index(default_ops, j);
287             if (op_data->va_type != va_type)
288                 continue;
289             g_ptr_array_add(ops, op_data_ref(op_data));
290         }
291     }
292
293     if (filter->operations)
294         g_ptr_array_unref(filter->operations);
295     filter->operations = g_ptr_array_ref(ops);
296
297     g_free(filters);
298     g_ptr_array_unref(default_ops);
299     return ops;
300
301 error:
302     g_free(filters);
303     g_ptr_array_unref(ops);
304     g_ptr_array_unref(default_ops);
305     return NULL;
306 }
307
308 /* Determine the set of supported VPP operations by the specific
309    filter, or known to this library if filter is NULL */
310 static GPtrArray *
311 ensure_operations(GstVaapiFilter *filter)
312 {
313     GPtrArray *ops;
314
315     if (filter && filter->operations)
316         return g_ptr_array_ref(filter->operations);
317
318     ops = get_operations_default();
319     if (!ops)
320         return NULL;
321     return filter ? get_operations_ordered(filter, ops) : ops;
322 }
323 #endif
324
325 /* Find whether the VPP operation is supported or not */
326 GstVaapiFilterOpData *
327 find_operation(GstVaapiFilter *filter, GstVaapiFilterOp op)
328 {
329     guint i;
330
331     if (!filter->operations)
332         return NULL;
333
334     for (i = 0; i < filter->operations->len; i++) {
335         GstVaapiFilterOpData * const op_data =
336             g_ptr_array_index(filter->operations, i);
337         if (op_data->op == op)
338             return op_data;
339     }
340     return NULL;
341 }
342
343 /* ------------------------------------------------------------------------- */
344 /* --- Surface Formats                                                   --- */
345 /* ------------------------------------------------------------------------- */
346
347 static GArray *
348 ensure_formats(GstVaapiFilter *filter)
349 {
350     VASurfaceAttrib *surface_attribs = NULL;
351     guint i, num_surface_attribs = 0;
352     VAStatus va_status;
353
354     if (G_LIKELY(filter->formats))
355         return filter->formats;
356
357 #if VA_CHECK_VERSION(0,34,0)
358     GST_VAAPI_DISPLAY_LOCK(filter->display);
359     va_status = vaQuerySurfaceAttributes(filter->va_display, filter->va_config,
360         NULL, &num_surface_attribs);
361     GST_VAAPI_DISPLAY_UNLOCK(filter->display);
362     if (!vaapi_check_status(va_status, "vaQuerySurfaceAttributes()"))
363         return NULL;
364
365     surface_attribs = g_malloc(num_surface_attribs * sizeof(*surface_attribs));
366     if (!surface_attribs)
367         return NULL;
368
369     GST_VAAPI_DISPLAY_LOCK(filter->display);
370     va_status = vaQuerySurfaceAttributes(filter->va_display, filter->va_config,
371         surface_attribs, &num_surface_attribs);
372     GST_VAAPI_DISPLAY_UNLOCK(filter->display);
373     if (!vaapi_check_status(va_status, "vaQuerySurfaceAttributes()"))
374         return NULL;
375
376     filter->formats = g_array_sized_new(FALSE, FALSE, sizeof(GstVideoFormat),
377         num_surface_attribs);
378     if (!filter->formats)
379         goto error;
380
381     for (i = 0; i < num_surface_attribs; i++) {
382         const VASurfaceAttrib * const surface_attrib = &surface_attribs[i];
383         GstVideoFormat format;
384
385         if (surface_attrib->type != VASurfaceAttribPixelFormat)
386             continue;
387         if (!(surface_attrib->flags & VA_SURFACE_ATTRIB_SETTABLE))
388             continue;
389
390         format = gst_vaapi_video_format_from_va_fourcc(
391             surface_attrib->value.value.i);
392         if (format == GST_VIDEO_FORMAT_UNKNOWN)
393             continue;
394         g_array_append_val(filter->formats, format);
395     }
396 #endif
397
398     g_free(surface_attribs);
399     return filter->formats;
400
401 error:
402     g_free(surface_attribs);
403     return NULL;
404 }
405
406 static inline gboolean
407 is_special_format(GstVideoFormat format)
408 {
409     return format == GST_VIDEO_FORMAT_UNKNOWN ||
410         format == GST_VIDEO_FORMAT_ENCODED;
411 }
412
413 static gboolean
414 find_format(GstVaapiFilter *filter, GstVideoFormat format)
415 {
416     guint i;
417
418     if (is_special_format(format) || !filter->formats)
419         return FALSE;
420
421     for (i = 0; i < filter->formats->len; i++) {
422         if (g_array_index(filter->formats, GstVideoFormat, i) == format)
423             return TRUE;
424     }
425     return FALSE;
426 }
427
428 /* ------------------------------------------------------------------------- */
429 /* --- Interface                                                         --- */
430 /* ------------------------------------------------------------------------- */
431
432 #if USE_VA_VPP
433 static gboolean
434 gst_vaapi_filter_init(GstVaapiFilter *filter, GstVaapiDisplay *display)
435 {
436     VAStatus va_status;
437
438     filter->display     = gst_vaapi_display_ref(display);
439     filter->va_display  = GST_VAAPI_DISPLAY_VADISPLAY(display);
440     filter->va_config   = VA_INVALID_ID;
441     filter->va_context  = VA_INVALID_ID;
442     filter->format      = DEFAULT_FORMAT;
443
444     if (!GST_VAAPI_DISPLAY_HAS_VPP(display))
445         return FALSE;
446
447     va_status = vaCreateConfig(filter->va_display, VAProfileNone,
448         VAEntrypointVideoProc, NULL, 0, &filter->va_config);
449     if (!vaapi_check_status(va_status, "vaCreateConfig() [VPP]"))
450         return FALSE;
451
452     va_status = vaCreateContext(filter->va_display, filter->va_config, 0, 0, 0,
453         NULL, 0, &filter->va_context);
454     if (!vaapi_check_status(va_status, "vaCreateContext() [VPP]"))
455         return FALSE;
456     return TRUE;
457 }
458
459 static void
460 gst_vaapi_filter_finalize(GstVaapiFilter *filter)
461 {
462     guint i;
463
464     GST_VAAPI_DISPLAY_LOCK(filter->display);
465     if (filter->operations) {
466         for (i = 0; i < filter->operations->len; i++) {
467             GstVaapiFilterOpData * const op_data =
468                 g_ptr_array_index(filter->operations, i);
469             vaapi_destroy_buffer(filter->va_display, &op_data->va_buffer);
470         }
471         g_ptr_array_unref(filter->operations);
472         filter->operations = NULL;
473     }
474
475     if (filter->va_context != VA_INVALID_ID) {
476         vaDestroyContext(filter->va_display, filter->va_context);
477         filter->va_context = VA_INVALID_ID;
478     }
479
480     if (filter->va_config != VA_INVALID_ID) {
481         vaDestroyConfig(filter->va_display, filter->va_config);
482         filter->va_config = VA_INVALID_ID;
483     }
484     GST_VAAPI_DISPLAY_UNLOCK(filter->display);
485     gst_vaapi_display_replace(&filter->display, NULL);
486
487     if (filter->formats) {
488         g_array_unref(filter->formats);
489         filter->formats = NULL;
490     }
491 }
492
493 static inline const GstVaapiMiniObjectClass *
494 gst_vaapi_filter_class(void)
495 {
496     static const GstVaapiMiniObjectClass GstVaapiFilterClass = {
497         sizeof(GstVaapiFilter),
498         (GDestroyNotify)gst_vaapi_filter_finalize
499     };
500     return &GstVaapiFilterClass;
501 }
502 #endif
503
504 /**
505  * gst_vaapi_filter_new:
506  * @display: a #GstVaapiDisplay
507  *
508  * Creates a new #GstVaapiFilter set up to operate in "identity"
509  * mode. This means that no other operation than scaling is performed.
510  *
511  * Return value: the newly created #GstVaapiFilter object
512  */
513 GstVaapiFilter *
514 gst_vaapi_filter_new(GstVaapiDisplay *display)
515 {
516 #if USE_VA_VPP
517     GstVaapiFilter *filter;
518
519     filter = (GstVaapiFilter *)
520         gst_vaapi_mini_object_new0(gst_vaapi_filter_class());
521     if (!filter)
522         return NULL;
523
524     if (!gst_vaapi_filter_init(filter, display))
525         goto error;
526     return filter;
527
528 error:
529     gst_vaapi_filter_unref(filter);
530     return NULL;
531 #else
532     GST_WARNING("video processing is not supported, "
533                 "please consider an upgrade to VA-API >= 0.34");
534     return NULL;
535 #endif
536 }
537
538 /**
539  * gst_vaapi_filter_ref:
540  * @filter: a #GstVaapiFilter
541  *
542  * Atomically increases the reference count of the given @filter by one.
543  *
544  * Returns: The same @filter argument
545  */
546 GstVaapiFilter *
547 gst_vaapi_filter_ref(GstVaapiFilter *filter)
548 {
549     g_return_val_if_fail(filter != NULL, NULL);
550
551     return GST_VAAPI_FILTER(gst_vaapi_mini_object_ref(
552                                 GST_VAAPI_MINI_OBJECT(filter)));
553 }
554
555 /**
556  * gst_vaapi_filter_unref:
557  * @filter: a #GstVaapiFilter
558  *
559  * Atomically decreases the reference count of the @filter by one. If
560  * the reference count reaches zero, the filter will be free'd.
561  */
562 void
563 gst_vaapi_filter_unref(GstVaapiFilter *filter)
564 {
565     g_return_if_fail(filter != NULL);
566
567     gst_vaapi_mini_object_unref(GST_VAAPI_MINI_OBJECT(filter));
568 }
569
570 /**
571  * gst_vaapi_filter_replace:
572  * @old_filter_ptr: a pointer to a #GstVaapiFilter
573  * @new_filter: a #GstVaapiFilter
574  *
575  * Atomically replaces the filter held in @old_filter_ptr with
576  * @new_filter. This means that @old_filter_ptr shall reference a
577  * valid filter. However, @new_filter can be NULL.
578  */
579 void
580 gst_vaapi_filter_replace(GstVaapiFilter **old_filter_ptr,
581     GstVaapiFilter *new_filter)
582 {
583     g_return_if_fail(old_filter_ptr != NULL);
584
585     gst_vaapi_mini_object_replace((GstVaapiMiniObject **)old_filter_ptr,
586         GST_VAAPI_MINI_OBJECT(new_filter));
587 }
588
589 /**
590  * gst_vaapi_filter_get_operations:
591  * @filter: a #GstVaapiFilter, or %NULL
592  *
593  * Determines the set of supported operations for video processing.
594  * The caller owns an extra reference to the resulting array of
595  * #GstVaapiFilterOpInfo elements, so it shall be released with
596  * g_ptr_array_unref() after usage.
597  *
598  * If @filter is %NULL, then this function returns the video
599  * processing operations supported by this library.
600  *
601  * Return value: the set of supported operations, or %NULL if an error
602  *   occurred.
603  */
604 GPtrArray *
605 gst_vaapi_filter_get_operations(GstVaapiFilter *filter)
606 {
607 #if USE_VA_VPP
608     return ensure_operations(filter);
609 #else
610     return NULL;
611 #endif
612 }
613
614 /**
615  * gst_vaapi_filter_set_operation:
616  * @filter: a #GstVaapiFilter
617  * @op: a #GstVaapiFilterOp
618  * @value: the @op settings
619  *
620  * Enable the specified operation @op to be performed during video
621  * processing, i.e. in gst_vaapi_filter_process(). The @value argument
622  * specifies the operation settings. e.g. deinterlacing method for
623  * deinterlacing, denoising level for noise reduction, etc.
624  *
625  * If @value is %NULL, then this function resets the operation
626  * settings to their default values.
627  *
628  * Return value: %TRUE if the specified operation may be supported,
629  *   %FALSE otherwise
630  */
631 gboolean
632 gst_vaapi_filter_set_operation(GstVaapiFilter *filter, GstVaapiFilterOp op,
633     const GValue *value)
634 {
635 #if USE_VA_VPP
636     GstVaapiFilterOpData *op_data;
637
638     g_return_val_if_fail(filter != NULL, FALSE);
639
640     op_data = find_operation(filter, op);
641     if (!op_data)
642         return FALSE;
643
644     if (value && !G_VALUE_HOLDS(value, G_PARAM_SPEC_VALUE_TYPE(op_data->pspec)))
645         return FALSE;
646
647     switch (op) {
648     case GST_VAAPI_FILTER_OP_FORMAT:
649         return gst_vaapi_filter_set_format(filter, value ?
650             g_value_get_enum(value) : DEFAULT_FORMAT);
651     default:
652         break;
653     }
654 #endif
655     return FALSE;
656 }
657
658 /**
659  * gst_vaapi_filter_process:
660  * @filter: a #GstVaapiFilter
661  * @src_surface: the source @GstVaapiSurface
662  * @dst_surface: the destination @GstVaapiSurface
663  * @flags: #GstVaapiSurfaceRenderFlags that apply to @src_surface
664  *
665  * Applies the operations currently defined in the @filter to
666  * @src_surface and return the output in @dst_surface. The order of
667  * operations is determined in a way that suits best the underlying
668  * hardware. i.e. the only guarantee held is the generated outcome,
669  * not any specific order of operations.
670  *
671  * Return value: a #GstVaapiFilterStatus
672  */
673 static GstVaapiFilterStatus
674 gst_vaapi_filter_process_unlocked(GstVaapiFilter *filter,
675     GstVaapiSurface *src_surface, GstVaapiSurface *dst_surface, guint flags)
676 {
677 #if USE_VA_VPP
678     VAProcPipelineParameterBuffer *pipeline_param = NULL;
679     VABufferID pipeline_param_buf_id;
680     VABufferID filters[N_PROPERTIES];
681     guint i, num_filters = 0;
682     VAStatus va_status;
683     VARectangle src_rect, dst_rect;
684
685     if (!ensure_operations(filter))
686         return GST_VAAPI_FILTER_STATUS_ERROR_ALLOCATION_FAILED;
687
688     src_rect.x      = 0;
689     src_rect.y      = 0;
690     src_rect.width  = GST_VAAPI_SURFACE_WIDTH(src_surface);
691     src_rect.height = GST_VAAPI_SURFACE_HEIGHT(src_surface);
692
693     dst_rect.x      = 0;
694     dst_rect.y      = 0;
695     dst_rect.width  = GST_VAAPI_SURFACE_WIDTH(dst_surface);
696     dst_rect.height = GST_VAAPI_SURFACE_HEIGHT(dst_surface);
697
698     for (i = 0, num_filters = 0; i < filter->operations->len; i++) {
699         GstVaapiFilterOpData * const op_data =
700             g_ptr_array_index(filter->operations, i);
701         if (!op_data->is_enabled)
702             continue;
703         if (op_data->va_buffer == VA_INVALID_ID) {
704             GST_ERROR("invalid VA buffer for operation %s",
705                       g_param_spec_get_name(op_data->pspec));
706             goto error;
707         }
708         filters[num_filters++] = op_data->va_buffer;
709     }
710
711     if (!vaapi_create_buffer(filter->va_display, filter->va_context,
712             VAProcPipelineParameterBufferType, sizeof(*pipeline_param),
713             NULL, &pipeline_param_buf_id, (gpointer *)&pipeline_param))
714         goto error;
715
716     memset(pipeline_param, 0, sizeof(*pipeline_param));
717     pipeline_param->surface = GST_VAAPI_OBJECT_ID(src_surface);
718     pipeline_param->surface_region = &src_rect;
719     pipeline_param->surface_color_standard = VAProcColorStandardNone;
720     pipeline_param->output_region = &dst_rect;
721     pipeline_param->output_color_standard = VAProcColorStandardNone;
722     pipeline_param->output_background_color = 0xff000000;
723     pipeline_param->filter_flags = from_GstVaapiSurfaceRenderFlags(flags);
724     pipeline_param->filters = filters;
725     pipeline_param->num_filters = num_filters;
726
727     vaapi_unmap_buffer(filter->va_display, pipeline_param_buf_id, NULL);
728
729     va_status = vaBeginPicture(filter->va_display, filter->va_context,
730         GST_VAAPI_OBJECT_ID(dst_surface));
731     if (!vaapi_check_status(va_status, "vaBeginPicture()"))
732         goto error;
733
734     va_status = vaRenderPicture(filter->va_display, filter->va_context,
735         &pipeline_param_buf_id, 1);
736     if (!vaapi_check_status(va_status, "vaRenderPicture()"))
737         goto error;
738
739     va_status = vaEndPicture(filter->va_display, filter->va_context);
740     if (!vaapi_check_status(va_status, "vaEndPicture()"))
741         goto error;
742     return GST_VAAPI_FILTER_STATUS_SUCCESS;
743
744 error:
745     vaDestroyBuffer(filter->va_display, pipeline_param_buf_id);
746     return GST_VAAPI_FILTER_STATUS_ERROR_OPERATION_FAILED;
747 #endif
748     return GST_VAAPI_FILTER_STATUS_ERROR_UNSUPPORTED_OPERATION;
749 }
750
751 GstVaapiFilterStatus
752 gst_vaapi_filter_process(GstVaapiFilter *filter, GstVaapiSurface *src_surface,
753     GstVaapiSurface *dst_surface, guint flags)
754 {
755     GstVaapiFilterStatus status;
756
757     g_return_val_if_fail(filter != NULL,
758         GST_VAAPI_FILTER_STATUS_ERROR_INVALID_PARAMETER);
759     g_return_val_if_fail(src_surface != NULL,
760         GST_VAAPI_FILTER_STATUS_ERROR_INVALID_PARAMETER);
761     g_return_val_if_fail(dst_surface != NULL,
762         GST_VAAPI_FILTER_STATUS_ERROR_INVALID_PARAMETER);
763
764     GST_VAAPI_DISPLAY_LOCK(filter->display);
765     status = gst_vaapi_filter_process_unlocked(filter,
766         src_surface, dst_surface, flags);
767     GST_VAAPI_DISPLAY_UNLOCK(filter->display);
768     return status;
769 }
770
771 /**
772  * gst_vaapi_filter_get_formats:
773  * @filter: a #GstVaapiFilter
774  *
775  * Determines the set of supported source or target formats for video
776  * processing.  The caller owns an extra reference to the resulting
777  * array of #GstVideoFormat elements, so it shall be released with
778  * g_array_unref() after usage.
779  *
780  * Return value: the set of supported target formats for video processing.
781  */
782 GArray *
783 gst_vaapi_filter_get_formats(GstVaapiFilter *filter)
784 {
785     g_return_val_if_fail(filter != NULL, NULL);
786
787     return ensure_formats(filter);
788 }
789
790 /**
791  * gst_vaapi_filter_set_format:
792  * @filter: a #GstVaapiFilter
793  * @format: the target surface format
794  *
795  * Sets the desired pixel format of the resulting video processing
796  * operations.
797  *
798  * If @format is #GST_VIDEO_FORMAT_UNKNOWN, the filter will assume iso
799  * format conversion, i.e. no color conversion at all and the target
800  * surface format shall match the source surface format.
801  *
802  * If @format is #GST_VIDEO_FORMAT_ENCODED, the filter will use the pixel
803  * format of the target surface passed to gst_vaapi_filter_process().
804  *
805  * Return value: %TRUE if the color conversion to the specified @format
806  *   may be supported, %FALSE otherwise.
807  */
808 gboolean
809 gst_vaapi_filter_set_format(GstVaapiFilter *filter, GstVideoFormat format)
810 {
811     g_return_val_if_fail(filter != NULL, FALSE);
812
813     if (!ensure_formats(filter))
814         return FALSE;
815
816     if (!is_special_format(format) && !find_format(filter, format))
817         return FALSE;
818
819     filter->format = format;
820     return TRUE;
821 }