msdkvpp: delete the macros to make video memory work on Windows
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / msdk / gstmsdkvpp.c
1 /* GStreamer Intel MSDK plugin
2  * Copyright (c) 2018, Intel Corporation
3  * All rights reserved.
4  *
5  * Author: Sreerenj Balachaandran <sreerenj.balachandran@intel.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice,
11  *    this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright notice,
14  *    this list of conditions and the following disclaimer in the documentation
15  *    and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the copyright holder nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
25  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
30  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
31  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 /**
35  * SECTION: element-msdkvpp
36  * @title: msdkvpp
37  * @short_description: MSDK Video Postprocessor
38  *
39  * A MediaSDK Video Postprocessing Filter
40  *
41  * ## Example launch line
42  * ```
43  * gst-launch-1.0 videotestsrc ! msdkvpp ! glimagesink
44  * ```
45  *
46  * Since: 1.16
47  *
48  */
49
50 #ifdef HAVE_CONFIG_H
51 #  include <config.h>
52 #endif
53
54 #include <stdlib.h>
55
56 #include "gstmsdkvpp.h"
57 #include "gstmsdkbufferpool.h"
58 #include "gstmsdkvideomemory.h"
59 #include "gstmsdksystemmemory.h"
60 #include "gstmsdkcontextutil.h"
61 #include "gstmsdkvpputil.h"
62
63 #define EXT_FORMATS     ""
64
65 #ifndef _WIN32
66 #include "gstmsdkallocator_libva.h"
67 #include <gst/va/gstvaallocator.h>
68 #if VA_CHECK_VERSION(1, 4, 1)
69 #undef EXT_FORMATS
70 #define EXT_FORMATS     ", BGR10A2_LE"
71 #endif
72 #else
73 #include <gst/d3d11/gstd3d11.h>
74 #endif
75
76 #if (MFX_VERSION >= 2004)
77 #define EXT_SINK_FORMATS        ", RGB16, Y410, Y210, P012_LE, Y212_LE, Y412_LE"
78 #define EXT_SRC_FORMATS         ", YV12, Y410, Y210, RGBP, BGRP, P012_LE, Y212_LE, Y412_LE"
79 #elif (MFX_VERSION >= 1032)
80 #define EXT_SINK_FORMATS        ", RGB16, Y410, Y210, P012_LE, Y212_LE, Y412_LE"
81 #define EXT_SRC_FORMATS         ", YV12, Y410, Y210, P012_LE, Y212_LE, Y412_LE"
82 #elif (MFX_VERSION >= 1031)
83 #define EXT_SINK_FORMATS        ", RGB16, Y410, Y210, P012_LE, Y212_LE, Y412_LE"
84 #define EXT_SRC_FORMATS         ", Y410, Y210, P012_LE, Y212_LE, Y412_LE"
85 #elif (MFX_VERSION >= 1028)
86 #define EXT_SINK_FORMATS        ", RGB16, Y410, Y210"
87 #define EXT_SRC_FORMATS         ", Y410, Y210"
88 #elif (MFX_VERSION >= 1027)
89 #define EXT_SINK_FORMATS        ", Y410, Y210"
90 #define EXT_SRC_FORMATS         ", Y410, Y210"
91 #else
92 #define EXT_SINK_FORMATS        ""
93 #define EXT_SRC_FORMATS         ""
94 #endif
95
96 GST_DEBUG_CATEGORY_EXTERN (gst_msdkvpp_debug);
97 #define GST_CAT_DEFAULT gst_msdkvpp_debug
98
99 #define SUPPORTED_SYSTEM_FORMAT \
100     "{ NV12, YV12, I420, YUY2, UYVY, VUYA, BGRA, BGRx, P010_10LE" EXT_SINK_FORMATS "}"
101 #define SUPPORTED_DMABUF_FORMAT \
102     "{ NV12, BGRA, YUY2, UYVY, VUYA, P010_10LE" EXT_SINK_FORMATS "}"
103 #define SUPPORTED_VA_FORMAT \
104     "{ NV12, VUYA, P010_10LE }"
105 #define SUPPORTED_D3D11_FORMAT \
106     "{ NV12, VUYA, P010_10LE }"
107 #define SRC_SYSTEM_FORMAT \
108     "{ NV12, BGRA, YUY2, UYVY, VUYA, BGRx, P010_10LE" EXT_FORMATS EXT_SRC_FORMATS "}"
109 #define SRC_DMABUF_FORMAT       \
110     "{ NV12, BGRA, YUY2, UYVY, VUYA, BGRx, P010_10LE" EXT_FORMATS EXT_SRC_FORMATS "}"
111
112 #ifndef _WIN32
113 #define DMABUF_SINK_CAPS_STR \
114   GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_DMABUF, \
115       SUPPORTED_DMABUF_FORMAT) ";"
116 #define VA_SINK_CAPS_STR \
117   GST_VIDEO_CAPS_MAKE_WITH_FEATURES ("memory:VAMemory", SUPPORTED_VA_FORMAT)
118 #else
119 #define D3D11_SINK_CAPS_STR \
120   GST_MSDK_CAPS_MAKE_WITH_D3D11_FEATURE (SUPPORTED_D3D11_FORMAT)
121 #endif
122
123 #ifndef _WIN32
124 #define DMABUF_SRC_CAPS_STR \
125   GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_DMABUF, \
126       SRC_DMABUF_FORMAT) ";"
127 #define VA_SRC_CAPS_STR \
128   GST_VIDEO_CAPS_MAKE_WITH_FEATURES ("memory:VAMemory", SUPPORTED_VA_FORMAT)
129 #else
130 #define D3D11_SRC_CAPS_STR \
131   GST_MSDK_CAPS_MAKE_WITH_D3D11_FEATURE (SUPPORTED_D3D11_FORMAT)
132 #endif
133
134 #ifndef _WIN32
135 static GstStaticPadTemplate gst_msdkvpp_sink_factory =
136     GST_STATIC_PAD_TEMPLATE ("sink",
137     GST_PAD_SINK,
138     GST_PAD_ALWAYS,
139     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (SUPPORTED_SYSTEM_FORMAT)
140         ", " "interlace-mode = (string){ progressive, interleaved, mixed }" ";"
141         DMABUF_SINK_CAPS_STR VA_SINK_CAPS_STR));
142
143 static GstStaticPadTemplate gst_msdkvpp_src_factory =
144     GST_STATIC_PAD_TEMPLATE ("src",
145     GST_PAD_SRC,
146     GST_PAD_ALWAYS,
147     GST_STATIC_CAPS (DMABUF_SRC_CAPS_STR
148         GST_VIDEO_CAPS_MAKE (SRC_SYSTEM_FORMAT) ", "
149         "interlace-mode = (string){ progressive, interleaved, mixed }" ";"
150         VA_SRC_CAPS_STR));
151 #else
152 static GstStaticPadTemplate gst_msdkvpp_sink_factory =
153     GST_STATIC_PAD_TEMPLATE ("sink",
154     GST_PAD_SINK,
155     GST_PAD_ALWAYS,
156     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (SUPPORTED_SYSTEM_FORMAT)
157         ", " "interlace-mode = (string){ progressive, interleaved, mixed }" ";"
158         D3D11_SINK_CAPS_STR));
159
160 static GstStaticPadTemplate gst_msdkvpp_src_factory =
161     GST_STATIC_PAD_TEMPLATE ("src",
162     GST_PAD_SRC,
163     GST_PAD_ALWAYS,
164     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (SRC_SYSTEM_FORMAT) ", "
165         "interlace-mode = (string){ progressive, interleaved, mixed }" ";"
166         D3D11_SRC_CAPS_STR));
167 #endif
168 enum
169 {
170   PROP_0,
171   PROP_HARDWARE,
172   PROP_ASYNC_DEPTH,
173   PROP_DENOISE,
174 #ifndef GST_REMOVE_DEPRECATED
175   PROP_ROTATION,
176 #endif
177   PROP_DEINTERLACE_MODE,
178   PROP_DEINTERLACE_METHOD,
179   PROP_HUE,
180   PROP_SATURATION,
181   PROP_BRIGHTNESS,
182   PROP_CONTRAST,
183   PROP_DETAIL,
184 #ifndef GST_REMOVE_DEPRECATED
185   PROP_MIRRORING,
186 #endif
187   PROP_SCALING_MODE,
188   PROP_FORCE_ASPECT_RATIO,
189   PROP_FRC_ALGORITHM,
190   PROP_VIDEO_DIRECTION,
191   PROP_CROP_LEFT,
192   PROP_CROP_RIGHT,
193   PROP_CROP_TOP,
194   PROP_CROP_BOTTOM,
195   PROP_N,
196 };
197
198 #define PROP_HARDWARE_DEFAULT            TRUE
199 #define PROP_ASYNC_DEPTH_DEFAULT         1
200 #define PROP_DENOISE_DEFAULT             0
201 #ifndef GST_REMOVE_DEPRECATED
202 #define PROP_ROTATION_DEFAULT            MFX_ANGLE_0
203 #define PROP_MIRRORING_DEFAULT           MFX_MIRRORING_DISABLED
204 #endif
205 #define PROP_DEINTERLACE_MODE_DEFAULT    GST_MSDKVPP_DEINTERLACE_MODE_AUTO
206 #define PROP_DEINTERLACE_METHOD_DEFAULT  MFX_DEINTERLACING_BOB
207 #define PROP_HUE_DEFAULT                 0
208 #define PROP_SATURATION_DEFAULT          1
209 #define PROP_BRIGHTNESS_DEFAULT          0
210 #define PROP_CONTRAST_DEFAULT            1
211 #define PROP_DETAIL_DEFAULT              0
212 #define PROP_SCALING_MODE_DEFAULT        MFX_SCALING_MODE_DEFAULT
213 #define PROP_FORCE_ASPECT_RATIO_DEFAULT  TRUE
214 #define PROP_FRC_ALGORITHM_DEFAULT       _MFX_FRC_ALGORITHM_NONE
215 #define PROP_VIDEO_DIRECTION_DEFAULT     GST_VIDEO_ORIENTATION_IDENTITY
216 #define PROP_CROP_LEFT_DEFAULT           0
217 #define PROP_CROP_RIGHT_DEFAULT          0
218 #define PROP_CROP_TOP_DEFAULT            0
219 #define PROP_CROP_BOTTOM_DEFAULT         0
220
221 /* 8 should enough for a normal encoder */
222 #define SRC_POOL_SIZE_DEFAULT            8
223
224 #define gst_msdkvpp_parent_class parent_class
225 G_DEFINE_TYPE (GstMsdkVPP, gst_msdkvpp, GST_TYPE_BASE_TRANSFORM);
226
227 static void
228 free_msdk_surface (gpointer p)
229 {
230   GstMsdkSurface *surface = (GstMsdkSurface *) p;
231   if (surface->buf)
232     gst_buffer_unref (surface->buf);
233   g_slice_free (GstMsdkSurface, surface);
234 }
235
236 static void
237 release_msdk_surface (GstMsdkVPP * thiz, GstMsdkSurface * surface,
238     GList ** list)
239 {
240   if (surface->surface) {
241     if (surface->surface->Data.Locked) {
242       *list = g_list_append (*list, surface);
243     } else {
244       free_msdk_surface (surface);
245     }
246   }
247 }
248
249 static void
250 release_in_surface (GstMsdkVPP * thiz, GstMsdkSurface * surface,
251     gboolean locked_by_others)
252 {
253   if (locked_by_others) {
254     /* mfxFrameSurface1 locked by others, others will hold the surface->buf reference */
255     /* we are good to release it here */
256     free_msdk_surface (surface);
257   } else {
258     release_msdk_surface (thiz, surface, &thiz->locked_in_surfaces);
259   }
260 }
261
262 static void
263 release_out_surface (GstMsdkVPP * thiz, GstMsdkSurface * surface)
264 {
265   release_msdk_surface (thiz, surface, &thiz->locked_out_surfaces);
266 }
267
268 static void
269 free_unlocked_msdk_surfaces_from_list (GstMsdkVPP * thiz, GList ** list)
270 {
271   GList *l;
272   GstMsdkSurface *surface;
273
274   for (l = *list; l;) {
275     GList *next = l->next;
276     surface = l->data;
277     if (surface->surface->Data.Locked == 0) {
278       free_msdk_surface (surface);
279       *list = g_list_delete_link (*list, l);
280     }
281     l = next;
282   }
283 }
284
285 static void
286 free_unlocked_msdk_surfaces (GstMsdkVPP * thiz)
287 {
288   free_unlocked_msdk_surfaces_from_list (thiz, &thiz->locked_in_surfaces);
289   free_unlocked_msdk_surfaces_from_list (thiz, &thiz->locked_out_surfaces);
290 }
291
292 static void
293 free_all_msdk_surfaces (GstMsdkVPP * thiz)
294 {
295   g_list_free_full (thiz->locked_in_surfaces, free_msdk_surface);
296   thiz->locked_in_surfaces = NULL;
297   g_list_free_full (thiz->locked_out_surfaces, free_msdk_surface);
298   thiz->locked_out_surfaces = NULL;
299 }
300
301 static void
302 gst_msdkvpp_add_extra_param (GstMsdkVPP * thiz, mfxExtBuffer * param)
303 {
304   if (thiz->num_extra_params < MAX_EXTRA_PARAMS) {
305     thiz->extra_params[thiz->num_extra_params] = param;
306     thiz->num_extra_params++;
307   }
308 }
309
310 static gboolean
311 gst_msdkvpp_context_prepare (GstMsdkVPP * thiz)
312 {
313   /* Try to find an existing context from the pipeline. This may (indirectly)
314    * invoke gst_msdkvpp_set_context, which will set thiz->context. */
315   if (!gst_msdk_context_find (GST_ELEMENT_CAST (thiz), &thiz->context))
316     return FALSE;
317
318   if (thiz->context == thiz->old_context) {
319     GST_INFO_OBJECT (thiz, "Found old context %" GST_PTR_FORMAT
320         ", reusing as-is", thiz->context);
321     return TRUE;
322   }
323
324   GST_INFO_OBJECT (thiz, "Found context %" GST_PTR_FORMAT " from neighbour",
325       thiz->context);
326
327   /* Check GST_MSDK_JOB_VPP and GST_MSDK_JOB_ENCODER together to avoid sharing context
328    * between VPP and ENCODER
329    * Example:
330    * gst-launch-1.0 videotestsrc ! msdkvpp ! video/x-raw,format=YUY2 ! msdkh264enc ! fakesink
331    */
332   if (!(gst_msdk_context_get_job_type (thiz->context) & (GST_MSDK_JOB_VPP |
333               GST_MSDK_JOB_ENCODER))) {
334     gst_msdk_context_add_job_type (thiz->context, GST_MSDK_JOB_VPP);
335     return TRUE;
336   }
337
338   /* Found an existing context that's already being used as VPP, so clone the
339    * MFX session inside it to create a new one */
340   {
341     GstMsdkContext *parent_context, *msdk_context;
342
343     GST_INFO_OBJECT (thiz, "Creating new context %" GST_PTR_FORMAT " with "
344         "joined session", thiz->context);
345     parent_context = thiz->context;
346     msdk_context = gst_msdk_context_new_with_parent (parent_context);
347
348     if (!msdk_context) {
349       GST_ERROR_OBJECT (thiz, "Failed to create a context with parent context "
350           "as %" GST_PTR_FORMAT, parent_context);
351       return FALSE;
352     }
353
354     thiz->context = msdk_context;
355     gst_object_unref (parent_context);
356   }
357
358   return TRUE;
359 }
360
361 static gboolean
362 ensure_context (GstBaseTransform * trans)
363 {
364   GstMsdkVPP *thiz = GST_MSDKVPP (trans);
365
366   if (!gst_msdkvpp_context_prepare (thiz)) {
367     if (!gst_msdk_ensure_new_context (GST_ELEMENT_CAST (thiz),
368             thiz->hardware, GST_MSDK_JOB_VPP, &thiz->context))
369       return FALSE;
370     GST_INFO_OBJECT (thiz, "Creating new context %" GST_PTR_FORMAT,
371         thiz->context);
372   }
373
374   /* Save the current context in a separate field so that we know whether it
375    * has changed between calls to _start() */
376   gst_object_replace ((GstObject **) & thiz->old_context,
377       (GstObject *) thiz->context);
378
379   gst_msdk_context_add_shared_async_depth (thiz->context, thiz->async_depth);
380
381   return TRUE;
382 }
383
384 static GstBuffer *
385 create_output_buffer (GstMsdkVPP * thiz)
386 {
387   GstBuffer *outbuf;
388   GstFlowReturn ret;
389   GstBufferPool *pool = thiz->srcpad_buffer_pool;
390
391   g_return_val_if_fail (pool != NULL, NULL);
392
393   if (!gst_buffer_pool_is_active (pool) &&
394       !gst_buffer_pool_set_active (pool, TRUE))
395     goto error_activate_pool;
396
397   outbuf = NULL;
398   ret = gst_buffer_pool_acquire_buffer (pool, &outbuf, NULL);
399   if (ret != GST_FLOW_OK || !outbuf)
400     goto error_create_buffer;
401
402   return outbuf;
403
404   /* ERRORS */
405 error_activate_pool:
406   {
407     GST_ERROR_OBJECT (thiz, "failed to activate output video buffer pool");
408     return NULL;
409   }
410 error_create_buffer:
411   {
412     GST_ERROR_OBJECT (thiz, "failed to create output video buffer");
413     return NULL;
414   }
415 }
416
417 static GstFlowReturn
418 gst_msdkvpp_prepare_output_buffer (GstBaseTransform * trans,
419     GstBuffer * inbuf, GstBuffer ** outbuf_ptr)
420 {
421   GstMsdkVPP *thiz = GST_MSDKVPP (trans);
422
423   if (gst_base_transform_is_passthrough (trans)) {
424     *outbuf_ptr = inbuf;
425     return GST_FLOW_OK;
426   }
427
428   *outbuf_ptr = create_output_buffer (thiz);
429   return *outbuf_ptr ? GST_FLOW_OK : GST_FLOW_ERROR;
430 }
431
432 #ifndef _WIN32
433 static GstBufferPool *
434 gst_msdk_create_va_pool (GstVideoInfo * info, GstMsdkContext * msdk_context,
435     gboolean use_dmabuf, guint min_buffers)
436 {
437   GstBufferPool *pool = NULL;
438   GstAllocator *allocator;
439   GArray *formats = NULL;
440   GstAllocationParams alloc_params = { 0, 31, 0, 0 };
441   GstVaDisplay *display = NULL;
442   GstCaps *aligned_caps = NULL;
443
444   display = (GstVaDisplay *) gst_msdk_context_get_va_display (msdk_context);
445
446   if (use_dmabuf)
447     allocator = gst_va_dmabuf_allocator_new (display);
448   else {
449     formats = g_array_new (FALSE, FALSE, sizeof (GstVideoFormat));
450     g_array_append_val (formats, GST_VIDEO_INFO_FORMAT (info));
451     allocator = gst_va_allocator_new (display, formats);
452   }
453   if (!allocator) {
454     GST_ERROR ("Failed to create allocator");
455     if (formats)
456       g_array_unref (formats);
457     return NULL;
458   }
459   aligned_caps = gst_video_info_to_caps (info);
460   pool =
461       gst_va_pool_new_with_config (aligned_caps,
462       GST_VIDEO_INFO_SIZE (info), min_buffers, 0,
463       VA_SURFACE_ATTRIB_USAGE_HINT_GENERIC, GST_VA_FEATURE_AUTO,
464       allocator, &alloc_params);
465
466   gst_object_unref (allocator);
467   gst_caps_unref (aligned_caps);
468
469   return pool;
470 }
471 #else
472 static GstBufferPool *
473 gst_msdk_create_d3d11_pool (GstMsdkVPP * thiz, GstVideoInfo * info,
474     guint num_buffers, gboolean propose)
475 {
476   GstBufferPool *pool = NULL;
477   GstD3D11Device *device;
478   GstStructure *config;
479   GstD3D11AllocationParams *params;
480   GstD3D11Format device_format;
481   guint bind_flags = 0;
482   GstCaps *aligned_caps = NULL;
483   GstVideoInfo aligned_info;
484   gint aligned_width;
485   gint aligned_height;
486
487   device = gst_msdk_context_get_d3d11_device (thiz->context);
488
489   aligned_width = GST_ROUND_UP_16 (info->width);
490   aligned_height = GST_ROUND_UP_32 (info->height);
491
492   gst_video_info_set_interlaced_format (&aligned_info,
493       GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_INTERLACE_MODE (info),
494       aligned_width, aligned_height);
495
496   gst_d3d11_device_get_format (device, GST_VIDEO_INFO_FORMAT (&aligned_info),
497       &device_format);
498   if (!propose
499       && ((device_format.format_support[0] & D3D11_FORMAT_SUPPORT_RENDER_TARGET)
500           == D3D11_FORMAT_SUPPORT_RENDER_TARGET)) {
501     bind_flags = D3D11_BIND_RENDER_TARGET;
502   }
503
504   aligned_caps = gst_video_info_to_caps (&aligned_info);
505
506   pool = gst_d3d11_buffer_pool_new (device);
507   config = gst_buffer_pool_get_config (pool);
508   params = gst_d3d11_allocation_params_new (device, &aligned_info,
509       GST_D3D11_ALLOCATION_FLAG_DEFAULT, bind_flags,
510       D3D11_RESOURCE_MISC_SHARED);
511
512   gst_buffer_pool_config_set_d3d11_allocation_params (config, params);
513   gst_d3d11_allocation_params_free (params);
514   gst_buffer_pool_config_set_params (config, aligned_caps,
515       GST_VIDEO_INFO_SIZE (&aligned_info), num_buffers, 0);
516   gst_buffer_pool_set_config (pool, config);
517
518   gst_caps_unref (aligned_caps);
519   GST_LOG_OBJECT (thiz, "Creating d3d11 pool");
520
521   return pool;
522 }
523 #endif
524
525 static GstBufferPool *
526 gst_msdkvpp_create_buffer_pool (GstMsdkVPP * thiz, GstPadDirection direction,
527     GstCaps * caps, guint min_num_buffers, gboolean propose)
528 {
529   GstBufferPool *pool = NULL;
530   GstStructure *config;
531   GstVideoInfo info;
532   GstVideoInfo *pool_info = NULL;
533   GstVideoAlignment align;
534   gboolean use_dmabuf = FALSE;
535
536   if (direction == GST_PAD_SINK) {
537     pool_info = &thiz->sinkpad_buffer_pool_info;
538     use_dmabuf = thiz->use_sinkpad_dmabuf;
539   } else if (direction == GST_PAD_SRC) {
540     pool_info = &thiz->srcpad_buffer_pool_info;
541     use_dmabuf = thiz->use_srcpad_dmabuf;
542   }
543
544   if (!gst_video_info_from_caps (&info, caps)) {
545     goto error_no_video_info;
546   }
547
548   gst_msdk_set_video_alignment (&info, 0, 0, &align);
549   gst_video_info_align (&info, &align);
550
551 #ifndef _WIN32
552   pool = gst_msdk_create_va_pool (&info, thiz->context, use_dmabuf,
553       min_num_buffers);
554 #else
555   pool = gst_msdk_create_d3d11_pool (thiz, &info, min_num_buffers, propose);
556 #endif
557   if (!thiz->use_video_memory)
558     pool = gst_video_buffer_pool_new ();
559
560   if (!pool)
561     goto error_no_pool;
562
563   config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
564   if (thiz->use_video_memory) {
565     gst_buffer_pool_config_add_option (config,
566         GST_BUFFER_POOL_OPTION_MSDK_USE_VIDEO_MEMORY);
567     if (use_dmabuf)
568       gst_buffer_pool_config_add_option (config,
569           GST_BUFFER_POOL_OPTION_MSDK_USE_DMABUF);
570   }
571
572   gst_buffer_pool_config_set_params (config, caps,
573       GST_VIDEO_INFO_SIZE (&info), min_num_buffers, 0);
574   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
575   gst_buffer_pool_config_add_option (config,
576       GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
577   gst_buffer_pool_config_set_video_alignment (config, &align);
578
579   if (!gst_buffer_pool_set_config (pool, config))
580     goto error_pool_config;
581
582   /* Updating pool_info with info which used to config pool */
583   *pool_info = info;
584
585   return pool;
586
587 error_no_pool:
588   {
589     GST_INFO_OBJECT (thiz, "Failed to create bufferpool");
590     return NULL;
591   }
592 error_no_video_info:
593   {
594     GST_INFO_OBJECT (thiz, "Failed to get Video info from caps");
595     gst_object_unref (pool);
596     return NULL;
597   }
598 error_pool_config:
599   {
600     GST_INFO_OBJECT (thiz, "Failed to set config");
601     gst_object_unref (pool);
602     return NULL;
603   }
604 }
605
606 static gboolean
607 _gst_caps_has_feature (const GstCaps * caps, const gchar * feature)
608 {
609   guint i;
610
611   for (i = 0; i < gst_caps_get_size (caps); i++) {
612     GstCapsFeatures *const features = gst_caps_get_features (caps, i);
613     /* Skip ANY features, we need an exact match for correct evaluation */
614     if (gst_caps_features_is_any (features))
615       continue;
616     if (gst_caps_features_contains (features, feature))
617       return TRUE;
618   }
619   return FALSE;
620 }
621
622 static GstBufferPool *
623 create_src_pool (GstMsdkVPP * thiz, GstQuery * query, GstCaps * caps)
624 {
625   GstBufferPool *pool = NULL;
626   guint size = 0, min_buffers = 0, max_buffers = 0;
627   gboolean update_pool = FALSE;
628   GstAllocator *allocator = NULL;
629   GstAllocationParams params;
630   mfxFrameAllocRequest request;
631
632   /* Check whether the query has pool */
633   if (gst_query_get_n_allocation_pools (query) > 0) {
634     update_pool = TRUE;
635     gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL);
636   }
637   if (pool) {
638     GstStructure *config = NULL;
639     /* get the configured pool properties inorder to set in query */
640     config = gst_buffer_pool_get_config (pool);
641     gst_object_unref (pool);
642
643     gst_buffer_pool_config_get_params (config, &caps, &size, &min_buffers,
644         &max_buffers);
645     if (gst_buffer_pool_config_get_allocator (config, &allocator, &params))
646       gst_query_add_allocation_param (query, allocator, &params);
647     gst_structure_free (config);
648   } else {
649     /* if we have tee after msdkvpp, we will not have pool for src pad,
650        we need assign size for the internal pool
651        gst-launch-1.0 -v videotestsrc  ! msdkvpp ! tee ! msdkh264enc ! fakesink silent=false
652      */
653     min_buffers = SRC_POOL_SIZE_DEFAULT;
654   }
655
656   /* Always create a pool for vpp out buffers. For vpp, we don't use
657    * external mfxFrameAllocator for video-memory allocation. */
658   request = thiz->request[1];
659   min_buffers += thiz->async_depth + request.NumFrameSuggested;
660   request.NumFrameSuggested = min_buffers;
661
662   pool =
663       gst_msdkvpp_create_buffer_pool (thiz, GST_PAD_SRC, caps, min_buffers,
664       FALSE);
665   if (!pool)
666     return NULL;
667   /* we do not support dynamic buffer count change */
668   max_buffers = min_buffers;
669   if (update_pool)
670     gst_query_set_nth_allocation_pool (query, 0, pool, size, min_buffers,
671         max_buffers);
672   else
673     gst_query_add_allocation_pool (query, pool, size, min_buffers, max_buffers);
674
675   return pool;
676 }
677
678 static gboolean
679 gst_msdkvpp_decide_allocation (GstBaseTransform * trans, GstQuery * query)
680 {
681   GstMsdkVPP *thiz = GST_MSDKVPP (trans);
682   GstVideoInfo info;
683   GstCaps *caps;
684
685   gst_query_parse_allocation (query, &caps, NULL);
686   if (!caps) {
687     GST_ERROR_OBJECT (thiz, "Failed to parse the decide_allocation caps");
688     return FALSE;
689   }
690   if (!gst_video_info_from_caps (&info, caps)) {
691     GST_ERROR_OBJECT (thiz, "Failed to get video info");
692     return FALSE;
693   }
694   /* We allocate the memory of type that downstream allocation requests */
695 #ifndef _WIN32
696   if (_gst_caps_has_feature (caps, GST_CAPS_FEATURE_MEMORY_DMABUF)) {
697     GST_INFO_OBJECT (thiz, "MSDK VPP srcpad uses DMABuf memory");
698     thiz->use_srcpad_dmabuf = TRUE;
699   }
700 #endif
701
702   if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL))
703     thiz->add_video_meta = TRUE;
704   else
705     thiz->add_video_meta = FALSE;
706
707   gst_clear_object (&thiz->srcpad_buffer_pool);
708   thiz->srcpad_buffer_pool = create_src_pool (thiz, query, caps);
709   if (!thiz->srcpad_buffer_pool)
710     return FALSE;
711
712   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
713
714   /* Fixme if downstream doesn't have videometa support, msdkvpp should
715    * copy the output buffers */
716
717   return TRUE;
718 }
719
720 static gboolean
721 gst_msdkvpp_propose_allocation (GstBaseTransform * trans,
722     GstQuery * decide_query, GstQuery * query)
723 {
724   GstMsdkVPP *thiz = GST_MSDKVPP (trans);
725   GstVideoInfo info;
726   GstBufferPool *pool = NULL;
727   GstAllocator *allocator = NULL;
728   GstCaps *caps;
729   GstStructure *config;
730   gboolean need_pool;
731   GstAllocationParams params;
732   guint size;
733   guint min_buffers = thiz->async_depth + 1;
734
735   gst_query_parse_allocation (query, &caps, &need_pool);
736   if (!caps) {
737     GST_ERROR_OBJECT (thiz, "Failed to parse the allocation caps");
738     return FALSE;
739   }
740
741   if (!gst_video_info_from_caps (&info, caps)) {
742     GST_ERROR_OBJECT (thiz, "Failed to get video info");
743     return FALSE;
744   }
745
746   /* if upstream allocation query supports dmabuf-capsfeatures,
747    * we do allocate dmabuf backed memory */
748   if (_gst_caps_has_feature (caps, GST_CAPS_FEATURE_MEMORY_DMABUF)) {
749     GST_INFO_OBJECT (thiz, "MSDK VPP srcpad uses DMABuf memory");
750     thiz->use_sinkpad_dmabuf = TRUE;
751   }
752
753   if (need_pool) {
754     /* alwys provide a new pool for upstream to help re-negotiation
755      * more info here: https://bugzilla.gnome.org/show_bug.cgi?id=748344 */
756     pool = gst_msdkvpp_create_buffer_pool (thiz, GST_PAD_SINK, caps,
757         min_buffers, TRUE);
758   }
759
760   /* Update the internal pool if any allocation attribute changed */
761   if (!gst_video_info_is_equal (&thiz->sinkpad_buffer_pool_info, &info)) {
762     gst_object_unref (thiz->sinkpad_buffer_pool);
763     thiz->sinkpad_buffer_pool = gst_msdkvpp_create_buffer_pool (thiz,
764         GST_PAD_SINK, caps, min_buffers, FALSE);
765   }
766
767   /* get the size and allocator params from configured pool and set it in query */
768   if (!need_pool)
769     pool = gst_object_ref (thiz->sinkpad_buffer_pool);
770   config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
771   gst_buffer_pool_config_get_params (config, NULL, &size, NULL, NULL);
772   if (gst_buffer_pool_config_get_allocator (config, &allocator, &params))
773     gst_query_add_allocation_param (query, allocator, &params);
774   gst_structure_free (config);
775
776   /* if upstream doesn't have a pool requirement, set only
777    *  size, min_buffers and max_buffers in query */
778   gst_query_add_allocation_pool (query, need_pool ? pool : NULL, size,
779       min_buffers, 0);
780   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
781
782   gst_object_unref (pool);
783
784   return GST_BASE_TRANSFORM_CLASS (parent_class)->propose_allocation (trans,
785       decide_query, query);
786 }
787
788 static GstMsdkSurface *
789 gst_msdkvpp_get_surface_from_pool (GstMsdkVPP * thiz, GstBufferPool * pool,
790     GstBuffer * buf)
791 {
792   GstBuffer *upload_buf;
793   GstMsdkSurface *msdk_surface = NULL;
794   GstVideoFrame src_frame, dst_frame;
795
796   if (!gst_buffer_pool_is_active (pool) &&
797       !gst_buffer_pool_set_active (pool, TRUE)) {
798     GST_ERROR_OBJECT (pool, "failed to activate buffer pool");
799     return NULL;
800   }
801
802   if (gst_buffer_pool_acquire_buffer (pool, &upload_buf, NULL) != GST_FLOW_OK) {
803     GST_ERROR_OBJECT (pool, "failed to acquire a buffer from pool");
804     return NULL;
805   }
806
807   if (!gst_video_frame_map (&src_frame, &thiz->sinkpad_info, buf, GST_MAP_READ)) {
808     GST_ERROR_OBJECT (thiz, "failed to map the frame for source");
809     gst_buffer_unref (upload_buf);
810     return NULL;
811   }
812
813   if (!gst_video_frame_map (&dst_frame, &thiz->sinkpad_buffer_pool_info,
814           upload_buf, GST_MAP_WRITE)) {
815     GST_ERROR_OBJECT (thiz, "failed to map the frame for destination");
816     gst_video_frame_unmap (&src_frame);
817     gst_buffer_unref (upload_buf);
818     return NULL;
819   }
820
821   for (guint i = 0; i < GST_VIDEO_FRAME_N_PLANES (&src_frame); i++) {
822     guint src_width_in_bytes, src_height;
823     guint dst_width_in_bytes, dst_height;
824     guint width_in_bytes, height;
825     guint src_stride, dst_stride;
826     guint8 *src_data, *dst_data;
827
828     src_width_in_bytes = GST_VIDEO_FRAME_COMP_WIDTH (&src_frame, i) *
829         GST_VIDEO_FRAME_COMP_PSTRIDE (&src_frame, i);
830     src_height = GST_VIDEO_FRAME_COMP_HEIGHT (&src_frame, i);
831     src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&src_frame, i);
832
833     dst_width_in_bytes = GST_VIDEO_FRAME_COMP_WIDTH (&dst_frame, i) *
834         GST_VIDEO_FRAME_COMP_PSTRIDE (&src_frame, i);
835     dst_height = GST_VIDEO_FRAME_COMP_HEIGHT (&src_frame, i);
836     dst_stride = GST_VIDEO_FRAME_COMP_STRIDE (&dst_frame, i);
837
838     width_in_bytes = MIN (src_width_in_bytes, dst_width_in_bytes);
839     height = MIN (src_height, dst_height);
840
841     src_data = (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (&src_frame, i);
842     dst_data = (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (&dst_frame, i);
843
844     for (guint j = 0; j < height; j++) {
845       memcpy (dst_data, src_data, width_in_bytes);
846       dst_data += dst_stride;
847       src_data += src_stride;
848     }
849   }
850
851   gst_video_frame_unmap (&dst_frame);
852   gst_video_frame_unmap (&src_frame);
853
854   if (thiz->use_video_memory) {
855     msdk_surface = gst_msdk_import_to_msdk_surface (upload_buf, thiz->context,
856         &thiz->sinkpad_info, GST_MAP_READ);
857   } else {
858     msdk_surface =
859         gst_msdk_import_sys_mem_to_msdk_surface (upload_buf,
860         thiz->sinkpad_buffer_pool_info);
861   }
862
863   if (msdk_surface)
864     msdk_surface->buf = upload_buf;
865
866   return msdk_surface;
867 }
868
869 static GstMsdkSurface *
870 get_msdk_surface_from_input_buffer (GstMsdkVPP * thiz, GstBuffer * inbuf)
871 {
872   GstMsdkSurface *msdk_surface = NULL;
873
874   if (gst_msdk_is_msdk_buffer (inbuf)) {
875     msdk_surface = g_slice_new0 (GstMsdkSurface);
876     msdk_surface->surface = gst_msdk_get_surface_from_buffer (inbuf);
877     msdk_surface->buf = gst_buffer_ref (inbuf);
878     return msdk_surface;
879   }
880
881   msdk_surface = gst_msdk_import_to_msdk_surface (inbuf, thiz->context,
882       &thiz->sinkpad_info, GST_MAP_READ);
883   if (msdk_surface) {
884     msdk_surface->buf = gst_buffer_ref (inbuf);
885     return msdk_surface;
886   }
887
888   /* If upstream hasn't accpeted the proposed msdk bufferpool,
889    * just copy frame to msdk buffer and take a surface from it.
890    */
891
892   return gst_msdkvpp_get_surface_from_pool (thiz, thiz->sinkpad_buffer_pool,
893       inbuf);
894 }
895
896 static GstFlowReturn
897 gst_msdkvpp_transform (GstBaseTransform * trans, GstBuffer * inbuf,
898     GstBuffer * outbuf)
899 {
900   GstMsdkVPP *thiz = GST_MSDKVPP (trans);
901   GstClockTime timestamp;
902   GstFlowReturn ret = GST_FLOW_OK;
903   mfxSession session;
904   mfxSyncPoint sync_point = NULL;
905   mfxStatus status;
906   mfxFrameInfo *in_info = NULL;
907   GstMsdkSurface *in_surface = NULL;
908   GstMsdkSurface *out_surface = NULL;
909   GstBuffer *outbuf_new = NULL;
910   gboolean locked_by_others;
911   gboolean create_new_surface = FALSE;
912
913   free_unlocked_msdk_surfaces (thiz);
914
915   in_surface = get_msdk_surface_from_input_buffer (thiz, inbuf);
916   if (!in_surface)
917     return GST_FLOW_ERROR;
918
919   if (!in_surface->surface) {
920     GST_ERROR_OBJECT (thiz, "mfx surface is NULL for the current input buffer");
921     free_msdk_surface (in_surface);
922     return GST_FLOW_ERROR;
923   }
924   locked_by_others = ! !in_surface->surface->Data.Locked;
925
926   /* always convert timestamp of input surface as msdk timestamp */
927   if (inbuf->pts == GST_CLOCK_TIME_NONE)
928     in_surface->surface->Data.TimeStamp = MFX_TIMESTAMP_UNKNOWN;
929   else
930     in_surface->surface->Data.TimeStamp =
931         gst_util_uint64_scale_round (inbuf->pts, 90000, GST_SECOND);
932
933   if (gst_msdk_is_msdk_buffer (outbuf)) {
934     out_surface = g_slice_new0 (GstMsdkSurface);
935     out_surface->surface = gst_msdk_get_surface_from_buffer (outbuf);
936   } else {
937     out_surface = gst_msdk_import_to_msdk_surface (outbuf, thiz->context,
938         &thiz->srcpad_info, GST_MAP_WRITE);
939     if (!thiz->use_video_memory) {
940       out_surface =
941           gst_msdk_import_sys_mem_to_msdk_surface (outbuf, thiz->srcpad_info);
942     }
943     if (out_surface)
944       out_surface->buf = gst_buffer_ref (outbuf);
945     else {
946       GST_ERROR_OBJECT (thiz, "Failed to get msdk outsurface!");
947       free_msdk_surface (in_surface);
948       return GST_FLOW_ERROR;
949     }
950   }
951
952   /* update surface crop info (NOTE: msdk min frame size is 2x2) */
953   in_info = &in_surface->surface->Info;
954   if ((thiz->crop_left + thiz->crop_right >= in_info->CropW - 1)
955       || (thiz->crop_top + thiz->crop_bottom >= in_info->CropH - 1)) {
956     GST_WARNING_OBJECT (thiz, "ignoring crop... cropping too much!");
957   } else if (!in_surface->from_qdata) {
958     /* We only fill crop info when it is a new surface.
959      * If the surface is a cached one, it already has crop info,
960      * and we should avoid updating again.
961      */
962     in_info->CropX = thiz->crop_left;
963     in_info->CropY = thiz->crop_top;
964     in_info->CropW -= thiz->crop_left + thiz->crop_right;
965     in_info->CropH -= thiz->crop_top + thiz->crop_bottom;
966   }
967
968   session = gst_msdk_context_get_session (thiz->context);
969
970   /* outer loop is for handling FrameRate Control and deinterlace use cases */
971   do {
972     for (;;) {
973       status =
974           MFXVideoVPP_RunFrameVPPAsync (session, in_surface->surface,
975           out_surface->surface, NULL, &sync_point);
976       timestamp = out_surface->surface->Data.TimeStamp;
977
978       if (status != MFX_WRN_DEVICE_BUSY)
979         break;
980       /* If device is busy, wait 1ms and retry, as per MSDK's recommendation */
981       g_usleep (1000);
982     }
983
984     if (timestamp == MFX_TIMESTAMP_UNKNOWN)
985       timestamp = GST_CLOCK_TIME_NONE;
986     else
987       timestamp = gst_util_uint64_scale_round (timestamp, GST_SECOND, 90000);
988
989     if (status == MFX_WRN_INCOMPATIBLE_VIDEO_PARAM)
990       GST_WARNING_OBJECT (thiz, "VPP returned: %s",
991           msdk_status_to_string (status));
992     else if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA
993         && status != MFX_ERR_MORE_SURFACE)
994       goto vpp_error;
995
996     /* No output generated */
997     if (status == MFX_ERR_MORE_DATA)
998       goto error_more_data;
999
1000     /* Wait for vpp operation to complete, the magic number 300000 below
1001      * is used in MSDK samples
1002      * #define MSDK_VPP_WAIT_INTERVAL 300000
1003      */
1004     if (sync_point &&
1005         MFXVideoCORE_SyncOperation (session, sync_point,
1006             300000) != MFX_ERR_NONE)
1007       GST_WARNING_OBJECT (thiz, "failed to do sync operation");
1008     /* push new output buffer forward after sync operation */
1009     if (create_new_surface) {
1010       create_new_surface = FALSE;
1011       ret = gst_pad_push (GST_BASE_TRANSFORM_SRC_PAD (trans), outbuf_new);
1012       if (ret != GST_FLOW_OK)
1013         goto error_push_buffer;
1014     }
1015
1016     /* More than one output buffers are generated */
1017     if (status == MFX_ERR_MORE_SURFACE) {
1018       outbuf_new = create_output_buffer (thiz);
1019       GST_BUFFER_TIMESTAMP (outbuf_new) = timestamp;
1020       GST_BUFFER_DURATION (outbuf_new) = thiz->buffer_duration;
1021
1022       if (gst_msdk_is_msdk_buffer (outbuf_new)) {
1023         release_out_surface (thiz, out_surface);
1024         out_surface = g_slice_new0 (GstMsdkSurface);
1025         out_surface->surface = gst_msdk_get_surface_from_buffer (outbuf_new);
1026         create_new_surface = TRUE;
1027       } else {
1028         release_out_surface (thiz, out_surface);
1029         out_surface =
1030             gst_msdk_import_to_msdk_surface (outbuf_new, thiz->context,
1031             &thiz->srcpad_buffer_pool_info, GST_MAP_WRITE);
1032         if (!thiz->use_video_memory) {
1033           out_surface =
1034               gst_msdk_import_sys_mem_to_msdk_surface (outbuf_new,
1035               thiz->srcpad_buffer_pool_info);
1036         }
1037         if (out_surface) {
1038           out_surface->buf = gst_buffer_ref (outbuf_new);
1039           create_new_surface = TRUE;
1040         } else {
1041           GST_ERROR_OBJECT (thiz, "Failed to get msdk outsurface!");
1042           release_in_surface (thiz, in_surface, locked_by_others);
1043           return GST_FLOW_ERROR;
1044         }
1045       }
1046     } else {
1047       GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
1048       GST_BUFFER_DURATION (outbuf) = thiz->buffer_duration;
1049     }
1050   } while (status == MFX_ERR_MORE_SURFACE);
1051
1052   goto transform_end;
1053
1054 vpp_error:
1055   GST_ERROR_OBJECT (thiz, "MSDK Failed to do VPP");
1056   ret = GST_FLOW_ERROR;
1057   goto transform_end;
1058
1059 error_more_data:
1060   GST_WARNING_OBJECT (thiz,
1061       "MSDK Requires additional input for processing, "
1062       "Retruning FLOW_DROPPED since no output buffer was generated");
1063   ret = GST_BASE_TRANSFORM_FLOW_DROPPED;
1064   goto transform_end;
1065
1066 error_push_buffer:
1067   GST_DEBUG_OBJECT (thiz, "failed to push output buffer: %s",
1068       gst_flow_get_name (ret));
1069
1070 transform_end:
1071   release_in_surface (thiz, in_surface, locked_by_others);
1072   release_out_surface (thiz, out_surface);
1073
1074   return ret;
1075 }
1076
1077 static void
1078 gst_msdkvpp_close (GstMsdkVPP * thiz)
1079 {
1080   mfxStatus status;
1081
1082   if (!thiz->context)
1083     return;
1084
1085   GST_DEBUG_OBJECT (thiz, "Closing VPP 0x%p", thiz->context);
1086   status = MFXVideoVPP_Close (gst_msdk_context_get_session (thiz->context));
1087   if (status != MFX_ERR_NONE && status != MFX_ERR_NOT_INITIALIZED) {
1088     GST_WARNING_OBJECT (thiz, "VPP close failed (%s)",
1089         msdk_status_to_string (status));
1090   }
1091   free_all_msdk_surfaces (thiz);
1092
1093   gst_clear_object (&thiz->context);
1094
1095   memset (&thiz->param, 0, sizeof (thiz->param));
1096
1097   gst_clear_object (&thiz->sinkpad_buffer_pool);
1098   gst_clear_object (&thiz->srcpad_buffer_pool);
1099
1100   thiz->buffer_duration = GST_CLOCK_TIME_NONE;
1101   gst_video_info_init (&thiz->sinkpad_info);
1102   gst_video_info_init (&thiz->srcpad_info);
1103 }
1104
1105 static void
1106 ensure_filters (GstMsdkVPP * thiz)
1107 {
1108   /* Denoise */
1109   if (thiz->flags & GST_MSDK_FLAG_DENOISE) {
1110     mfxExtVPPDenoise *mfx_denoise = &thiz->mfx_denoise;
1111     mfx_denoise->Header.BufferId = MFX_EXTBUFF_VPP_DENOISE;
1112     mfx_denoise->Header.BufferSz = sizeof (mfxExtVPPDenoise);
1113     mfx_denoise->DenoiseFactor = thiz->denoise_factor;
1114     gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_denoise);
1115   }
1116
1117   /* Rotation */
1118   if (thiz->rotation != MFX_ANGLE_0) {
1119     mfxExtVPPRotation *mfx_rotation = &thiz->mfx_rotation;
1120     mfx_rotation->Header.BufferId = MFX_EXTBUFF_VPP_ROTATION;
1121     mfx_rotation->Header.BufferSz = sizeof (mfxExtVPPRotation);
1122     mfx_rotation->Angle = thiz->rotation;
1123     gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_rotation);
1124   }
1125
1126   /* Deinterlace */
1127   if (thiz->flags & GST_MSDK_FLAG_DEINTERLACE) {
1128     mfxExtVPPDeinterlacing *mfx_deinterlace = &thiz->mfx_deinterlace;
1129     mfx_deinterlace->Header.BufferId = MFX_EXTBUFF_VPP_DEINTERLACING;
1130     mfx_deinterlace->Header.BufferSz = sizeof (mfxExtVPPDeinterlacing);
1131     mfx_deinterlace->Mode = thiz->deinterlace_method;
1132     gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_deinterlace);
1133   }
1134
1135   /* Colorbalance(ProcAmp) */
1136   if (thiz->flags & (GST_MSDK_FLAG_HUE | GST_MSDK_FLAG_SATURATION |
1137           GST_MSDK_FLAG_BRIGHTNESS | GST_MSDK_FLAG_CONTRAST)) {
1138     mfxExtVPPProcAmp *mfx_procamp = &thiz->mfx_procamp;
1139     mfx_procamp->Header.BufferId = MFX_EXTBUFF_VPP_PROCAMP;
1140     mfx_procamp->Header.BufferSz = sizeof (mfxExtVPPProcAmp);
1141     mfx_procamp->Hue = thiz->hue;
1142     mfx_procamp->Saturation = thiz->saturation;
1143     mfx_procamp->Brightness = thiz->brightness;
1144     mfx_procamp->Contrast = thiz->contrast;
1145     gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_procamp);
1146   }
1147
1148   /* Detail/Edge enhancement */
1149   if (thiz->flags & GST_MSDK_FLAG_DETAIL) {
1150     mfxExtVPPDetail *mfx_detail = &thiz->mfx_detail;
1151     mfx_detail->Header.BufferId = MFX_EXTBUFF_VPP_DETAIL;
1152     mfx_detail->Header.BufferSz = sizeof (mfxExtVPPDetail);
1153     mfx_detail->DetailFactor = thiz->detail;
1154     gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_detail);
1155   }
1156
1157   /* Mirroring */
1158   if (thiz->mirroring != MFX_MIRRORING_DISABLED) {
1159     mfxExtVPPMirroring *mfx_mirroring = &thiz->mfx_mirroring;
1160     mfx_mirroring->Header.BufferId = MFX_EXTBUFF_VPP_MIRRORING;
1161     mfx_mirroring->Header.BufferSz = sizeof (mfxExtVPPMirroring);
1162     mfx_mirroring->Type = thiz->mirroring;
1163     gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_mirroring);
1164   }
1165
1166   /* Scaling Mode */
1167   if (thiz->flags & GST_MSDK_FLAG_SCALING_MODE) {
1168     mfxExtVPPScaling *mfx_scaling = &thiz->mfx_scaling;
1169     mfx_scaling->Header.BufferId = MFX_EXTBUFF_VPP_SCALING;
1170     mfx_scaling->Header.BufferSz = sizeof (mfxExtVPPScaling);
1171     mfx_scaling->ScalingMode = thiz->scaling_mode;
1172     gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_scaling);
1173   }
1174
1175   /* FRC */
1176   if (thiz->flags & GST_MSDK_FLAG_FRC) {
1177     mfxExtVPPFrameRateConversion *mfx_frc = &thiz->mfx_frc;
1178     mfx_frc->Header.BufferId = MFX_EXTBUFF_VPP_FRAME_RATE_CONVERSION;
1179     mfx_frc->Header.BufferSz = sizeof (mfxExtVPPFrameRateConversion);
1180     mfx_frc->Algorithm = thiz->frc_algm;
1181     gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_frc);
1182   }
1183 }
1184
1185 static void
1186 gst_msdkvpp_set_passthrough (GstMsdkVPP * thiz)
1187 {
1188   gboolean passthrough = TRUE;
1189
1190   /* no passthrough if any of the filter algorithm is enabled */
1191   if (thiz->flags)
1192     passthrough = FALSE;
1193
1194   /* vpp could be needed in some specific circumstances, for eg:
1195    * input surface is dmabuf and output must be videomemory. So far
1196    * the underline iHD driver doesn't seems to support dmabuf mapping,
1197    * so we could explicitly ask msdkvpp to provide non-dambuf videomemory
1198    * surfaces as output thourgh capsfileters */
1199   if (thiz->need_vpp)
1200     passthrough = FALSE;
1201
1202   /* no passthrough if there is change in out width,height or format */
1203   if (GST_VIDEO_INFO_WIDTH (&thiz->sinkpad_info) !=
1204       GST_VIDEO_INFO_WIDTH (&thiz->srcpad_info)
1205       || GST_VIDEO_INFO_HEIGHT (&thiz->sinkpad_info) !=
1206       GST_VIDEO_INFO_HEIGHT (&thiz->srcpad_info)
1207       || GST_VIDEO_INFO_FORMAT (&thiz->sinkpad_info) !=
1208       GST_VIDEO_INFO_FORMAT (&thiz->srcpad_info))
1209     passthrough = FALSE;
1210
1211   gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (thiz), passthrough);
1212 }
1213
1214 static gboolean
1215 gst_msdkvpp_initialize (GstMsdkVPP * thiz)
1216 {
1217   mfxSession session;
1218   mfxStatus status;
1219   mfxFrameAllocRequest *request = &thiz->request[0];
1220
1221   if (!thiz->context) {
1222     GST_WARNING_OBJECT (thiz, "No MSDK Context");
1223     return FALSE;
1224   }
1225
1226   GST_OBJECT_LOCK (thiz);
1227   session = gst_msdk_context_get_session (thiz->context);
1228
1229   /* Close the current session if the session has been initialized,
1230    * otherwise the subsequent function call of MFXVideoVPP_Init() will
1231    * fail
1232    */
1233   if (thiz->initialized) {
1234     MFXVideoVPP_Close (session);
1235
1236     memset (&thiz->param, 0, sizeof (thiz->param));
1237     memset (&thiz->extra_params, 0, sizeof (thiz->extra_params));
1238     thiz->num_extra_params = 0;
1239   }
1240
1241   if (thiz->use_video_memory) {
1242     gst_msdk_set_frame_allocator (thiz->context);
1243     thiz->param.IOPattern =
1244         MFX_IOPATTERN_IN_VIDEO_MEMORY | MFX_IOPATTERN_OUT_VIDEO_MEMORY;
1245   } else {
1246     thiz->param.IOPattern =
1247         MFX_IOPATTERN_IN_SYSTEM_MEMORY | MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
1248   }
1249
1250   /* update input video attributes */
1251   gst_msdk_set_mfx_frame_info_from_video_info (&thiz->param.vpp.In,
1252       &thiz->sinkpad_info);
1253
1254   /* update output video attributes, only CSC and Scaling are supported for now */
1255   gst_msdk_set_mfx_frame_info_from_video_info (&thiz->param.vpp.Out,
1256       &thiz->srcpad_info);
1257
1258   /* use msdk frame rarte control if there is a mismatch in In & OUt fps  */
1259   if (GST_VIDEO_INFO_FPS_N (&thiz->srcpad_info) &&
1260       (GST_VIDEO_INFO_FPS_N (&thiz->sinkpad_info) !=
1261           GST_VIDEO_INFO_FPS_N (&thiz->srcpad_info)
1262           || GST_VIDEO_INFO_FPS_D (&thiz->sinkpad_info) !=
1263           GST_VIDEO_INFO_FPS_D (&thiz->srcpad_info))) {
1264     thiz->flags |= GST_MSDK_FLAG_FRC;
1265     /* manually set distributed timestamp as frc algorithm
1266      * as it is more resonable for framerate conversion
1267      */
1268     thiz->frc_algm = MFX_FRCALGM_DISTRIBUTED_TIMESTAMP;
1269   }
1270
1271   /* work-around to avoid zero fps in msdk structure */
1272   if (!thiz->param.vpp.In.FrameRateExtN)
1273     thiz->param.vpp.In.FrameRateExtN = 30;
1274   if (!thiz->param.vpp.Out.FrameRateExtN)
1275     thiz->param.vpp.Out.FrameRateExtN = thiz->param.vpp.In.FrameRateExtN;
1276
1277   /* set vpp out picstruct as progressive if deinterlacing enabled */
1278   if (thiz->flags & GST_MSDK_FLAG_DEINTERLACE)
1279     thiz->param.vpp.Out.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
1280
1281   /* Enable the required filters */
1282   ensure_filters (thiz);
1283
1284   /* Add extended buffers */
1285   if (thiz->num_extra_params) {
1286     thiz->param.NumExtParam = thiz->num_extra_params;
1287     thiz->param.ExtParam = thiz->extra_params;
1288   }
1289
1290   /* validate parameters and allow MFX to make adjustments */
1291   status = MFXVideoVPP_Query (session, &thiz->param, &thiz->param);
1292   if (status < MFX_ERR_NONE) {
1293     GST_ERROR_OBJECT (thiz, "Video VPP Query failed (%s)",
1294         msdk_status_to_string (status));
1295     goto no_vpp;
1296   } else if (status > MFX_ERR_NONE) {
1297     GST_WARNING_OBJECT (thiz, "Video VPP Query returned: %s",
1298         msdk_status_to_string (status));
1299   }
1300
1301   status = MFXVideoVPP_QueryIOSurf (session, &thiz->param, request);
1302   if (status < MFX_ERR_NONE) {
1303     GST_ERROR_OBJECT (thiz, "VPP Query IO surfaces failed (%s)",
1304         msdk_status_to_string (status));
1305     goto no_vpp;
1306   } else if (status > MFX_ERR_NONE) {
1307     GST_WARNING_OBJECT (thiz, "VPP Query IO surfaces returned: %s",
1308         msdk_status_to_string (status));
1309   }
1310
1311   if (thiz->use_video_memory) {
1312     /* Input surface pool pre-allocation */
1313     request[0].Type |= MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET;
1314     if (thiz->use_sinkpad_dmabuf)
1315       request[0].Type |= MFX_MEMTYPE_EXPORT_FRAME;
1316
1317     /* Output surface pool pre-allocation */
1318     request[1].Type |= MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET;
1319     if (thiz->use_srcpad_dmabuf)
1320       request[1].Type |= MFX_MEMTYPE_EXPORT_FRAME;
1321   }
1322
1323   thiz->in_num_surfaces = request[0].NumFrameSuggested;
1324
1325   status = MFXVideoVPP_Init (session, &thiz->param);
1326   if (status < MFX_ERR_NONE) {
1327     GST_ERROR_OBJECT (thiz, "Init failed (%s)", msdk_status_to_string (status));
1328     goto no_vpp;
1329   } else if (status > MFX_ERR_NONE) {
1330     GST_WARNING_OBJECT (thiz, "Init returned: %s",
1331         msdk_status_to_string (status));
1332   }
1333
1334   thiz->initialized = TRUE;
1335   GST_OBJECT_UNLOCK (thiz);
1336   return TRUE;
1337
1338 no_vpp:
1339   GST_OBJECT_UNLOCK (thiz);
1340   gst_clear_object (&thiz->context);
1341   return FALSE;
1342 }
1343
1344 static gboolean
1345 gst_msdkvpp_set_caps (GstBaseTransform * trans, GstCaps * caps,
1346     GstCaps * out_caps)
1347 {
1348   GstMsdkVPP *thiz = GST_MSDKVPP (trans);
1349   GstVideoInfo in_info, out_info;
1350   gboolean sinkpad_info_changed = FALSE;
1351   gboolean srcpad_info_changed = FALSE;
1352   gboolean deinterlace;
1353
1354   if (!gst_caps_features_is_equal (gst_caps_get_features (caps, 0),
1355           gst_caps_get_features (out_caps, 0)))
1356     thiz->need_vpp = 1;
1357
1358   if (!gst_video_info_from_caps (&in_info, caps))
1359     goto error_no_video_info;
1360   if (!gst_video_info_from_caps (&out_info, out_caps))
1361     goto error_no_video_info;
1362
1363   if (!gst_video_info_is_equal (&in_info, &thiz->sinkpad_info))
1364     sinkpad_info_changed = TRUE;
1365   if (!gst_video_info_is_equal (&out_info, &thiz->srcpad_info))
1366     srcpad_info_changed = TRUE;
1367
1368   if (!sinkpad_info_changed && !srcpad_info_changed && thiz->initialized)
1369     return TRUE;
1370
1371   thiz->sinkpad_info = in_info;
1372   thiz->srcpad_info = out_info;
1373
1374   thiz->use_video_memory = TRUE;
1375
1376   /* check for deinterlace requirement */
1377   deinterlace = gst_msdkvpp_is_deinterlace_enabled (thiz, &in_info);
1378   if (deinterlace)
1379     thiz->flags |= GST_MSDK_FLAG_DEINTERLACE;
1380
1381   thiz->buffer_duration = GST_VIDEO_INFO_FPS_N (&out_info) > 0 ?
1382       gst_util_uint64_scale (GST_SECOND, GST_VIDEO_INFO_FPS_D (&out_info),
1383       GST_VIDEO_INFO_FPS_N (&out_info)) : 0;
1384
1385   if (!gst_msdkvpp_initialize (thiz))
1386     return FALSE;
1387
1388   /* set passthrough according to filter operation change */
1389   gst_msdkvpp_set_passthrough (thiz);
1390
1391   /* Ensure sinkpad buffer pool */
1392   if (thiz->sinkpad_buffer_pool)
1393     gst_object_unref (thiz->sinkpad_buffer_pool);
1394
1395   thiz->sinkpad_buffer_pool =
1396       gst_msdkvpp_create_buffer_pool (thiz, GST_PAD_SINK, caps,
1397       thiz->in_num_surfaces, FALSE);
1398   if (!thiz->sinkpad_buffer_pool) {
1399     GST_ERROR_OBJECT (thiz, "Failed to ensure the sinkpad buffer pool");
1400     return FALSE;
1401   }
1402
1403   return TRUE;
1404
1405 error_no_video_info:
1406   GST_ERROR_OBJECT (thiz, "Failed to get video info from caps");
1407   return FALSE;
1408 }
1409
1410 static gboolean
1411 pad_accept_memory (GstMsdkVPP * thiz, const gchar * mem_type,
1412     GstPadDirection direction, GstCaps * filter)
1413 {
1414   gboolean ret = FALSE;
1415   GstCaps *caps, *out_caps;
1416   GstPad *pad;
1417   GstBaseTransform *trans = GST_BASE_TRANSFORM (thiz);
1418
1419   if (direction == GST_PAD_SRC)
1420     pad = GST_BASE_TRANSFORM_SRC_PAD (trans);
1421   else
1422     pad = GST_BASE_TRANSFORM_SINK_PAD (trans);
1423
1424   /* make a copy of filter caps since we need to alter the structure
1425    * by adding dmabuf-capsfeatures */
1426   caps = gst_caps_copy (filter);
1427   gst_caps_set_features (caps, 0, gst_caps_features_from_string (mem_type));
1428
1429   out_caps = gst_pad_peer_query_caps (pad, caps);
1430   if (!out_caps)
1431     goto done;
1432
1433   if (gst_caps_is_any (out_caps) || gst_caps_is_empty (out_caps)
1434       || out_caps == caps)
1435     goto done;
1436
1437   if (_gst_caps_has_feature (out_caps, mem_type))
1438     ret = TRUE;
1439 done:
1440   if (caps)
1441     gst_caps_unref (caps);
1442   if (out_caps)
1443     gst_caps_unref (out_caps);
1444   return ret;
1445 }
1446
1447 static GstCaps *
1448 gst_msdkvpp_fixate_caps (GstBaseTransform * trans,
1449     GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
1450 {
1451   GstMsdkVPP *thiz = GST_MSDKVPP (trans);
1452   GstCaps *result = NULL;
1453   gboolean *use_dmabuf;
1454
1455   if (direction == GST_PAD_SRC) {
1456     result = gst_caps_fixate (result);
1457     use_dmabuf = &thiz->use_sinkpad_dmabuf;
1458   } else {
1459     /*
1460      * Override mirroring & rotation properties once video-direction
1461      * is set explicitly
1462      */
1463     if (thiz->flags & GST_MSDK_FLAG_VIDEO_DIRECTION)
1464       gst_msdk_get_mfx_video_orientation_from_video_direction
1465           (thiz->video_direction, &thiz->mirroring, &thiz->rotation);
1466
1467     result = gst_msdkvpp_fixate_srccaps (thiz, caps, othercaps);
1468     use_dmabuf = &thiz->use_srcpad_dmabuf;
1469   }
1470
1471   GST_DEBUG_OBJECT (trans, "fixated to %" GST_PTR_FORMAT, result);
1472   gst_caps_unref (othercaps);
1473
1474   /* We let msdkvpp srcpad first query if downstream has va memory type caps,
1475    * if not, will check the type of dma memory.
1476    */
1477 #ifndef _WIN32
1478   if (pad_accept_memory (thiz, GST_CAPS_FEATURE_MEMORY_VA,
1479           direction == GST_PAD_SRC ? GST_PAD_SINK : GST_PAD_SRC, result)) {
1480     gst_caps_set_features (result, 0,
1481         gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_VA, NULL));
1482   } else if (pad_accept_memory (thiz, GST_CAPS_FEATURE_MEMORY_DMABUF,
1483           direction == GST_PAD_SRC ? GST_PAD_SINK : GST_PAD_SRC, result)) {
1484     gst_caps_set_features (result, 0,
1485         gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_DMABUF, NULL));
1486     *use_dmabuf = TRUE;
1487   }
1488 #else
1489   if (pad_accept_memory (thiz, GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY,
1490           direction == GST_PAD_SRC ? GST_PAD_SINK : GST_PAD_SRC, result)) {
1491     gst_caps_set_features (result, 0,
1492         gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, NULL));
1493   }
1494 #endif
1495
1496   return result;
1497 }
1498
1499 /* Generic code for now, requires changes in future when we
1500  * add hardware query for supported formats, Framerate control etc */
1501 static GstCaps *
1502 gst_msdkvpp_transform_caps (GstBaseTransform * trans,
1503     GstPadDirection direction, GstCaps * caps, GstCaps * filter)
1504 {
1505   GstCaps *out_caps;
1506
1507   GST_DEBUG_OBJECT (trans,
1508       "Transforming caps %" GST_PTR_FORMAT " in direction %s", caps,
1509       (direction == GST_PAD_SINK) ? "sink" : "src");
1510
1511   if (direction == GST_PAD_SRC)
1512     out_caps = gst_static_pad_template_get_caps (&gst_msdkvpp_sink_factory);
1513   else
1514     out_caps = gst_static_pad_template_get_caps (&gst_msdkvpp_src_factory);
1515
1516   if (out_caps && filter) {
1517     GstCaps *intersection;
1518
1519     intersection = gst_caps_intersect_full (out_caps, filter,
1520         GST_CAPS_INTERSECT_FIRST);
1521     gst_caps_unref (out_caps);
1522     out_caps = intersection;
1523   }
1524
1525   GST_DEBUG_OBJECT (trans, "returning caps: %" GST_PTR_FORMAT, out_caps);
1526   return out_caps;
1527 }
1528
1529 static gboolean
1530 gst_msdkvpp_start (GstBaseTransform * trans)
1531 {
1532   if (!ensure_context (trans))
1533     return FALSE;
1534   return TRUE;
1535 }
1536
1537 static gboolean
1538 gst_msdkvpp_stop (GstBaseTransform * trans)
1539 {
1540   gst_msdkvpp_close (GST_MSDKVPP (trans));
1541   return TRUE;
1542 }
1543
1544 static gboolean
1545 gst_msdkvpp_query (GstBaseTransform * trans, GstPadDirection direction,
1546     GstQuery * query)
1547 {
1548   GstMsdkVPP *thiz = GST_MSDKVPP (trans);
1549   gboolean ret = FALSE;
1550
1551   switch (GST_QUERY_TYPE (query)) {
1552     case GST_QUERY_CONTEXT:{
1553       GstMsdkContext *msdk_context = NULL;
1554
1555       gst_object_replace ((GstObject **) & msdk_context,
1556           (GstObject *) thiz->context);
1557       ret = gst_msdk_handle_context_query (GST_ELEMENT_CAST (trans),
1558           query, msdk_context);
1559       gst_clear_object (&msdk_context);
1560       break;
1561     }
1562     default:
1563       ret = GST_BASE_TRANSFORM_CLASS (parent_class)->query (trans,
1564           direction, query);
1565       break;
1566   }
1567
1568   return ret;
1569 }
1570
1571 static void
1572 gst_msdkvpp_set_property (GObject * object, guint prop_id,
1573     const GValue * value, GParamSpec * pspec)
1574 {
1575   GstMsdkVPP *thiz = GST_MSDKVPP (object);
1576
1577   switch (prop_id) {
1578     case PROP_HARDWARE:
1579       thiz->hardware = g_value_get_boolean (value);
1580       break;
1581     case PROP_ASYNC_DEPTH:
1582       thiz->async_depth = g_value_get_uint (value);
1583       break;
1584     case PROP_DENOISE:
1585       thiz->denoise_factor = g_value_get_uint (value);
1586       thiz->flags |= GST_MSDK_FLAG_DENOISE;
1587       break;
1588 #ifndef GST_REMOVE_DEPRECATED
1589     case PROP_ROTATION:
1590       thiz->rotation = g_value_get_enum (value);
1591       thiz->flags |= GST_MSDK_FLAG_ROTATION;
1592       break;
1593     case PROP_MIRRORING:
1594       thiz->mirroring = g_value_get_enum (value);
1595       thiz->flags |= GST_MSDK_FLAG_MIRRORING;
1596       break;
1597 #endif
1598     case PROP_DEINTERLACE_MODE:
1599       thiz->deinterlace_mode = g_value_get_enum (value);
1600       break;
1601     case PROP_DEINTERLACE_METHOD:
1602       thiz->deinterlace_method = g_value_get_enum (value);
1603       break;
1604     case PROP_HUE:
1605       thiz->hue = g_value_get_float (value);
1606       thiz->flags |= GST_MSDK_FLAG_HUE;
1607       break;
1608     case PROP_SATURATION:
1609       thiz->saturation = g_value_get_float (value);
1610       thiz->flags |= GST_MSDK_FLAG_SATURATION;
1611       break;
1612     case PROP_BRIGHTNESS:
1613       thiz->brightness = g_value_get_float (value);
1614       thiz->flags |= GST_MSDK_FLAG_BRIGHTNESS;
1615       break;
1616     case PROP_CONTRAST:
1617       thiz->contrast = g_value_get_float (value);
1618       thiz->flags |= GST_MSDK_FLAG_CONTRAST;
1619       break;
1620     case PROP_DETAIL:
1621       thiz->detail = g_value_get_uint (value);
1622       thiz->flags |= GST_MSDK_FLAG_DETAIL;
1623       break;
1624     case PROP_SCALING_MODE:
1625       thiz->scaling_mode = g_value_get_enum (value);
1626       thiz->flags |= GST_MSDK_FLAG_SCALING_MODE;
1627       break;
1628     case PROP_FORCE_ASPECT_RATIO:
1629       thiz->keep_aspect = g_value_get_boolean (value);
1630       break;
1631     case PROP_FRC_ALGORITHM:
1632       thiz->frc_algm = g_value_get_enum (value);
1633       break;
1634     case PROP_VIDEO_DIRECTION:
1635       thiz->video_direction = g_value_get_enum (value);
1636       thiz->flags |= GST_MSDK_FLAG_VIDEO_DIRECTION;
1637       break;
1638     case PROP_CROP_LEFT:
1639       thiz->crop_left = g_value_get_uint (value);
1640       break;
1641     case PROP_CROP_RIGHT:
1642       thiz->crop_right = g_value_get_uint (value);
1643       break;
1644     case PROP_CROP_TOP:
1645       thiz->crop_top = g_value_get_uint (value);
1646       break;
1647     case PROP_CROP_BOTTOM:
1648       thiz->crop_bottom = g_value_get_uint (value);
1649       break;
1650     default:
1651       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1652       break;
1653   }
1654 }
1655
1656 static void
1657 gst_msdkvpp_get_property (GObject * object, guint prop_id,
1658     GValue * value, GParamSpec * pspec)
1659 {
1660   GstMsdkVPP *thiz = GST_MSDKVPP (object);
1661
1662   switch (prop_id) {
1663     case PROP_HARDWARE:
1664       g_value_set_boolean (value, thiz->hardware);
1665       break;
1666     case PROP_ASYNC_DEPTH:
1667       g_value_set_uint (value, thiz->async_depth);
1668       break;
1669     case PROP_DENOISE:
1670       g_value_set_uint (value, thiz->denoise_factor);
1671       break;
1672 #ifndef GST_REMOVE_DEPRECATED
1673     case PROP_ROTATION:
1674       g_value_set_enum (value, thiz->rotation);
1675       break;
1676     case PROP_MIRRORING:
1677       g_value_set_enum (value, thiz->mirroring);
1678       break;
1679 #endif
1680     case PROP_DEINTERLACE_MODE:
1681       g_value_set_enum (value, thiz->deinterlace_mode);
1682       break;
1683     case PROP_DEINTERLACE_METHOD:
1684       g_value_set_enum (value, thiz->deinterlace_method);
1685       break;
1686     case PROP_HUE:
1687       g_value_set_float (value, thiz->hue);
1688       break;
1689     case PROP_SATURATION:
1690       g_value_set_float (value, thiz->saturation);
1691       break;
1692     case PROP_BRIGHTNESS:
1693       g_value_set_float (value, thiz->brightness);
1694       break;
1695     case PROP_CONTRAST:
1696       g_value_set_float (value, thiz->contrast);
1697       break;
1698     case PROP_DETAIL:
1699       g_value_set_uint (value, thiz->detail);
1700       break;
1701     case PROP_SCALING_MODE:
1702       g_value_set_enum (value, thiz->scaling_mode);
1703       break;
1704     case PROP_FORCE_ASPECT_RATIO:
1705       g_value_set_boolean (value, thiz->keep_aspect);
1706       break;
1707     case PROP_FRC_ALGORITHM:
1708       g_value_set_enum (value, thiz->frc_algm);
1709       break;
1710     case PROP_VIDEO_DIRECTION:
1711       g_value_set_enum (value, thiz->video_direction);
1712       break;
1713     case PROP_CROP_LEFT:
1714       g_value_set_uint (value, thiz->crop_left);
1715       break;
1716     case PROP_CROP_RIGHT:
1717       g_value_set_uint (value, thiz->crop_right);
1718       break;
1719     case PROP_CROP_TOP:
1720       g_value_set_uint (value, thiz->crop_top);
1721       break;
1722     case PROP_CROP_BOTTOM:
1723       g_value_set_uint (value, thiz->crop_bottom);
1724       break;
1725     default:
1726       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1727       break;
1728   }
1729 }
1730
1731 static void
1732 gst_msdkvpp_dispose (GObject * object)
1733 {
1734   GstMsdkVPP *thiz = GST_MSDKVPP (object);
1735
1736   gst_clear_object (&thiz->old_context);
1737
1738   G_OBJECT_CLASS (parent_class)->dispose (object);
1739 }
1740
1741 static void
1742 gst_msdkvpp_set_context (GstElement * element, GstContext * context)
1743 {
1744   GstMsdkContext *msdk_context = NULL;
1745   GstMsdkVPP *thiz = GST_MSDKVPP (element);
1746
1747   if (gst_msdk_context_get_context (context, &msdk_context)) {
1748     gst_object_replace ((GstObject **) & thiz->context,
1749         (GstObject *) msdk_context);
1750     gst_object_unref (msdk_context);
1751   } else
1752 #ifndef _WIN32
1753     if (gst_msdk_context_from_external_va_display (context,
1754           thiz->hardware, 0 /* GST_MSDK_JOB_VPP will be set later */ ,
1755           &msdk_context)) {
1756     gst_object_replace ((GstObject **) & thiz->context,
1757         (GstObject *) msdk_context);
1758     gst_object_unref (msdk_context);
1759   }
1760 #else
1761     if (gst_msdk_context_from_external_d3d11_device (context,
1762           thiz->hardware, 0 /* GST_MSDK_JOB_VPP will be set later */ ,
1763           &msdk_context)) {
1764     gst_object_replace ((GstObject **) & thiz->context,
1765         (GstObject *) msdk_context);
1766     gst_object_unref (msdk_context);
1767   }
1768 #endif
1769
1770   GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
1771 }
1772
1773 static void
1774 gst_msdkvpp_class_init (GstMsdkVPPClass * klass)
1775 {
1776   GObjectClass *gobject_class;
1777   GstElementClass *element_class;
1778   GstBaseTransformClass *trans_class;
1779   GParamSpec *obj_properties[PROP_N] = { NULL, };
1780
1781   gobject_class = G_OBJECT_CLASS (klass);
1782   element_class = GST_ELEMENT_CLASS (klass);
1783   trans_class = GST_BASE_TRANSFORM_CLASS (klass);
1784
1785   gobject_class->set_property = gst_msdkvpp_set_property;
1786   gobject_class->get_property = gst_msdkvpp_get_property;
1787   gobject_class->dispose = gst_msdkvpp_dispose;
1788
1789   element_class->set_context = gst_msdkvpp_set_context;
1790
1791   gst_element_class_add_static_pad_template (element_class,
1792       &gst_msdkvpp_src_factory);
1793   gst_element_class_add_static_pad_template (element_class,
1794       &gst_msdkvpp_sink_factory);
1795
1796   gst_element_class_set_static_metadata (element_class,
1797       "Intel MSDK Video Postprocessor",
1798       "Filter/Converter/Video;Filter/Converter/Video/Scaler;"
1799       "Filter/Effect/Video;Filter/Effect/Video/Deinterlace",
1800       "Video Postprocessing Filter based on " MFX_API_SDK,
1801       "Sreerenj Balachandrn <sreerenj.balachandran@intel.com>");
1802
1803   trans_class->start = GST_DEBUG_FUNCPTR (gst_msdkvpp_start);
1804   trans_class->stop = GST_DEBUG_FUNCPTR (gst_msdkvpp_stop);
1805   trans_class->transform_caps = GST_DEBUG_FUNCPTR (gst_msdkvpp_transform_caps);
1806   trans_class->fixate_caps = GST_DEBUG_FUNCPTR (gst_msdkvpp_fixate_caps);
1807   trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_msdkvpp_set_caps);
1808   trans_class->transform = GST_DEBUG_FUNCPTR (gst_msdkvpp_transform);
1809   trans_class->propose_allocation =
1810       GST_DEBUG_FUNCPTR (gst_msdkvpp_propose_allocation);
1811   trans_class->decide_allocation =
1812       GST_DEBUG_FUNCPTR (gst_msdkvpp_decide_allocation);
1813   trans_class->prepare_output_buffer =
1814       GST_DEBUG_FUNCPTR (gst_msdkvpp_prepare_output_buffer);
1815   trans_class->query = GST_DEBUG_FUNCPTR (gst_msdkvpp_query);
1816
1817   obj_properties[PROP_HARDWARE] =
1818       g_param_spec_boolean ("hardware", "Hardware", "Enable hardware VPP",
1819       PROP_HARDWARE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1820
1821   obj_properties[PROP_ASYNC_DEPTH] =
1822       g_param_spec_uint ("async-depth", "Async Depth",
1823       "Depth of asynchronous pipeline",
1824       1, 1, PROP_ASYNC_DEPTH_DEFAULT,
1825       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1826
1827   obj_properties[PROP_DENOISE] =
1828       g_param_spec_uint ("denoise", "Denoising factor",
1829       "Denoising Factor",
1830       0, 100, PROP_DENOISE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1831
1832 #ifndef GST_REMOVE_DEPRECATED
1833   obj_properties[PROP_ROTATION] =
1834       g_param_spec_enum ("rotation", "Rotation",
1835       "Rotation Angle (DEPRECATED, use video-direction instead)",
1836       gst_msdkvpp_rotation_get_type (), PROP_ROTATION_DEFAULT,
1837       G_PARAM_DEPRECATED | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1838
1839   obj_properties[PROP_MIRRORING] =
1840       g_param_spec_enum ("mirroring", "Mirroring",
1841       "The Mirroring type (DEPRECATED, use video-direction instead)",
1842       gst_msdkvpp_mirroring_get_type (), PROP_MIRRORING_DEFAULT,
1843       G_PARAM_DEPRECATED | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1844
1845 #endif
1846
1847   obj_properties[PROP_DEINTERLACE_MODE] =
1848       g_param_spec_enum ("deinterlace-mode", "Deinterlace Mode",
1849       "Deinterlace mode to use", gst_msdkvpp_deinterlace_mode_get_type (),
1850       PROP_DEINTERLACE_MODE_DEFAULT,
1851       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1852
1853   obj_properties[PROP_DEINTERLACE_METHOD] =
1854       g_param_spec_enum ("deinterlace-method", "Deinterlace Method",
1855       "Deinterlace method to use", gst_msdkvpp_deinterlace_method_get_type (),
1856       PROP_DEINTERLACE_METHOD_DEFAULT,
1857       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1858
1859   obj_properties[PROP_HUE] =
1860       g_param_spec_float ("hue", "Hue",
1861       "The hue of the video",
1862       -180, 180, PROP_HUE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1863
1864   obj_properties[PROP_SATURATION] =
1865       g_param_spec_float ("saturation", "Saturation",
1866       "The Saturation of the video",
1867       0, 10, PROP_SATURATION_DEFAULT,
1868       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1869
1870   obj_properties[PROP_BRIGHTNESS] =
1871       g_param_spec_float ("brightness", "Brightness",
1872       "The Brightness of the video",
1873       -100, 100, PROP_BRIGHTNESS_DEFAULT,
1874       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1875
1876   obj_properties[PROP_CONTRAST] =
1877       g_param_spec_float ("contrast", "Contrast",
1878       "The Contrast of the video",
1879       0, 10, PROP_CONTRAST_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1880
1881   obj_properties[PROP_DETAIL] =
1882       g_param_spec_uint ("detail", "Detail",
1883       "The factor of detail/edge enhancement filter algorithm",
1884       0, 100, PROP_DETAIL_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1885
1886   obj_properties[PROP_SCALING_MODE] =
1887       g_param_spec_enum ("scaling-mode", "Scaling Mode",
1888       "The Scaling mode to use", gst_msdkvpp_scaling_mode_get_type (),
1889       PROP_SCALING_MODE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1890
1891   obj_properties[PROP_FORCE_ASPECT_RATIO] =
1892       g_param_spec_boolean ("force-aspect-ratio", "Force Aspect Ratio",
1893       "When enabled, scaling will respect original aspect ratio",
1894       PROP_FORCE_ASPECT_RATIO_DEFAULT,
1895       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1896
1897   obj_properties[PROP_FRC_ALGORITHM] =
1898       g_param_spec_enum ("frc-algorithm", "FrameRateControl Algorithm",
1899       "The Framerate Control Alogorithm to use",
1900       gst_msdkvpp_frc_algorithm_get_type (), PROP_FRC_ALGORITHM_DEFAULT,
1901       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1902
1903   /*
1904    * The video-direction to use, expressed as an enum value. See
1905    * #GstVideoOrientationMethod.
1906    */
1907   obj_properties[PROP_VIDEO_DIRECTION] = g_param_spec_enum ("video-direction",
1908       "Video Direction", "Video direction: rotation and flipping"
1909 #ifndef GST_REMOVE_DEPRECATED
1910       ", it will override both mirroring & rotation properties if set explicitly"
1911 #endif
1912       ,
1913       GST_TYPE_VIDEO_ORIENTATION_METHOD,
1914       PROP_VIDEO_DIRECTION_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1915
1916   obj_properties[PROP_CROP_LEFT] = g_param_spec_uint ("crop-left",
1917       "Crop Left", "Pixels to crop at left",
1918       0, G_MAXUINT16, PROP_CROP_LEFT_DEFAULT,
1919       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1920
1921   obj_properties[PROP_CROP_RIGHT] = g_param_spec_uint ("crop-right",
1922       "Crop Right", "Pixels to crop at right",
1923       0, G_MAXUINT16, PROP_CROP_RIGHT_DEFAULT,
1924       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1925
1926   obj_properties[PROP_CROP_TOP] = g_param_spec_uint ("crop-top",
1927       "Crop Top", "Pixels to crop at top",
1928       0, G_MAXUINT16, PROP_CROP_TOP_DEFAULT,
1929       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1930
1931   obj_properties[PROP_CROP_BOTTOM] = g_param_spec_uint ("crop-bottom",
1932       "Crop Bottom", "Pixels to crop at bottom",
1933       0, G_MAXUINT16, PROP_CROP_BOTTOM_DEFAULT,
1934       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1935
1936   g_object_class_install_properties (gobject_class, PROP_N, obj_properties);
1937 }
1938
1939 static void
1940 gst_msdkvpp_init (GstMsdkVPP * thiz)
1941 {
1942   thiz->initialized = FALSE;
1943   thiz->hardware = PROP_HARDWARE_DEFAULT;
1944   thiz->async_depth = PROP_ASYNC_DEPTH_DEFAULT;
1945   thiz->denoise_factor = PROP_DENOISE_DEFAULT;
1946 #ifndef GST_REMOVE_DEPRECATED
1947   thiz->rotation = PROP_ROTATION_DEFAULT;
1948   thiz->mirroring = PROP_MIRRORING_DEFAULT;
1949 #else
1950   thiz->rotation = MFX_ANGLE_0;
1951   thiz->mirroring = MFX_MIRRORING_DISABLED;
1952 #endif
1953   thiz->deinterlace_mode = PROP_DEINTERLACE_MODE_DEFAULT;
1954   thiz->deinterlace_method = PROP_DEINTERLACE_METHOD_DEFAULT;
1955   thiz->buffer_duration = GST_CLOCK_TIME_NONE;
1956   thiz->hue = PROP_HUE_DEFAULT;
1957   thiz->saturation = PROP_SATURATION_DEFAULT;
1958   thiz->brightness = PROP_BRIGHTNESS_DEFAULT;
1959   thiz->contrast = PROP_CONTRAST_DEFAULT;
1960   thiz->detail = PROP_DETAIL_DEFAULT;
1961   thiz->scaling_mode = PROP_SCALING_MODE_DEFAULT;
1962   thiz->keep_aspect = PROP_FORCE_ASPECT_RATIO_DEFAULT;
1963   thiz->frc_algm = PROP_FRC_ALGORITHM_DEFAULT;
1964   thiz->video_direction = PROP_VIDEO_DIRECTION_DEFAULT;
1965   thiz->crop_left = PROP_CROP_LEFT_DEFAULT;
1966   thiz->crop_right = PROP_CROP_RIGHT_DEFAULT;
1967   thiz->crop_top = PROP_CROP_TOP_DEFAULT;
1968   thiz->crop_bottom = PROP_CROP_BOTTOM_DEFAULT;
1969
1970   gst_video_info_init (&thiz->sinkpad_info);
1971   gst_video_info_init (&thiz->srcpad_info);
1972 }