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