ea99d1905ffae1394f85e4db6cddb7694949f938
[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 #ifndef _WIN32
938     out_surface = gst_msdk_import_to_msdk_surface (outbuf, thiz->context,
939         &thiz->srcpad_info, 0);
940 #else
941     out_surface =
942         gst_msdk_import_sys_mem_to_msdk_surface (outbuf, thiz->srcpad_info);
943 #endif
944     if (out_surface)
945       out_surface->buf = gst_buffer_ref (outbuf);
946     else {
947       GST_ERROR_OBJECT (thiz, "Failed to get msdk outsurface!");
948       free_msdk_surface (in_surface);
949       return GST_FLOW_ERROR;
950     }
951   }
952
953   /* update surface crop info (NOTE: msdk min frame size is 2x2) */
954   in_info = &in_surface->surface->Info;
955   if ((thiz->crop_left + thiz->crop_right >= in_info->CropW - 1)
956       || (thiz->crop_top + thiz->crop_bottom >= in_info->CropH - 1)) {
957     GST_WARNING_OBJECT (thiz, "ignoring crop... cropping too much!");
958   } else if (!in_surface->from_qdata) {
959     /* We only fill crop info when it is a new surface.
960      * If the surface is a cached one, it already has crop info,
961      * and we should avoid updating again.
962      */
963     in_info->CropX = thiz->crop_left;
964     in_info->CropY = thiz->crop_top;
965     in_info->CropW -= thiz->crop_left + thiz->crop_right;
966     in_info->CropH -= thiz->crop_top + thiz->crop_bottom;
967   }
968
969   session = gst_msdk_context_get_session (thiz->context);
970
971   /* outer loop is for handling FrameRate Control and deinterlace use cases */
972   do {
973     for (;;) {
974       status =
975           MFXVideoVPP_RunFrameVPPAsync (session, in_surface->surface,
976           out_surface->surface, NULL, &sync_point);
977       timestamp = out_surface->surface->Data.TimeStamp;
978
979       if (status != MFX_WRN_DEVICE_BUSY)
980         break;
981       /* If device is busy, wait 1ms and retry, as per MSDK's recommendation */
982       g_usleep (1000);
983     }
984
985     if (timestamp == MFX_TIMESTAMP_UNKNOWN)
986       timestamp = GST_CLOCK_TIME_NONE;
987     else
988       timestamp = gst_util_uint64_scale_round (timestamp, GST_SECOND, 90000);
989
990     if (status == MFX_WRN_INCOMPATIBLE_VIDEO_PARAM)
991       GST_WARNING_OBJECT (thiz, "VPP returned: %s",
992           msdk_status_to_string (status));
993     else if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA
994         && status != MFX_ERR_MORE_SURFACE)
995       goto vpp_error;
996
997     /* No output generated */
998     if (status == MFX_ERR_MORE_DATA)
999       goto error_more_data;
1000
1001     /* Wait for vpp operation to complete, the magic number 300000 below
1002      * is used in MSDK samples
1003      * #define MSDK_VPP_WAIT_INTERVAL 300000
1004      */
1005     if (sync_point &&
1006         MFXVideoCORE_SyncOperation (session, sync_point,
1007             300000) != MFX_ERR_NONE)
1008       GST_WARNING_OBJECT (thiz, "failed to do sync operation");
1009     /* push new output buffer forward after sync operation */
1010     if (create_new_surface) {
1011       create_new_surface = FALSE;
1012       ret = gst_pad_push (GST_BASE_TRANSFORM_SRC_PAD (trans), outbuf_new);
1013       if (ret != GST_FLOW_OK)
1014         goto error_push_buffer;
1015     }
1016
1017     /* More than one output buffers are generated */
1018     if (status == MFX_ERR_MORE_SURFACE) {
1019       outbuf_new = create_output_buffer (thiz);
1020       GST_BUFFER_TIMESTAMP (outbuf_new) = timestamp;
1021       GST_BUFFER_DURATION (outbuf_new) = thiz->buffer_duration;
1022
1023       if (gst_msdk_is_msdk_buffer (outbuf_new)) {
1024         release_out_surface (thiz, out_surface);
1025         out_surface = g_slice_new0 (GstMsdkSurface);
1026         out_surface->surface = gst_msdk_get_surface_from_buffer (outbuf_new);
1027         create_new_surface = TRUE;
1028       } else {
1029         release_out_surface (thiz, out_surface);
1030 #ifndef _WIN32
1031         out_surface =
1032             gst_msdk_import_to_msdk_surface (outbuf_new, thiz->context,
1033             &thiz->srcpad_buffer_pool_info, 0);
1034 #else
1035         out_surface =
1036             gst_msdk_import_sys_mem_to_msdk_surface (outbuf_new,
1037             thiz->srcpad_buffer_pool_info);
1038 #endif
1039         if (out_surface) {
1040           out_surface->buf = gst_buffer_ref (outbuf_new);
1041           create_new_surface = TRUE;
1042         } else {
1043           GST_ERROR_OBJECT (thiz, "Failed to get msdk outsurface!");
1044           release_in_surface (thiz, in_surface, locked_by_others);
1045           return GST_FLOW_ERROR;
1046         }
1047       }
1048     } else {
1049       GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
1050       GST_BUFFER_DURATION (outbuf) = thiz->buffer_duration;
1051     }
1052   } while (status == MFX_ERR_MORE_SURFACE);
1053
1054   goto transform_end;
1055
1056 vpp_error:
1057   GST_ERROR_OBJECT (thiz, "MSDK Failed to do VPP");
1058   ret = GST_FLOW_ERROR;
1059   goto transform_end;
1060
1061 error_more_data:
1062   GST_WARNING_OBJECT (thiz,
1063       "MSDK Requires additional input for processing, "
1064       "Retruning FLOW_DROPPED since no output buffer was generated");
1065   ret = GST_BASE_TRANSFORM_FLOW_DROPPED;
1066   goto transform_end;
1067
1068 error_push_buffer:
1069   GST_DEBUG_OBJECT (thiz, "failed to push output buffer: %s",
1070       gst_flow_get_name (ret));
1071
1072 transform_end:
1073   release_in_surface (thiz, in_surface, locked_by_others);
1074   release_out_surface (thiz, out_surface);
1075
1076   return ret;
1077 }
1078
1079 static void
1080 gst_msdkvpp_close (GstMsdkVPP * thiz)
1081 {
1082   mfxStatus status;
1083
1084   if (!thiz->context)
1085     return;
1086
1087   GST_DEBUG_OBJECT (thiz, "Closing VPP 0x%p", thiz->context);
1088   status = MFXVideoVPP_Close (gst_msdk_context_get_session (thiz->context));
1089   if (status != MFX_ERR_NONE && status != MFX_ERR_NOT_INITIALIZED) {
1090     GST_WARNING_OBJECT (thiz, "VPP close failed (%s)",
1091         msdk_status_to_string (status));
1092   }
1093   free_all_msdk_surfaces (thiz);
1094
1095   gst_clear_object (&thiz->context);
1096
1097   memset (&thiz->param, 0, sizeof (thiz->param));
1098
1099   gst_clear_object (&thiz->sinkpad_buffer_pool);
1100   gst_clear_object (&thiz->srcpad_buffer_pool);
1101
1102   thiz->buffer_duration = GST_CLOCK_TIME_NONE;
1103   gst_video_info_init (&thiz->sinkpad_info);
1104   gst_video_info_init (&thiz->srcpad_info);
1105 }
1106
1107 static void
1108 ensure_filters (GstMsdkVPP * thiz)
1109 {
1110   /* Denoise */
1111   if (thiz->flags & GST_MSDK_FLAG_DENOISE) {
1112     mfxExtVPPDenoise *mfx_denoise = &thiz->mfx_denoise;
1113     mfx_denoise->Header.BufferId = MFX_EXTBUFF_VPP_DENOISE;
1114     mfx_denoise->Header.BufferSz = sizeof (mfxExtVPPDenoise);
1115     mfx_denoise->DenoiseFactor = thiz->denoise_factor;
1116     gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_denoise);
1117   }
1118
1119   /* Rotation */
1120   if (thiz->rotation != MFX_ANGLE_0) {
1121     mfxExtVPPRotation *mfx_rotation = &thiz->mfx_rotation;
1122     mfx_rotation->Header.BufferId = MFX_EXTBUFF_VPP_ROTATION;
1123     mfx_rotation->Header.BufferSz = sizeof (mfxExtVPPRotation);
1124     mfx_rotation->Angle = thiz->rotation;
1125     gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_rotation);
1126   }
1127
1128   /* Deinterlace */
1129   if (thiz->flags & GST_MSDK_FLAG_DEINTERLACE) {
1130     mfxExtVPPDeinterlacing *mfx_deinterlace = &thiz->mfx_deinterlace;
1131     mfx_deinterlace->Header.BufferId = MFX_EXTBUFF_VPP_DEINTERLACING;
1132     mfx_deinterlace->Header.BufferSz = sizeof (mfxExtVPPDeinterlacing);
1133     mfx_deinterlace->Mode = thiz->deinterlace_method;
1134     gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_deinterlace);
1135   }
1136
1137   /* Colorbalance(ProcAmp) */
1138   if (thiz->flags & (GST_MSDK_FLAG_HUE | GST_MSDK_FLAG_SATURATION |
1139           GST_MSDK_FLAG_BRIGHTNESS | GST_MSDK_FLAG_CONTRAST)) {
1140     mfxExtVPPProcAmp *mfx_procamp = &thiz->mfx_procamp;
1141     mfx_procamp->Header.BufferId = MFX_EXTBUFF_VPP_PROCAMP;
1142     mfx_procamp->Header.BufferSz = sizeof (mfxExtVPPProcAmp);
1143     mfx_procamp->Hue = thiz->hue;
1144     mfx_procamp->Saturation = thiz->saturation;
1145     mfx_procamp->Brightness = thiz->brightness;
1146     mfx_procamp->Contrast = thiz->contrast;
1147     gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_procamp);
1148   }
1149
1150   /* Detail/Edge enhancement */
1151   if (thiz->flags & GST_MSDK_FLAG_DETAIL) {
1152     mfxExtVPPDetail *mfx_detail = &thiz->mfx_detail;
1153     mfx_detail->Header.BufferId = MFX_EXTBUFF_VPP_DETAIL;
1154     mfx_detail->Header.BufferSz = sizeof (mfxExtVPPDetail);
1155     mfx_detail->DetailFactor = thiz->detail;
1156     gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_detail);
1157   }
1158
1159   /* Mirroring */
1160   if (thiz->mirroring != MFX_MIRRORING_DISABLED) {
1161     mfxExtVPPMirroring *mfx_mirroring = &thiz->mfx_mirroring;
1162     mfx_mirroring->Header.BufferId = MFX_EXTBUFF_VPP_MIRRORING;
1163     mfx_mirroring->Header.BufferSz = sizeof (mfxExtVPPMirroring);
1164     mfx_mirroring->Type = thiz->mirroring;
1165     gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_mirroring);
1166   }
1167
1168   /* Scaling Mode */
1169   if (thiz->flags & GST_MSDK_FLAG_SCALING_MODE) {
1170     mfxExtVPPScaling *mfx_scaling = &thiz->mfx_scaling;
1171     mfx_scaling->Header.BufferId = MFX_EXTBUFF_VPP_SCALING;
1172     mfx_scaling->Header.BufferSz = sizeof (mfxExtVPPScaling);
1173     mfx_scaling->ScalingMode = thiz->scaling_mode;
1174     gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_scaling);
1175   }
1176
1177   /* FRC */
1178   if (thiz->flags & GST_MSDK_FLAG_FRC) {
1179     mfxExtVPPFrameRateConversion *mfx_frc = &thiz->mfx_frc;
1180     mfx_frc->Header.BufferId = MFX_EXTBUFF_VPP_FRAME_RATE_CONVERSION;
1181     mfx_frc->Header.BufferSz = sizeof (mfxExtVPPFrameRateConversion);
1182     mfx_frc->Algorithm = thiz->frc_algm;
1183     gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_frc);
1184   }
1185 }
1186
1187 static void
1188 gst_msdkvpp_set_passthrough (GstMsdkVPP * thiz)
1189 {
1190   gboolean passthrough = TRUE;
1191
1192   /* no passthrough if any of the filter algorithm is enabled */
1193   if (thiz->flags)
1194     passthrough = FALSE;
1195
1196   /* vpp could be needed in some specific circumstances, for eg:
1197    * input surface is dmabuf and output must be videomemory. So far
1198    * the underline iHD driver doesn't seems to support dmabuf mapping,
1199    * so we could explicitly ask msdkvpp to provide non-dambuf videomemory
1200    * surfaces as output thourgh capsfileters */
1201   if (thiz->need_vpp)
1202     passthrough = FALSE;
1203
1204   /* no passthrough if there is change in out width,height or format */
1205   if (GST_VIDEO_INFO_WIDTH (&thiz->sinkpad_info) !=
1206       GST_VIDEO_INFO_WIDTH (&thiz->srcpad_info)
1207       || GST_VIDEO_INFO_HEIGHT (&thiz->sinkpad_info) !=
1208       GST_VIDEO_INFO_HEIGHT (&thiz->srcpad_info)
1209       || GST_VIDEO_INFO_FORMAT (&thiz->sinkpad_info) !=
1210       GST_VIDEO_INFO_FORMAT (&thiz->srcpad_info))
1211     passthrough = FALSE;
1212
1213   gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (thiz), passthrough);
1214 }
1215
1216 static gboolean
1217 gst_msdkvpp_initialize (GstMsdkVPP * thiz)
1218 {
1219   mfxSession session;
1220   mfxStatus status;
1221   mfxFrameAllocRequest *request = &thiz->request[0];
1222
1223   if (!thiz->context) {
1224     GST_WARNING_OBJECT (thiz, "No MSDK Context");
1225     return FALSE;
1226   }
1227
1228   GST_OBJECT_LOCK (thiz);
1229   session = gst_msdk_context_get_session (thiz->context);
1230
1231   /* Close the current session if the session has been initialized,
1232    * otherwise the subsequent function call of MFXVideoVPP_Init() will
1233    * fail
1234    */
1235   if (thiz->initialized) {
1236     MFXVideoVPP_Close (session);
1237
1238     memset (&thiz->param, 0, sizeof (thiz->param));
1239     memset (&thiz->extra_params, 0, sizeof (thiz->extra_params));
1240     thiz->num_extra_params = 0;
1241   }
1242
1243   if (thiz->use_video_memory) {
1244     gst_msdk_set_frame_allocator (thiz->context);
1245     thiz->param.IOPattern =
1246         MFX_IOPATTERN_IN_VIDEO_MEMORY | MFX_IOPATTERN_OUT_VIDEO_MEMORY;
1247   } else {
1248     thiz->param.IOPattern =
1249         MFX_IOPATTERN_IN_SYSTEM_MEMORY | MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
1250   }
1251
1252   /* update input video attributes */
1253   gst_msdk_set_mfx_frame_info_from_video_info (&thiz->param.vpp.In,
1254       &thiz->sinkpad_info);
1255
1256   /* update output video attributes, only CSC and Scaling are supported for now */
1257   gst_msdk_set_mfx_frame_info_from_video_info (&thiz->param.vpp.Out,
1258       &thiz->srcpad_info);
1259
1260   /* use msdk frame rarte control if there is a mismatch in In & OUt fps  */
1261   if (GST_VIDEO_INFO_FPS_N (&thiz->srcpad_info) &&
1262       (GST_VIDEO_INFO_FPS_N (&thiz->sinkpad_info) !=
1263           GST_VIDEO_INFO_FPS_N (&thiz->srcpad_info)
1264           || GST_VIDEO_INFO_FPS_D (&thiz->sinkpad_info) !=
1265           GST_VIDEO_INFO_FPS_D (&thiz->srcpad_info))) {
1266     thiz->flags |= GST_MSDK_FLAG_FRC;
1267     /* manually set distributed timestamp as frc algorithm
1268      * as it is more resonable for framerate conversion
1269      */
1270     thiz->frc_algm = MFX_FRCALGM_DISTRIBUTED_TIMESTAMP;
1271   }
1272
1273   /* work-around to avoid zero fps in msdk structure */
1274   if (!thiz->param.vpp.In.FrameRateExtN)
1275     thiz->param.vpp.In.FrameRateExtN = 30;
1276   if (!thiz->param.vpp.Out.FrameRateExtN)
1277     thiz->param.vpp.Out.FrameRateExtN = thiz->param.vpp.In.FrameRateExtN;
1278
1279   /* set vpp out picstruct as progressive if deinterlacing enabled */
1280   if (thiz->flags & GST_MSDK_FLAG_DEINTERLACE)
1281     thiz->param.vpp.Out.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
1282
1283   /* Enable the required filters */
1284   ensure_filters (thiz);
1285
1286   /* Add extended buffers */
1287   if (thiz->num_extra_params) {
1288     thiz->param.NumExtParam = thiz->num_extra_params;
1289     thiz->param.ExtParam = thiz->extra_params;
1290   }
1291
1292   /* validate parameters and allow MFX to make adjustments */
1293   status = MFXVideoVPP_Query (session, &thiz->param, &thiz->param);
1294   if (status < MFX_ERR_NONE) {
1295     GST_ERROR_OBJECT (thiz, "Video VPP Query failed (%s)",
1296         msdk_status_to_string (status));
1297     goto no_vpp;
1298   } else if (status > MFX_ERR_NONE) {
1299     GST_WARNING_OBJECT (thiz, "Video VPP Query returned: %s",
1300         msdk_status_to_string (status));
1301   }
1302
1303   status = MFXVideoVPP_QueryIOSurf (session, &thiz->param, request);
1304   if (status < MFX_ERR_NONE) {
1305     GST_ERROR_OBJECT (thiz, "VPP Query IO surfaces failed (%s)",
1306         msdk_status_to_string (status));
1307     goto no_vpp;
1308   } else if (status > MFX_ERR_NONE) {
1309     GST_WARNING_OBJECT (thiz, "VPP Query IO surfaces returned: %s",
1310         msdk_status_to_string (status));
1311   }
1312
1313   if (thiz->use_video_memory) {
1314     /* Input surface pool pre-allocation */
1315     request[0].Type |= MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET;
1316     if (thiz->use_sinkpad_dmabuf)
1317       request[0].Type |= MFX_MEMTYPE_EXPORT_FRAME;
1318
1319     /* Output surface pool pre-allocation */
1320     request[1].Type |= MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET;
1321     if (thiz->use_srcpad_dmabuf)
1322       request[1].Type |= MFX_MEMTYPE_EXPORT_FRAME;
1323   }
1324
1325   thiz->in_num_surfaces = request[0].NumFrameSuggested;
1326
1327   status = MFXVideoVPP_Init (session, &thiz->param);
1328   if (status < MFX_ERR_NONE) {
1329     GST_ERROR_OBJECT (thiz, "Init failed (%s)", msdk_status_to_string (status));
1330     goto no_vpp;
1331   } else if (status > MFX_ERR_NONE) {
1332     GST_WARNING_OBJECT (thiz, "Init returned: %s",
1333         msdk_status_to_string (status));
1334   }
1335
1336   thiz->initialized = TRUE;
1337   GST_OBJECT_UNLOCK (thiz);
1338   return TRUE;
1339
1340 no_vpp:
1341   GST_OBJECT_UNLOCK (thiz);
1342   gst_clear_object (&thiz->context);
1343   return FALSE;
1344 }
1345
1346 static gboolean
1347 gst_msdkvpp_set_caps (GstBaseTransform * trans, GstCaps * caps,
1348     GstCaps * out_caps)
1349 {
1350   GstMsdkVPP *thiz = GST_MSDKVPP (trans);
1351   GstVideoInfo in_info, out_info;
1352   gboolean sinkpad_info_changed = FALSE;
1353   gboolean srcpad_info_changed = FALSE;
1354   gboolean deinterlace;
1355
1356   if (!gst_caps_features_is_equal (gst_caps_get_features (caps, 0),
1357           gst_caps_get_features (out_caps, 0)))
1358     thiz->need_vpp = 1;
1359
1360   if (!gst_video_info_from_caps (&in_info, caps))
1361     goto error_no_video_info;
1362   if (!gst_video_info_from_caps (&out_info, out_caps))
1363     goto error_no_video_info;
1364
1365   if (!gst_video_info_is_equal (&in_info, &thiz->sinkpad_info))
1366     sinkpad_info_changed = TRUE;
1367   if (!gst_video_info_is_equal (&out_info, &thiz->srcpad_info))
1368     srcpad_info_changed = TRUE;
1369
1370   if (!sinkpad_info_changed && !srcpad_info_changed && thiz->initialized)
1371     return TRUE;
1372
1373   thiz->sinkpad_info = in_info;
1374   thiz->srcpad_info = out_info;
1375
1376   thiz->use_video_memory = TRUE;
1377
1378   /* check for deinterlace requirement */
1379   deinterlace = gst_msdkvpp_is_deinterlace_enabled (thiz, &in_info);
1380   if (deinterlace)
1381     thiz->flags |= GST_MSDK_FLAG_DEINTERLACE;
1382
1383   thiz->buffer_duration = GST_VIDEO_INFO_FPS_N (&out_info) > 0 ?
1384       gst_util_uint64_scale (GST_SECOND, GST_VIDEO_INFO_FPS_D (&out_info),
1385       GST_VIDEO_INFO_FPS_N (&out_info)) : 0;
1386
1387   if (!gst_msdkvpp_initialize (thiz))
1388     return FALSE;
1389
1390   /* set passthrough according to filter operation change */
1391   gst_msdkvpp_set_passthrough (thiz);
1392
1393   /* Ensure sinkpad buffer pool */
1394   if (thiz->sinkpad_buffer_pool)
1395     gst_object_unref (thiz->sinkpad_buffer_pool);
1396
1397   thiz->sinkpad_buffer_pool =
1398       gst_msdkvpp_create_buffer_pool (thiz, GST_PAD_SINK, caps,
1399       thiz->in_num_surfaces, FALSE);
1400   if (!thiz->sinkpad_buffer_pool) {
1401     GST_ERROR_OBJECT (thiz, "Failed to ensure the sinkpad buffer pool");
1402     return FALSE;
1403   }
1404
1405   return TRUE;
1406
1407 error_no_video_info:
1408   GST_ERROR_OBJECT (thiz, "Failed to get video info from caps");
1409   return FALSE;
1410 }
1411
1412 static gboolean
1413 pad_accept_memory (GstMsdkVPP * thiz, const gchar * mem_type,
1414     GstPadDirection direction, GstCaps * filter)
1415 {
1416   gboolean ret = FALSE;
1417   GstCaps *caps, *out_caps;
1418   GstPad *pad;
1419   GstBaseTransform *trans = GST_BASE_TRANSFORM (thiz);
1420
1421   if (direction == GST_PAD_SRC)
1422     pad = GST_BASE_TRANSFORM_SRC_PAD (trans);
1423   else
1424     pad = GST_BASE_TRANSFORM_SINK_PAD (trans);
1425
1426   /* make a copy of filter caps since we need to alter the structure
1427    * by adding dmabuf-capsfeatures */
1428   caps = gst_caps_copy (filter);
1429   gst_caps_set_features (caps, 0, gst_caps_features_from_string (mem_type));
1430
1431   out_caps = gst_pad_peer_query_caps (pad, caps);
1432   if (!out_caps)
1433     goto done;
1434
1435   if (gst_caps_is_any (out_caps) || gst_caps_is_empty (out_caps)
1436       || out_caps == caps)
1437     goto done;
1438
1439   if (_gst_caps_has_feature (out_caps, mem_type))
1440     ret = TRUE;
1441 done:
1442   if (caps)
1443     gst_caps_unref (caps);
1444   if (out_caps)
1445     gst_caps_unref (out_caps);
1446   return ret;
1447 }
1448
1449 static GstCaps *
1450 gst_msdkvpp_fixate_caps (GstBaseTransform * trans,
1451     GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
1452 {
1453   GstMsdkVPP *thiz = GST_MSDKVPP (trans);
1454   GstCaps *result = NULL;
1455   gboolean *use_dmabuf;
1456
1457   if (direction == GST_PAD_SRC) {
1458     result = gst_caps_fixate (result);
1459     use_dmabuf = &thiz->use_sinkpad_dmabuf;
1460   } else {
1461     /*
1462      * Override mirroring & rotation properties once video-direction
1463      * is set explicitly
1464      */
1465     if (thiz->flags & GST_MSDK_FLAG_VIDEO_DIRECTION)
1466       gst_msdk_get_mfx_video_orientation_from_video_direction
1467           (thiz->video_direction, &thiz->mirroring, &thiz->rotation);
1468
1469     result = gst_msdkvpp_fixate_srccaps (thiz, caps, othercaps);
1470     use_dmabuf = &thiz->use_srcpad_dmabuf;
1471   }
1472
1473   GST_DEBUG_OBJECT (trans, "fixated to %" GST_PTR_FORMAT, result);
1474   gst_caps_unref (othercaps);
1475
1476   /* We let msdkvpp srcpad first query if downstream has va memory type caps,
1477    * if not, will check the type of dma memory.
1478    */
1479 #ifndef _WIN32
1480   if (pad_accept_memory (thiz, GST_CAPS_FEATURE_MEMORY_VA,
1481           direction == GST_PAD_SRC ? GST_PAD_SINK : GST_PAD_SRC, result)) {
1482     gst_caps_set_features (result, 0,
1483         gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_VA, NULL));
1484   } else if (pad_accept_memory (thiz, GST_CAPS_FEATURE_MEMORY_DMABUF,
1485           direction == GST_PAD_SRC ? GST_PAD_SINK : GST_PAD_SRC, result)) {
1486     gst_caps_set_features (result, 0,
1487         gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_DMABUF, NULL));
1488     *use_dmabuf = TRUE;
1489   }
1490 #else
1491   if (pad_accept_memory (thiz, GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY,
1492           direction == GST_PAD_SRC ? GST_PAD_SINK : GST_PAD_SRC, result)) {
1493     gst_caps_set_features (result, 0,
1494         gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, NULL));
1495   }
1496 #endif
1497
1498   return result;
1499 }
1500
1501 /* Generic code for now, requires changes in future when we
1502  * add hardware query for supported formats, Framerate control etc */
1503 static GstCaps *
1504 gst_msdkvpp_transform_caps (GstBaseTransform * trans,
1505     GstPadDirection direction, GstCaps * caps, GstCaps * filter)
1506 {
1507   GstCaps *out_caps;
1508
1509   GST_DEBUG_OBJECT (trans,
1510       "Transforming caps %" GST_PTR_FORMAT " in direction %s", caps,
1511       (direction == GST_PAD_SINK) ? "sink" : "src");
1512
1513   if (direction == GST_PAD_SRC)
1514     out_caps = gst_static_pad_template_get_caps (&gst_msdkvpp_sink_factory);
1515   else
1516     out_caps = gst_static_pad_template_get_caps (&gst_msdkvpp_src_factory);
1517
1518   if (out_caps && filter) {
1519     GstCaps *intersection;
1520
1521     intersection = gst_caps_intersect_full (out_caps, filter,
1522         GST_CAPS_INTERSECT_FIRST);
1523     gst_caps_unref (out_caps);
1524     out_caps = intersection;
1525   }
1526
1527   GST_DEBUG_OBJECT (trans, "returning caps: %" GST_PTR_FORMAT, out_caps);
1528   return out_caps;
1529 }
1530
1531 static gboolean
1532 gst_msdkvpp_start (GstBaseTransform * trans)
1533 {
1534   if (!ensure_context (trans))
1535     return FALSE;
1536   return TRUE;
1537 }
1538
1539 static gboolean
1540 gst_msdkvpp_stop (GstBaseTransform * trans)
1541 {
1542   gst_msdkvpp_close (GST_MSDKVPP (trans));
1543   return TRUE;
1544 }
1545
1546 static gboolean
1547 gst_msdkvpp_query (GstBaseTransform * trans, GstPadDirection direction,
1548     GstQuery * query)
1549 {
1550   GstMsdkVPP *thiz = GST_MSDKVPP (trans);
1551   gboolean ret = FALSE;
1552
1553   switch (GST_QUERY_TYPE (query)) {
1554     case GST_QUERY_CONTEXT:{
1555       GstMsdkContext *msdk_context = NULL;
1556
1557       gst_object_replace ((GstObject **) & msdk_context,
1558           (GstObject *) thiz->context);
1559       ret = gst_msdk_handle_context_query (GST_ELEMENT_CAST (trans),
1560           query, msdk_context);
1561       gst_clear_object (&msdk_context);
1562       break;
1563     }
1564     default:
1565       ret = GST_BASE_TRANSFORM_CLASS (parent_class)->query (trans,
1566           direction, query);
1567       break;
1568   }
1569
1570   return ret;
1571 }
1572
1573 static void
1574 gst_msdkvpp_set_property (GObject * object, guint prop_id,
1575     const GValue * value, GParamSpec * pspec)
1576 {
1577   GstMsdkVPP *thiz = GST_MSDKVPP (object);
1578
1579   switch (prop_id) {
1580     case PROP_HARDWARE:
1581       thiz->hardware = g_value_get_boolean (value);
1582       break;
1583     case PROP_ASYNC_DEPTH:
1584       thiz->async_depth = g_value_get_uint (value);
1585       break;
1586     case PROP_DENOISE:
1587       thiz->denoise_factor = g_value_get_uint (value);
1588       thiz->flags |= GST_MSDK_FLAG_DENOISE;
1589       break;
1590 #ifndef GST_REMOVE_DEPRECATED
1591     case PROP_ROTATION:
1592       thiz->rotation = g_value_get_enum (value);
1593       thiz->flags |= GST_MSDK_FLAG_ROTATION;
1594       break;
1595     case PROP_MIRRORING:
1596       thiz->mirroring = g_value_get_enum (value);
1597       thiz->flags |= GST_MSDK_FLAG_MIRRORING;
1598       break;
1599 #endif
1600     case PROP_DEINTERLACE_MODE:
1601       thiz->deinterlace_mode = g_value_get_enum (value);
1602       break;
1603     case PROP_DEINTERLACE_METHOD:
1604       thiz->deinterlace_method = g_value_get_enum (value);
1605       break;
1606     case PROP_HUE:
1607       thiz->hue = g_value_get_float (value);
1608       thiz->flags |= GST_MSDK_FLAG_HUE;
1609       break;
1610     case PROP_SATURATION:
1611       thiz->saturation = g_value_get_float (value);
1612       thiz->flags |= GST_MSDK_FLAG_SATURATION;
1613       break;
1614     case PROP_BRIGHTNESS:
1615       thiz->brightness = g_value_get_float (value);
1616       thiz->flags |= GST_MSDK_FLAG_BRIGHTNESS;
1617       break;
1618     case PROP_CONTRAST:
1619       thiz->contrast = g_value_get_float (value);
1620       thiz->flags |= GST_MSDK_FLAG_CONTRAST;
1621       break;
1622     case PROP_DETAIL:
1623       thiz->detail = g_value_get_uint (value);
1624       thiz->flags |= GST_MSDK_FLAG_DETAIL;
1625       break;
1626     case PROP_SCALING_MODE:
1627       thiz->scaling_mode = g_value_get_enum (value);
1628       thiz->flags |= GST_MSDK_FLAG_SCALING_MODE;
1629       break;
1630     case PROP_FORCE_ASPECT_RATIO:
1631       thiz->keep_aspect = g_value_get_boolean (value);
1632       break;
1633     case PROP_FRC_ALGORITHM:
1634       thiz->frc_algm = g_value_get_enum (value);
1635       break;
1636     case PROP_VIDEO_DIRECTION:
1637       thiz->video_direction = g_value_get_enum (value);
1638       thiz->flags |= GST_MSDK_FLAG_VIDEO_DIRECTION;
1639       break;
1640     case PROP_CROP_LEFT:
1641       thiz->crop_left = g_value_get_uint (value);
1642       break;
1643     case PROP_CROP_RIGHT:
1644       thiz->crop_right = g_value_get_uint (value);
1645       break;
1646     case PROP_CROP_TOP:
1647       thiz->crop_top = g_value_get_uint (value);
1648       break;
1649     case PROP_CROP_BOTTOM:
1650       thiz->crop_bottom = g_value_get_uint (value);
1651       break;
1652     default:
1653       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1654       break;
1655   }
1656 }
1657
1658 static void
1659 gst_msdkvpp_get_property (GObject * object, guint prop_id,
1660     GValue * value, GParamSpec * pspec)
1661 {
1662   GstMsdkVPP *thiz = GST_MSDKVPP (object);
1663
1664   switch (prop_id) {
1665     case PROP_HARDWARE:
1666       g_value_set_boolean (value, thiz->hardware);
1667       break;
1668     case PROP_ASYNC_DEPTH:
1669       g_value_set_uint (value, thiz->async_depth);
1670       break;
1671     case PROP_DENOISE:
1672       g_value_set_uint (value, thiz->denoise_factor);
1673       break;
1674 #ifndef GST_REMOVE_DEPRECATED
1675     case PROP_ROTATION:
1676       g_value_set_enum (value, thiz->rotation);
1677       break;
1678     case PROP_MIRRORING:
1679       g_value_set_enum (value, thiz->mirroring);
1680       break;
1681 #endif
1682     case PROP_DEINTERLACE_MODE:
1683       g_value_set_enum (value, thiz->deinterlace_mode);
1684       break;
1685     case PROP_DEINTERLACE_METHOD:
1686       g_value_set_enum (value, thiz->deinterlace_method);
1687       break;
1688     case PROP_HUE:
1689       g_value_set_float (value, thiz->hue);
1690       break;
1691     case PROP_SATURATION:
1692       g_value_set_float (value, thiz->saturation);
1693       break;
1694     case PROP_BRIGHTNESS:
1695       g_value_set_float (value, thiz->brightness);
1696       break;
1697     case PROP_CONTRAST:
1698       g_value_set_float (value, thiz->contrast);
1699       break;
1700     case PROP_DETAIL:
1701       g_value_set_uint (value, thiz->detail);
1702       break;
1703     case PROP_SCALING_MODE:
1704       g_value_set_enum (value, thiz->scaling_mode);
1705       break;
1706     case PROP_FORCE_ASPECT_RATIO:
1707       g_value_set_boolean (value, thiz->keep_aspect);
1708       break;
1709     case PROP_FRC_ALGORITHM:
1710       g_value_set_enum (value, thiz->frc_algm);
1711       break;
1712     case PROP_VIDEO_DIRECTION:
1713       g_value_set_enum (value, thiz->video_direction);
1714       break;
1715     case PROP_CROP_LEFT:
1716       g_value_set_uint (value, thiz->crop_left);
1717       break;
1718     case PROP_CROP_RIGHT:
1719       g_value_set_uint (value, thiz->crop_right);
1720       break;
1721     case PROP_CROP_TOP:
1722       g_value_set_uint (value, thiz->crop_top);
1723       break;
1724     case PROP_CROP_BOTTOM:
1725       g_value_set_uint (value, thiz->crop_bottom);
1726       break;
1727     default:
1728       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1729       break;
1730   }
1731 }
1732
1733 static void
1734 gst_msdkvpp_dispose (GObject * object)
1735 {
1736   GstMsdkVPP *thiz = GST_MSDKVPP (object);
1737
1738   gst_clear_object (&thiz->old_context);
1739
1740   G_OBJECT_CLASS (parent_class)->dispose (object);
1741 }
1742
1743 static void
1744 gst_msdkvpp_set_context (GstElement * element, GstContext * context)
1745 {
1746   GstMsdkContext *msdk_context = NULL;
1747   GstMsdkVPP *thiz = GST_MSDKVPP (element);
1748
1749   if (gst_msdk_context_get_context (context, &msdk_context)) {
1750     gst_object_replace ((GstObject **) & thiz->context,
1751         (GstObject *) msdk_context);
1752     gst_object_unref (msdk_context);
1753   } else
1754 #ifndef _WIN32
1755     if (gst_msdk_context_from_external_va_display (context,
1756           thiz->hardware, 0 /* GST_MSDK_JOB_VPP will be set later */ ,
1757           &msdk_context)) {
1758     gst_object_replace ((GstObject **) & thiz->context,
1759         (GstObject *) msdk_context);
1760     gst_object_unref (msdk_context);
1761   }
1762 #else
1763     if (gst_msdk_context_from_external_d3d11_device (context,
1764           thiz->hardware, 0 /* GST_MSDK_JOB_VPP will be set later */ ,
1765           &msdk_context)) {
1766     gst_object_replace ((GstObject **) & thiz->context,
1767         (GstObject *) msdk_context);
1768     gst_object_unref (msdk_context);
1769   }
1770 #endif
1771
1772   GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
1773 }
1774
1775 static void
1776 gst_msdkvpp_class_init (GstMsdkVPPClass * klass)
1777 {
1778   GObjectClass *gobject_class;
1779   GstElementClass *element_class;
1780   GstBaseTransformClass *trans_class;
1781   GParamSpec *obj_properties[PROP_N] = { NULL, };
1782
1783   gobject_class = G_OBJECT_CLASS (klass);
1784   element_class = GST_ELEMENT_CLASS (klass);
1785   trans_class = GST_BASE_TRANSFORM_CLASS (klass);
1786
1787   gobject_class->set_property = gst_msdkvpp_set_property;
1788   gobject_class->get_property = gst_msdkvpp_get_property;
1789   gobject_class->dispose = gst_msdkvpp_dispose;
1790
1791   element_class->set_context = gst_msdkvpp_set_context;
1792
1793   gst_element_class_add_static_pad_template (element_class,
1794       &gst_msdkvpp_src_factory);
1795   gst_element_class_add_static_pad_template (element_class,
1796       &gst_msdkvpp_sink_factory);
1797
1798   gst_element_class_set_static_metadata (element_class,
1799       "Intel MSDK Video Postprocessor",
1800       "Filter/Converter/Video;Filter/Converter/Video/Scaler;"
1801       "Filter/Effect/Video;Filter/Effect/Video/Deinterlace",
1802       "Video Postprocessing Filter based on " MFX_API_SDK,
1803       "Sreerenj Balachandrn <sreerenj.balachandran@intel.com>");
1804
1805   trans_class->start = GST_DEBUG_FUNCPTR (gst_msdkvpp_start);
1806   trans_class->stop = GST_DEBUG_FUNCPTR (gst_msdkvpp_stop);
1807   trans_class->transform_caps = GST_DEBUG_FUNCPTR (gst_msdkvpp_transform_caps);
1808   trans_class->fixate_caps = GST_DEBUG_FUNCPTR (gst_msdkvpp_fixate_caps);
1809   trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_msdkvpp_set_caps);
1810   trans_class->transform = GST_DEBUG_FUNCPTR (gst_msdkvpp_transform);
1811   trans_class->propose_allocation =
1812       GST_DEBUG_FUNCPTR (gst_msdkvpp_propose_allocation);
1813   trans_class->decide_allocation =
1814       GST_DEBUG_FUNCPTR (gst_msdkvpp_decide_allocation);
1815   trans_class->prepare_output_buffer =
1816       GST_DEBUG_FUNCPTR (gst_msdkvpp_prepare_output_buffer);
1817   trans_class->query = GST_DEBUG_FUNCPTR (gst_msdkvpp_query);
1818
1819   obj_properties[PROP_HARDWARE] =
1820       g_param_spec_boolean ("hardware", "Hardware", "Enable hardware VPP",
1821       PROP_HARDWARE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1822
1823   obj_properties[PROP_ASYNC_DEPTH] =
1824       g_param_spec_uint ("async-depth", "Async Depth",
1825       "Depth of asynchronous pipeline",
1826       1, 1, PROP_ASYNC_DEPTH_DEFAULT,
1827       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1828
1829   obj_properties[PROP_DENOISE] =
1830       g_param_spec_uint ("denoise", "Denoising factor",
1831       "Denoising Factor",
1832       0, 100, PROP_DENOISE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1833
1834 #ifndef GST_REMOVE_DEPRECATED
1835   obj_properties[PROP_ROTATION] =
1836       g_param_spec_enum ("rotation", "Rotation",
1837       "Rotation Angle (DEPRECATED, use video-direction instead)",
1838       gst_msdkvpp_rotation_get_type (), PROP_ROTATION_DEFAULT,
1839       G_PARAM_DEPRECATED | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1840
1841   obj_properties[PROP_MIRRORING] =
1842       g_param_spec_enum ("mirroring", "Mirroring",
1843       "The Mirroring type (DEPRECATED, use video-direction instead)",
1844       gst_msdkvpp_mirroring_get_type (), PROP_MIRRORING_DEFAULT,
1845       G_PARAM_DEPRECATED | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1846
1847 #endif
1848
1849   obj_properties[PROP_DEINTERLACE_MODE] =
1850       g_param_spec_enum ("deinterlace-mode", "Deinterlace Mode",
1851       "Deinterlace mode to use", gst_msdkvpp_deinterlace_mode_get_type (),
1852       PROP_DEINTERLACE_MODE_DEFAULT,
1853       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1854
1855   obj_properties[PROP_DEINTERLACE_METHOD] =
1856       g_param_spec_enum ("deinterlace-method", "Deinterlace Method",
1857       "Deinterlace method to use", gst_msdkvpp_deinterlace_method_get_type (),
1858       PROP_DEINTERLACE_METHOD_DEFAULT,
1859       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1860
1861   obj_properties[PROP_HUE] =
1862       g_param_spec_float ("hue", "Hue",
1863       "The hue of the video",
1864       -180, 180, PROP_HUE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1865
1866   obj_properties[PROP_SATURATION] =
1867       g_param_spec_float ("saturation", "Saturation",
1868       "The Saturation of the video",
1869       0, 10, PROP_SATURATION_DEFAULT,
1870       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1871
1872   obj_properties[PROP_BRIGHTNESS] =
1873       g_param_spec_float ("brightness", "Brightness",
1874       "The Brightness of the video",
1875       -100, 100, PROP_BRIGHTNESS_DEFAULT,
1876       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1877
1878   obj_properties[PROP_CONTRAST] =
1879       g_param_spec_float ("contrast", "Contrast",
1880       "The Contrast of the video",
1881       0, 10, PROP_CONTRAST_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1882
1883   obj_properties[PROP_DETAIL] =
1884       g_param_spec_uint ("detail", "Detail",
1885       "The factor of detail/edge enhancement filter algorithm",
1886       0, 100, PROP_DETAIL_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1887
1888   obj_properties[PROP_SCALING_MODE] =
1889       g_param_spec_enum ("scaling-mode", "Scaling Mode",
1890       "The Scaling mode to use", gst_msdkvpp_scaling_mode_get_type (),
1891       PROP_SCALING_MODE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1892
1893   obj_properties[PROP_FORCE_ASPECT_RATIO] =
1894       g_param_spec_boolean ("force-aspect-ratio", "Force Aspect Ratio",
1895       "When enabled, scaling will respect original aspect ratio",
1896       PROP_FORCE_ASPECT_RATIO_DEFAULT,
1897       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1898
1899   obj_properties[PROP_FRC_ALGORITHM] =
1900       g_param_spec_enum ("frc-algorithm", "FrameRateControl Algorithm",
1901       "The Framerate Control Alogorithm to use",
1902       gst_msdkvpp_frc_algorithm_get_type (), PROP_FRC_ALGORITHM_DEFAULT,
1903       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1904
1905   /*
1906    * The video-direction to use, expressed as an enum value. See
1907    * #GstVideoOrientationMethod.
1908    */
1909   obj_properties[PROP_VIDEO_DIRECTION] = g_param_spec_enum ("video-direction",
1910       "Video Direction", "Video direction: rotation and flipping"
1911 #ifndef GST_REMOVE_DEPRECATED
1912       ", it will override both mirroring & rotation properties if set explicitly"
1913 #endif
1914       ,
1915       GST_TYPE_VIDEO_ORIENTATION_METHOD,
1916       PROP_VIDEO_DIRECTION_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1917
1918   obj_properties[PROP_CROP_LEFT] = g_param_spec_uint ("crop-left",
1919       "Crop Left", "Pixels to crop at left",
1920       0, G_MAXUINT16, PROP_CROP_LEFT_DEFAULT,
1921       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1922
1923   obj_properties[PROP_CROP_RIGHT] = g_param_spec_uint ("crop-right",
1924       "Crop Right", "Pixels to crop at right",
1925       0, G_MAXUINT16, PROP_CROP_RIGHT_DEFAULT,
1926       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1927
1928   obj_properties[PROP_CROP_TOP] = g_param_spec_uint ("crop-top",
1929       "Crop Top", "Pixels to crop at top",
1930       0, G_MAXUINT16, PROP_CROP_TOP_DEFAULT,
1931       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1932
1933   obj_properties[PROP_CROP_BOTTOM] = g_param_spec_uint ("crop-bottom",
1934       "Crop Bottom", "Pixels to crop at bottom",
1935       0, G_MAXUINT16, PROP_CROP_BOTTOM_DEFAULT,
1936       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1937
1938   g_object_class_install_properties (gobject_class, PROP_N, obj_properties);
1939 }
1940
1941 static void
1942 gst_msdkvpp_init (GstMsdkVPP * thiz)
1943 {
1944   thiz->initialized = FALSE;
1945   thiz->hardware = PROP_HARDWARE_DEFAULT;
1946   thiz->async_depth = PROP_ASYNC_DEPTH_DEFAULT;
1947   thiz->denoise_factor = PROP_DENOISE_DEFAULT;
1948 #ifndef GST_REMOVE_DEPRECATED
1949   thiz->rotation = PROP_ROTATION_DEFAULT;
1950   thiz->mirroring = PROP_MIRRORING_DEFAULT;
1951 #else
1952   thiz->rotation = MFX_ANGLE_0;
1953   thiz->mirroring = MFX_MIRRORING_DISABLED;
1954 #endif
1955   thiz->deinterlace_mode = PROP_DEINTERLACE_MODE_DEFAULT;
1956   thiz->deinterlace_method = PROP_DEINTERLACE_METHOD_DEFAULT;
1957   thiz->buffer_duration = GST_CLOCK_TIME_NONE;
1958   thiz->hue = PROP_HUE_DEFAULT;
1959   thiz->saturation = PROP_SATURATION_DEFAULT;
1960   thiz->brightness = PROP_BRIGHTNESS_DEFAULT;
1961   thiz->contrast = PROP_CONTRAST_DEFAULT;
1962   thiz->detail = PROP_DETAIL_DEFAULT;
1963   thiz->scaling_mode = PROP_SCALING_MODE_DEFAULT;
1964   thiz->keep_aspect = PROP_FORCE_ASPECT_RATIO_DEFAULT;
1965   thiz->frc_algm = PROP_FRC_ALGORITHM_DEFAULT;
1966   thiz->video_direction = PROP_VIDEO_DIRECTION_DEFAULT;
1967   thiz->crop_left = PROP_CROP_LEFT_DEFAULT;
1968   thiz->crop_right = PROP_CROP_RIGHT_DEFAULT;
1969   thiz->crop_top = PROP_CROP_TOP_DEFAULT;
1970   thiz->crop_bottom = PROP_CROP_BOTTOM_DEFAULT;
1971
1972   gst_video_info_init (&thiz->sinkpad_info);
1973   gst_video_info_init (&thiz->srcpad_info);
1974 }