msdk: vpp: Add support for horizontal and vertical mirroring
[platform/upstream/gstreamer.git] / 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 #ifdef HAVE_CONFIG_H
35 #  include <config.h>
36 #endif
37
38 #include <stdlib.h>
39
40 #include "gstmsdkvpp.h"
41 #include "gstmsdkbufferpool.h"
42 #include "gstmsdkvideomemory.h"
43 #include "gstmsdksystemmemory.h"
44 #include "gstmsdkcontextutil.h"
45 #include "gstmsdkvpputil.h"
46
47 GST_DEBUG_CATEGORY_EXTERN (gst_msdkvpp_debug);
48 #define GST_CAT_DEFAULT gst_msdkvpp_debug
49
50 static GstStaticPadTemplate gst_msdkvpp_sink_factory =
51 GST_STATIC_PAD_TEMPLATE ("sink",
52     GST_PAD_SINK,
53     GST_PAD_ALWAYS,
54     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ NV12, I420, YUY2, UYVY, BGRA }")
55         ", " "interlace-mode = (string){ progressive, interleaved, mixed }"));
56
57 static GstStaticPadTemplate gst_msdkvpp_src_factory =
58 GST_STATIC_PAD_TEMPLATE ("src",
59     GST_PAD_SRC,
60     GST_PAD_ALWAYS,
61     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ NV12, BGRA }") ", "
62         "interlace-mode = (string){ progressive, interleaved, mixed }"));
63
64 enum
65 {
66   PROP_0,
67   PROP_HARDWARE,
68   PROP_ASYNC_DEPTH,
69   PROP_DENOISE,
70   PROP_ROTATION,
71   PROP_DEINTERLACE_MODE,
72   PROP_DEINTERLACE_METHOD,
73   PROP_HUE,
74   PROP_SATURATION,
75   PROP_BRIGHTNESS,
76   PROP_CONTRAST,
77   PROP_DETAIL,
78   PROP_MIRRORING,
79   PROP_N,
80 };
81
82 #define PROP_HARDWARE_DEFAULT            TRUE
83 #define PROP_ASYNC_DEPTH_DEFAULT         1
84 #define PROP_DENOISE_DEFAULT             0
85 #define PROP_ROTATION_DEFAULT            MFX_ANGLE_0
86 #define PROP_DEINTERLACE_MODE_DEFAULT    GST_MSDKVPP_DEINTERLACE_MODE_AUTO
87 #define PROP_DEINTERLACE_METHOD_DEFAULT  MFX_DEINTERLACING_BOB
88 #define PROP_HUE_DEFAULT                 0
89 #define PROP_SATURATION_DEFAULT          1
90 #define PROP_BRIGHTNESS_DEFAULT          0
91 #define PROP_CONTRAST_DEFAULT            1
92 #define PROP_DETAIL_DEFAULT              0
93 #define PROP_MIRRORING_DEFAULT           MFX_MIRRORING_DISABLED
94
95 #define gst_msdkvpp_parent_class parent_class
96 G_DEFINE_TYPE (GstMsdkVPP, gst_msdkvpp, GST_TYPE_BASE_TRANSFORM);
97
98 typedef struct
99 {
100   mfxFrameSurface1 *surface;
101   GstBuffer *buf;
102 } MsdkSurface;
103
104 static void
105 free_msdk_surface (MsdkSurface * surface)
106 {
107   if (surface->buf)
108     gst_buffer_unref (surface->buf);
109   g_slice_free (MsdkSurface, surface);
110 }
111
112 static void
113 gst_msdkvpp_add_extra_param (GstMsdkVPP * thiz, mfxExtBuffer * param)
114 {
115   if (thiz->num_extra_params < MAX_EXTRA_PARAMS) {
116     thiz->extra_params[thiz->num_extra_params] = param;
117     thiz->num_extra_params++;
118   }
119 }
120
121 static gboolean
122 ensure_context (GstBaseTransform * trans)
123 {
124   GstMsdkVPP *thiz = GST_MSDKVPP (trans);
125
126   if (gst_msdk_context_prepare (GST_ELEMENT_CAST (thiz), &thiz->context)) {
127     GST_INFO_OBJECT (thiz, "Found context from neighbour %" GST_PTR_FORMAT,
128         thiz->context);
129
130     if (gst_msdk_context_get_job_type (thiz->context) & GST_MSDK_JOB_VPP) {
131       GstMsdkContext *parent_context;
132
133       parent_context = thiz->context;
134       thiz->context = gst_msdk_context_new_with_parent (parent_context);
135       gst_object_unref (parent_context);
136
137       GST_INFO_OBJECT (thiz,
138           "Creating new context %" GST_PTR_FORMAT " with joined session",
139           thiz->context);
140     } else {
141       gst_msdk_context_add_job_type (thiz->context, GST_MSDK_JOB_VPP);
142     }
143   } else {
144     if (!gst_msdk_context_ensure_context (GST_ELEMENT_CAST (thiz),
145             thiz->hardware, GST_MSDK_JOB_VPP))
146       return FALSE;
147     GST_INFO_OBJECT (thiz, "Creating new context %" GST_PTR_FORMAT,
148         thiz->context);
149   }
150
151   gst_msdk_context_add_shared_async_depth (thiz->context, thiz->async_depth);
152
153   return TRUE;
154 }
155
156 static GstBuffer *
157 create_output_buffer (GstMsdkVPP * thiz)
158 {
159   GstBuffer *outbuf;
160   GstFlowReturn ret;
161   GstBufferPool *pool = thiz->srcpad_buffer_pool;
162
163   g_return_val_if_fail (pool != NULL, NULL);
164
165   if (!gst_buffer_pool_is_active (pool) &&
166       !gst_buffer_pool_set_active (pool, TRUE))
167     goto error_activate_pool;
168
169   outbuf = NULL;
170   ret = gst_buffer_pool_acquire_buffer (pool, &outbuf, NULL);
171   if (ret != GST_FLOW_OK || !outbuf)
172     goto error_create_buffer;
173
174   return outbuf;
175
176   /* ERRORS */
177 error_activate_pool:
178   {
179     GST_ERROR_OBJECT (thiz, "failed to activate output video buffer pool");
180     return NULL;
181   }
182 error_create_buffer:
183   {
184     GST_ERROR_OBJECT (thiz, "failed to create output video buffer");
185     return NULL;
186   }
187 }
188
189 static GstFlowReturn
190 gst_msdkvpp_prepare_output_buffer (GstBaseTransform * trans,
191     GstBuffer * inbuf, GstBuffer ** outbuf_ptr)
192 {
193   GstMsdkVPP *thiz = GST_MSDKVPP (trans);
194
195   if (gst_base_transform_is_passthrough (trans)) {
196     *outbuf_ptr = inbuf;
197     return GST_FLOW_OK;
198   }
199
200   *outbuf_ptr = create_output_buffer (thiz);
201   return *outbuf_ptr ? GST_FLOW_OK : GST_FLOW_ERROR;
202 }
203
204 static GstBufferPool *
205 gst_msdkvpp_create_buffer_pool (GstMsdkVPP * thiz, GstPadDirection direction,
206     GstCaps * caps, guint min_num_buffers)
207 {
208   GstBufferPool *pool = NULL;
209   GstStructure *config;
210   GstAllocator *allocator = NULL;
211   GstVideoInfo info;
212   GstVideoInfo *pool_info = NULL;
213   GstVideoAlignment align;
214   GstAllocationParams params = { 0, 31, 0, 0, };
215   mfxFrameAllocResponse *alloc_resp = NULL;
216
217   if (direction == GST_PAD_SINK) {
218     alloc_resp = &thiz->in_alloc_resp;
219     pool_info = &thiz->sinkpad_buffer_pool_info;
220   } else if (direction == GST_PAD_SRC) {
221     alloc_resp = &thiz->out_alloc_resp;
222     pool_info = &thiz->srcpad_buffer_pool_info;
223   }
224
225   pool = gst_msdk_buffer_pool_new (thiz->context, alloc_resp);
226   if (!pool)
227     goto error_no_pool;
228
229   if (!gst_video_info_from_caps (&info, caps))
230     goto error_no_video_info;
231
232   gst_msdk_set_video_alignment (&info, &align);
233   gst_video_info_align (&info, &align);
234
235   if (thiz->use_video_memory)
236     allocator = gst_msdk_video_allocator_new (thiz->context, &info, alloc_resp);
237   else
238     allocator = gst_msdk_system_allocator_new (&info);
239
240   if (!allocator)
241     goto error_no_allocator;
242
243   config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
244   gst_buffer_pool_config_set_params (config, caps, info.size, min_num_buffers,
245       0);
246
247   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
248   gst_buffer_pool_config_add_option (config,
249       GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
250   if (thiz->use_video_memory)
251     gst_buffer_pool_config_add_option (config,
252         GST_BUFFER_POOL_OPTION_MSDK_USE_VIDEO_MEMORY);
253
254   gst_buffer_pool_config_set_video_alignment (config, &align);
255   gst_buffer_pool_config_set_allocator (config, allocator, &params);
256   gst_object_unref (allocator);
257
258   if (!gst_buffer_pool_set_config (pool, config))
259     goto error_pool_config;
260
261   /* Updating pool_info with algined info of allocator */
262   *pool_info = info;
263
264   return pool;
265
266 error_no_pool:
267   {
268     GST_INFO_OBJECT (thiz, "Failed to create bufferpool");
269     return NULL;
270   }
271 error_no_video_info:
272   {
273     GST_INFO_OBJECT (thiz, "Failed to get Video info from caps");
274     return NULL;
275   }
276 error_no_allocator:
277   {
278     GST_INFO_OBJECT (thiz, "Failed to create allocator");
279     if (pool)
280       gst_object_unref (pool);
281     return NULL;
282   }
283 error_pool_config:
284   {
285     GST_INFO_OBJECT (thiz, "Failed to set config");
286     if (pool)
287       gst_object_unref (pool);
288     if (allocator)
289       gst_object_unref (allocator);
290     return NULL;
291   }
292 }
293
294 static gboolean
295 gst_msdkvpp_decide_allocation (GstBaseTransform * trans, GstQuery * query)
296 {
297   GstMsdkVPP *thiz = GST_MSDKVPP (trans);
298   GstVideoInfo info;
299   GstBufferPool *pool = NULL;
300   GstStructure *config = NULL;
301   GstCaps *caps;
302   guint size = 0, min_buffers = 0, max_buffers = 0;
303   GstAllocator *allocator = NULL;
304   GstAllocationParams params;
305   gboolean update_pool = FALSE;
306
307   gst_query_parse_allocation (query, &caps, NULL);
308   if (!caps) {
309     GST_ERROR_OBJECT (thiz, "Failed to parse the decide_allocation caps");
310     return FALSE;
311   }
312   if (!gst_video_info_from_caps (&info, caps)) {
313     GST_ERROR_OBJECT (thiz, "Failed to get video info");
314     return FALSE;
315   }
316
317   if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL))
318     thiz->add_video_meta = TRUE;
319   else
320     thiz->add_video_meta = FALSE;
321
322   if (gst_query_get_n_allocation_pools (query) > 0) {
323     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min_buffers,
324         &max_buffers);
325     update_pool = TRUE;
326     size = MAX (size, GST_VIDEO_INFO_SIZE (&info));
327
328     if (pool && !GST_IS_MSDK_BUFFER_POOL (pool)) {
329       GST_INFO_OBJECT (thiz, "ignoring non-msdk pool: %" GST_PTR_FORMAT, pool);
330       g_clear_object (&pool);
331     }
332   }
333
334   if (!pool) {
335     gst_object_unref (thiz->srcpad_buffer_pool);
336     pool =
337         gst_msdkvpp_create_buffer_pool (thiz, GST_PAD_SRC, caps, min_buffers);
338     thiz->srcpad_buffer_pool = pool;
339
340     /* get the configured pool properties inorder to set in query */
341     config = gst_buffer_pool_get_config (pool);
342     gst_buffer_pool_config_get_params (config, &caps, &size, &min_buffers,
343         &max_buffers);
344     if (gst_buffer_pool_config_get_allocator (config, &allocator, &params))
345       gst_query_add_allocation_param (query, allocator, &params);
346     gst_structure_free (config);
347   }
348
349   if (update_pool)
350     gst_query_set_nth_allocation_pool (query, 0, pool, size, min_buffers,
351         max_buffers);
352   else
353     gst_query_add_allocation_pool (query, pool, size, min_buffers, max_buffers);
354
355   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
356
357   /* Fixme if downstream doesn't have videometa support, msdkvpp should
358    * copy the output buffers */
359
360   return TRUE;
361 }
362
363 static gboolean
364 gst_msdkvpp_propose_allocation (GstBaseTransform * trans,
365     GstQuery * decide_query, GstQuery * query)
366 {
367   GstMsdkVPP *thiz = GST_MSDKVPP (trans);
368   GstVideoInfo info;
369   GstBufferPool *pool = NULL;
370   GstAllocator *allocator = NULL;
371   GstCaps *caps;
372   GstStructure *config;
373   gboolean need_pool;
374   guint size;
375   GstAllocationParams params;
376
377   gst_query_parse_allocation (query, &caps, &need_pool);
378   if (!caps) {
379     GST_ERROR_OBJECT (thiz, "Failed to parse the allocation caps");
380     return FALSE;
381   }
382
383   if (!gst_video_info_from_caps (&info, caps)) {
384     GST_ERROR_OBJECT (thiz, "Failed to get video info");
385     return FALSE;
386   }
387
388   size = MAX (info.size, GST_VIDEO_INFO_SIZE (&thiz->sinkpad_buffer_pool_info));
389
390   /* We already created a pool while setting the caps
391    * just to make sure the pipeline works even if there is
392    * no allocation query from upstream (theoratical ??).Provide the
393    * same pool in query if required/possible */
394   if (!gst_video_info_is_equal (&thiz->sinkpad_buffer_pool_info, &info)) {
395     gst_object_unref (thiz->sinkpad_buffer_pool);
396     thiz->sinkpad_buffer_pool =
397         gst_msdkvpp_create_buffer_pool (thiz, GST_PAD_SINK, caps,
398         thiz->in_num_surfaces);
399   }
400
401   pool = thiz->sinkpad_buffer_pool;
402
403   config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
404
405   gst_buffer_pool_config_get_params (config, NULL, &size, NULL, NULL);
406
407   if (gst_buffer_pool_config_get_allocator (config, &allocator, &params))
408     gst_query_add_allocation_param (query, allocator, &params);
409   gst_structure_free (config);
410
411   /* if upstream does't have a pool requirement, set only
412    *  size, min_buffers and max_buffers in query */
413   if (!need_pool)
414     pool = NULL;
415
416   gst_query_add_allocation_pool (query, pool, size, thiz->in_num_surfaces, 0);
417   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
418
419   return GST_BASE_TRANSFORM_CLASS (parent_class)->propose_allocation (trans,
420       decide_query, query);
421 }
422
423 static MsdkSurface *
424 get_surface_from_pool (GstMsdkVPP * thiz, GstBufferPool * pool,
425     GstBufferPoolAcquireParams * params)
426 {
427   GstBuffer *new_buffer;
428   mfxFrameSurface1 *new_surface;
429   MsdkSurface *msdk_surface;
430
431   if (!gst_buffer_pool_is_active (pool) &&
432       !gst_buffer_pool_set_active (pool, TRUE)) {
433     GST_ERROR_OBJECT (pool, "failed to activate buffer pool");
434     return NULL;
435   }
436
437   if (gst_buffer_pool_acquire_buffer (pool, &new_buffer, params) != GST_FLOW_OK) {
438     GST_ERROR_OBJECT (pool, "failed to acquire a buffer from pool");
439     return NULL;
440   }
441
442   if (gst_msdk_is_msdk_buffer (new_buffer))
443     new_surface = gst_msdk_get_surface_from_buffer (new_buffer);
444   else {
445     GST_ERROR_OBJECT (pool, "the acquired memory is not MSDK memory");
446     return NULL;
447   }
448
449   msdk_surface = g_slice_new0 (MsdkSurface);
450   msdk_surface->surface = new_surface;
451   msdk_surface->buf = new_buffer;
452
453   return msdk_surface;
454 }
455
456 static MsdkSurface *
457 get_msdk_surface_from_input_buffer (GstMsdkVPP * thiz, GstBuffer * inbuf)
458 {
459   GstVideoFrame src_frame, out_frame;
460   MsdkSurface *msdk_surface;
461
462   if (gst_msdk_is_msdk_buffer (inbuf)) {
463     msdk_surface = g_slice_new0 (MsdkSurface);
464     msdk_surface->surface = gst_msdk_get_surface_from_buffer (inbuf);
465     msdk_surface->buf = gst_buffer_ref (inbuf);
466     return msdk_surface;
467   }
468
469   /* If upstream hasn't accpeted the proposed msdk bufferpool,
470    * just copy frame to msdk buffer and take a surface from it.
471    */
472   if (!(msdk_surface =
473           get_surface_from_pool (thiz, thiz->sinkpad_buffer_pool, NULL)))
474     goto error;
475
476   if (!gst_video_frame_map (&src_frame, &thiz->sinkpad_info, inbuf,
477           GST_MAP_READ)) {
478     GST_ERROR_OBJECT (thiz, "failed to map the frame for source");
479     goto error;
480   }
481
482   if (!gst_video_frame_map (&out_frame, &thiz->sinkpad_buffer_pool_info,
483           msdk_surface->buf, GST_MAP_WRITE)) {
484     GST_ERROR_OBJECT (thiz, "failed to map the frame for destination");
485     gst_video_frame_unmap (&src_frame);
486     goto error;
487   }
488
489   if (!gst_video_frame_copy (&out_frame, &src_frame)) {
490     GST_ERROR_OBJECT (thiz, "failed to copy frame");
491     gst_video_frame_unmap (&out_frame);
492     gst_video_frame_unmap (&src_frame);
493     goto error;
494   }
495
496   gst_video_frame_unmap (&out_frame);
497   gst_video_frame_unmap (&src_frame);
498
499   return msdk_surface;
500
501 error:
502   return NULL;
503 }
504
505 static GstFlowReturn
506 gst_msdkvpp_transform (GstBaseTransform * trans, GstBuffer * inbuf,
507     GstBuffer * outbuf)
508 {
509   GstMsdkVPP *thiz = GST_MSDKVPP (trans);
510   mfxSession session;
511   mfxSyncPoint sync_point = NULL;
512   mfxStatus status;
513   MsdkSurface *in_surface = NULL;
514   MsdkSurface *out_surface = NULL;
515
516   in_surface = get_msdk_surface_from_input_buffer (thiz, inbuf);
517   if (!in_surface)
518     return GST_FLOW_ERROR;
519
520   if (gst_msdk_is_msdk_buffer (outbuf)) {
521     out_surface = g_slice_new0 (MsdkSurface);
522     out_surface->surface = gst_msdk_get_surface_from_buffer (outbuf);
523   } else {
524     GST_ERROR ("Failed to get msdk outsurface!");
525     return GST_FLOW_ERROR;
526   }
527
528   session = gst_msdk_context_get_session (thiz->context);
529   for (;;) {
530     status =
531         MFXVideoVPP_RunFrameVPPAsync (session, in_surface->surface,
532         out_surface->surface, NULL, &sync_point);
533     if (status != MFX_WRN_DEVICE_BUSY)
534       break;
535     /* If device is busy, wait 1ms and retry, as per MSDK's recomendation */
536     g_usleep (1000);
537   };
538
539   if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA
540       && status != MFX_ERR_MORE_SURFACE)
541     goto vpp_error;
542
543   /* No output generated */
544   if (status == MFX_ERR_MORE_DATA)
545     goto error_more_data;
546   if (sync_point)
547     MFXVideoCORE_SyncOperation (session, sync_point, 10000);
548
549   /* More than one output buffers are generated */
550   if (status == MFX_ERR_MORE_SURFACE)
551     status = MFX_ERR_NONE;
552
553   gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
554
555   free_msdk_surface (in_surface);
556   return GST_FLOW_OK;
557
558 vpp_error:
559   GST_ERROR_OBJECT (thiz, "MSDK Failed to do VPP");
560   free_msdk_surface (in_surface);
561   free_msdk_surface (out_surface);
562   return GST_FLOW_ERROR;
563
564 error_more_data:
565   GST_WARNING_OBJECT (thiz,
566       "MSDK Requries additional input for processing, "
567       "Retruning FLOW_DROPPED since no output buffer was generated");
568   free_msdk_surface (in_surface);
569   return GST_BASE_TRANSFORM_FLOW_DROPPED;
570 }
571
572 static void
573 gst_msdkvpp_close (GstMsdkVPP * thiz)
574 {
575   mfxStatus status;
576
577   if (!thiz->context)
578     return;
579
580   GST_DEBUG_OBJECT (thiz, "Closing VPP 0x%p", thiz->context);
581   status = MFXVideoVPP_Close (gst_msdk_context_get_session (thiz->context));
582   if (status != MFX_ERR_NONE && status != MFX_ERR_NOT_INITIALIZED) {
583     GST_WARNING_OBJECT (thiz, "Encoder close failed (%s)",
584         msdk_status_to_string (status));
585   }
586
587   if (thiz->context)
588     gst_object_replace ((GstObject **) & thiz->context, NULL);
589
590   memset (&thiz->param, 0, sizeof (thiz->param));
591
592   if (thiz->sinkpad_buffer_pool)
593     gst_object_unref (thiz->sinkpad_buffer_pool);
594   thiz->sinkpad_buffer_pool = NULL;
595   if (thiz->srcpad_buffer_pool)
596     gst_object_unref (thiz->srcpad_buffer_pool);
597   thiz->srcpad_buffer_pool = NULL;
598
599   thiz->field_duration = GST_CLOCK_TIME_NONE;
600   gst_video_info_init (&thiz->sinkpad_info);
601   gst_video_info_init (&thiz->srcpad_info);
602 }
603
604 static void
605 ensure_filters (GstMsdkVPP * thiz)
606 {
607   guint n_filters = 0;
608
609   /* Denoise */
610   if (thiz->flags & GST_MSDK_FLAG_DENOISE) {
611     mfxExtVPPDenoise *mfx_denoise = &thiz->mfx_denoise;
612     mfx_denoise->Header.BufferId = MFX_EXTBUFF_VPP_DENOISE;
613     mfx_denoise->Header.BufferSz = sizeof (mfxExtVPPDenoise);
614     mfx_denoise->DenoiseFactor = thiz->denoise_factor;
615     gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_denoise);
616     thiz->max_filter_algorithms[n_filters] = MFX_EXTBUFF_VPP_DENOISE;
617     n_filters++;
618   }
619
620   /* Rotation */
621   if (thiz->flags & GST_MSDK_FLAG_ROTATION) {
622     mfxExtVPPRotation *mfx_rotation = &thiz->mfx_rotation;
623     mfx_rotation->Header.BufferId = MFX_EXTBUFF_VPP_ROTATION;
624     mfx_rotation->Header.BufferSz = sizeof (mfxExtVPPRotation);
625     mfx_rotation->Angle = thiz->rotation;
626     gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_rotation);
627     thiz->max_filter_algorithms[n_filters] = MFX_EXTBUFF_VPP_ROTATION;
628     n_filters++;
629   }
630
631   /* Deinterlace */
632   if (thiz->flags & GST_MSDK_FLAG_DEINTERLACE) {
633     mfxExtVPPDeinterlacing *mfx_deinterlace = &thiz->mfx_deinterlace;
634     mfx_deinterlace->Header.BufferId = MFX_EXTBUFF_VPP_DEINTERLACING;
635     mfx_deinterlace->Header.BufferSz = sizeof (mfxExtVPPDeinterlacing);
636     mfx_deinterlace->Mode = thiz->deinterlace_method;
637     gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_deinterlace);
638     thiz->max_filter_algorithms[n_filters] = MFX_EXTBUFF_VPP_DEINTERLACING;
639     n_filters++;
640   }
641
642   /* Colorbalance(ProcAmp) */
643   if (thiz->flags & (GST_MSDK_FLAG_HUE | GST_MSDK_FLAG_SATURATION |
644           GST_MSDK_FLAG_BRIGHTNESS | GST_MSDK_FLAG_CONTRAST)) {
645     mfxExtVPPProcAmp *mfx_procamp = &thiz->mfx_procamp;
646     mfx_procamp->Header.BufferId = MFX_EXTBUFF_VPP_PROCAMP;
647     mfx_procamp->Header.BufferSz = sizeof (mfxExtVPPProcAmp);
648     mfx_procamp->Hue = thiz->hue;
649     mfx_procamp->Saturation = thiz->saturation;
650     mfx_procamp->Brightness = thiz->brightness;
651     mfx_procamp->Contrast = thiz->contrast;
652     gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_procamp);
653     thiz->max_filter_algorithms[n_filters] = MFX_EXTBUFF_VPP_PROCAMP;
654     n_filters++;
655   }
656
657   /* Detail/Edge enhancement */
658   if (thiz->flags & GST_MSDK_FLAG_DETAIL) {
659     mfxExtVPPDetail *mfx_detail = &thiz->mfx_detail;
660     mfx_detail->Header.BufferId = MFX_EXTBUFF_VPP_DETAIL;
661     mfx_detail->Header.BufferSz = sizeof (mfxExtVPPDetail);
662     mfx_detail->DetailFactor = thiz->detail;
663     gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_detail);
664     thiz->max_filter_algorithms[n_filters] = MFX_EXTBUFF_VPP_DETAIL;
665     n_filters++;
666   }
667
668   /* mfxExtVPPDoUse */
669   if (n_filters) {
670     mfxExtVPPDoUse *mfx_vpp_douse = &thiz->mfx_vpp_douse;
671     mfx_vpp_douse->Header.BufferId = MFX_EXTBUFF_VPP_DOUSE;
672     mfx_vpp_douse->Header.BufferSz = sizeof (mfxExtVPPDoUse);
673     mfx_vpp_douse->NumAlg = n_filters;
674     mfx_vpp_douse->AlgList = thiz->max_filter_algorithms;
675     gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_vpp_douse);
676   }
677
678   /* Mirroring */
679   if (thiz->flags & GST_MSDK_FLAG_MIRRORING) {
680     mfxExtVPPMirroring *mfx_mirroring = &thiz->mfx_mirroring;
681     mfx_mirroring->Header.BufferId = MFX_EXTBUFF_VPP_MIRRORING;
682     mfx_mirroring->Header.BufferSz = sizeof (mfxExtVPPMirroring);
683     mfx_mirroring->Type = thiz->mirroring;
684     gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_mirroring);
685     thiz->max_filter_algorithms[n_filters] = MFX_EXTBUFF_VPP_MIRRORING;
686     n_filters++;
687   }
688 }
689
690 static void
691 gst_msdkvpp_set_passthrough (GstMsdkVPP * thiz)
692 {
693   gboolean passthrough = TRUE;
694
695   /* no passthrough if any of the filter algorithm is enabled */
696   if (thiz->flags)
697     passthrough = FALSE;
698
699   /* no passthrough if there is change in out width,height or format */
700   if (GST_VIDEO_INFO_WIDTH (&thiz->sinkpad_info) !=
701       GST_VIDEO_INFO_WIDTH (&thiz->srcpad_info)
702       || GST_VIDEO_INFO_HEIGHT (&thiz->sinkpad_info) !=
703       GST_VIDEO_INFO_HEIGHT (&thiz->srcpad_info)
704       || GST_VIDEO_INFO_FORMAT (&thiz->sinkpad_info) !=
705       GST_VIDEO_INFO_FORMAT (&thiz->srcpad_info))
706     passthrough = FALSE;
707
708   GST_OBJECT_UNLOCK (thiz);
709   gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (thiz), passthrough);
710   GST_OBJECT_LOCK (thiz);
711 }
712
713 static gboolean
714 gst_msdkvpp_initialize (GstMsdkVPP * thiz)
715 {
716   mfxSession session;
717   mfxStatus status;
718   mfxFrameAllocRequest request[2];
719
720   if (!thiz->context) {
721     GST_WARNING_OBJECT (thiz, "No MSDK Context");
722     return FALSE;
723   }
724
725   GST_OBJECT_LOCK (thiz);
726   session = gst_msdk_context_get_session (thiz->context);
727
728   if (thiz->use_video_memory) {
729     gst_msdk_set_frame_allocator (thiz->context);
730     thiz->param.IOPattern =
731         MFX_IOPATTERN_IN_VIDEO_MEMORY | MFX_IOPATTERN_OUT_VIDEO_MEMORY;
732   } else {
733     thiz->param.IOPattern =
734         MFX_IOPATTERN_IN_SYSTEM_MEMORY | MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
735   }
736
737   /* update input video attributes */
738   gst_msdk_set_mfx_frame_info_from_video_info (&thiz->param.vpp.In,
739       &thiz->sinkpad_info);
740
741   /* update output video attributes, only CSC and Scaling are supported for now */
742   gst_msdk_set_mfx_frame_info_from_video_info (&thiz->param.vpp.Out,
743       &thiz->srcpad_info);
744   thiz->param.vpp.Out.FrameRateExtN =
745       GST_VIDEO_INFO_FPS_N (&thiz->sinkpad_info);
746   thiz->param.vpp.Out.FrameRateExtD =
747       GST_VIDEO_INFO_FPS_D (&thiz->sinkpad_info);
748
749   /* set vpp out picstruct as progressive if deinterlacing enabled */
750   if (thiz->flags & GST_MSDK_FLAG_DEINTERLACE)
751     thiz->param.vpp.Out.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
752
753   /* validate parameters and allow the Media SDK to make adjustments */
754   status = MFXVideoVPP_Query (session, &thiz->param, &thiz->param);
755   if (status < MFX_ERR_NONE) {
756     GST_ERROR_OBJECT (thiz, "Video VPP Query failed (%s)",
757         msdk_status_to_string (status));
758     goto no_vpp;
759   } else if (status > MFX_ERR_NONE) {
760     GST_WARNING_OBJECT (thiz, "Video VPP Query returned: %s",
761         msdk_status_to_string (status));
762   }
763
764   /* Enable the required filters */
765   ensure_filters (thiz);
766
767   /* set passthrough according to filter operation change */
768   gst_msdkvpp_set_passthrough (thiz);
769
770   /* Add exteneded buffers */
771   if (thiz->num_extra_params) {
772     thiz->param.NumExtParam = thiz->num_extra_params;
773     thiz->param.ExtParam = thiz->extra_params;
774   }
775
776   status = MFXVideoVPP_QueryIOSurf (session, &thiz->param, request);
777   if (status < MFX_ERR_NONE) {
778     GST_ERROR_OBJECT (thiz, "VPP Query IO surfaces failed (%s)",
779         msdk_status_to_string (status));
780     goto no_vpp;
781   } else if (status > MFX_ERR_NONE) {
782     GST_WARNING_OBJECT (thiz, "VPP Query IO surfaces returned: %s",
783         msdk_status_to_string (status));
784   }
785
786   if (thiz->use_video_memory) {
787     /* Input surface pool pre-allocation */
788     gst_msdk_frame_alloc (thiz->context, &(request[0]), &thiz->in_alloc_resp);
789     /* Output surface pool pre-allocation */
790     gst_msdk_frame_alloc (thiz->context, &(request[1]), &thiz->out_alloc_resp);
791   }
792
793   thiz->in_num_surfaces = request[0].NumFrameSuggested;
794   thiz->out_num_surfaces = request[1].NumFrameSuggested;
795
796
797   status = MFXVideoVPP_Init (session, &thiz->param);
798   if (status < MFX_ERR_NONE) {
799     GST_ERROR_OBJECT (thiz, "Init failed (%s)", msdk_status_to_string (status));
800     goto no_vpp;
801   } else if (status > MFX_ERR_NONE) {
802     GST_WARNING_OBJECT (thiz, "Init returned: %s",
803         msdk_status_to_string (status));
804   }
805
806   GST_OBJECT_UNLOCK (thiz);
807   return TRUE;
808
809 no_vpp:
810   GST_OBJECT_UNLOCK (thiz);
811   if (thiz->context)
812     gst_object_replace ((GstObject **) & thiz->context, NULL);
813   return FALSE;
814 }
815
816 static gboolean
817 gst_msdkvpp_set_caps (GstBaseTransform * trans, GstCaps * caps,
818     GstCaps * out_caps)
819 {
820   GstMsdkVPP *thiz = GST_MSDKVPP (trans);
821   GstVideoInfo in_info, out_info;
822   gboolean sinkpad_info_changed = FALSE;
823   gboolean srcpad_info_changed = FALSE;
824   gboolean deinterlace;
825
826   gst_video_info_from_caps (&in_info, caps);
827   gst_video_info_from_caps (&out_info, out_caps);
828
829   if (!gst_video_info_is_equal (&in_info, &thiz->sinkpad_info))
830     sinkpad_info_changed = TRUE;
831   if (!gst_video_info_is_equal (&out_info, &thiz->srcpad_info))
832     srcpad_info_changed = TRUE;
833
834   thiz->sinkpad_info = in_info;
835   thiz->srcpad_info = out_info;
836 #ifndef _WIN32
837   thiz->use_video_memory = TRUE;
838 #else
839   thiz->use_video_memory = FALSE;
840 #endif
841
842   if (!sinkpad_info_changed && !srcpad_info_changed)
843     return TRUE;
844
845   /* check for deinterlace requirement */
846   deinterlace = gst_msdkvpp_is_deinterlace_enabled (thiz, &in_info);
847   if (deinterlace)
848     thiz->flags |= GST_MSDK_FLAG_DEINTERLACE;
849   thiz->field_duration = GST_VIDEO_INFO_FPS_N (&in_info) > 0 ?
850       gst_util_uint64_scale (GST_SECOND, GST_VIDEO_INFO_FPS_D (&in_info),
851       (1 + deinterlace) * GST_VIDEO_INFO_FPS_N (&in_info)) : 0;
852
853   if (!gst_msdkvpp_initialize (thiz))
854     return FALSE;
855
856   /* Ensure sinkpad buffer pool */
857   thiz->sinkpad_buffer_pool =
858       gst_msdkvpp_create_buffer_pool (thiz, GST_PAD_SINK, caps,
859       thiz->in_num_surfaces);
860   if (!thiz->sinkpad_buffer_pool) {
861     GST_ERROR_OBJECT (thiz, "Failed to ensure the sinkpad buffer pool");
862     return FALSE;
863   }
864   /* Ensure a srcpad buffer pool */
865   thiz->srcpad_buffer_pool =
866       gst_msdkvpp_create_buffer_pool (thiz, GST_PAD_SRC, out_caps,
867       thiz->out_num_surfaces);
868   if (!thiz->srcpad_buffer_pool) {
869     GST_ERROR_OBJECT (thiz, "Failed to ensure the srcpad buffer pool");
870     return FALSE;
871   }
872
873   return TRUE;
874 }
875
876 static GstCaps *
877 gst_msdkvpp_fixate_caps (GstBaseTransform * trans,
878     GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
879 {
880   GstMsdkVPP *thiz = GST_MSDKVPP (trans);
881   GstCaps *result = NULL;
882
883   if (direction == GST_PAD_SRC)
884     result = gst_caps_fixate (result);
885   else {
886     result = gst_msdkvpp_fixate_srccaps (thiz, caps, othercaps);
887   }
888
889   GST_DEBUG_OBJECT (trans, "fixated to %" GST_PTR_FORMAT, result);
890   gst_caps_unref (othercaps);
891   return result;
892 }
893
894 /* Generic code for now, requires changes in future when we
895  * add hardware query for supported formats, Framerate control etc */
896 static GstCaps *
897 gst_msdkvpp_transform_caps (GstBaseTransform * trans,
898     GstPadDirection direction, GstCaps * caps, GstCaps * filter)
899 {
900   GstCaps *out_caps;
901
902   GST_DEBUG_OBJECT (trans,
903       "Transforming caps %" GST_PTR_FORMAT " in direction %s", caps,
904       (direction == GST_PAD_SINK) ? "sink" : "src");
905
906   if (direction == GST_PAD_SRC)
907     out_caps = gst_static_pad_template_get_caps (&gst_msdkvpp_sink_factory);
908   else
909     out_caps = gst_static_pad_template_get_caps (&gst_msdkvpp_src_factory);
910
911   if (out_caps && filter) {
912     GstCaps *intersection;
913
914     intersection = gst_caps_intersect_full (out_caps, filter,
915         GST_CAPS_INTERSECT_FIRST);
916     gst_caps_unref (out_caps);
917     out_caps = intersection;
918   }
919
920   GST_DEBUG_OBJECT (trans, "returning caps: %" GST_PTR_FORMAT, out_caps);
921   return out_caps;
922 }
923
924 static gboolean
925 gst_msdkvpp_start (GstBaseTransform * trans)
926 {
927   if (!ensure_context (trans))
928     return FALSE;
929   return TRUE;
930 }
931
932 static gboolean
933 gst_msdkvpp_stop (GstBaseTransform * trans)
934 {
935   gst_msdkvpp_close (GST_MSDKVPP (trans));
936   return TRUE;
937 }
938
939 static void
940 gst_msdkvpp_set_property (GObject * object, guint prop_id,
941     const GValue * value, GParamSpec * pspec)
942 {
943   GstMsdkVPP *thiz = GST_MSDKVPP (object);
944
945   switch (prop_id) {
946     case PROP_HARDWARE:
947       thiz->hardware = g_value_get_boolean (value);
948       break;
949     case PROP_ASYNC_DEPTH:
950       thiz->async_depth = g_value_get_uint (value);
951       break;
952     case PROP_DENOISE:
953       thiz->denoise_factor = g_value_get_uint (value);
954       thiz->flags |= GST_MSDK_FLAG_DENOISE;
955       break;
956     case PROP_ROTATION:
957       thiz->rotation = g_value_get_enum (value);
958       thiz->flags |= GST_MSDK_FLAG_ROTATION;
959       break;
960     case PROP_DEINTERLACE_MODE:
961       thiz->deinterlace_mode = g_value_get_enum (value);
962       break;
963     case PROP_DEINTERLACE_METHOD:
964       thiz->deinterlace_method = g_value_get_enum (value);
965       break;
966     case PROP_HUE:
967       thiz->hue = g_value_get_float (value);
968       thiz->flags |= GST_MSDK_FLAG_HUE;
969       break;
970     case PROP_SATURATION:
971       thiz->saturation = g_value_get_float (value);
972       thiz->flags |= GST_MSDK_FLAG_SATURATION;
973       break;
974     case PROP_BRIGHTNESS:
975       thiz->brightness = g_value_get_float (value);
976       thiz->flags |= GST_MSDK_FLAG_BRIGHTNESS;
977       break;
978     case PROP_CONTRAST:
979       thiz->contrast = g_value_get_float (value);
980       thiz->flags |= GST_MSDK_FLAG_CONTRAST;
981       break;
982     case PROP_DETAIL:
983       thiz->detail = g_value_get_uint (value);
984       thiz->flags |= GST_MSDK_FLAG_DETAIL;
985       break;
986     case PROP_MIRRORING:
987       thiz->mirroring = g_value_get_enum (value);
988       thiz->flags |= GST_MSDK_FLAG_MIRRORING;
989       break;
990     default:
991       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
992       break;
993   }
994 }
995
996 static void
997 gst_msdkvpp_get_property (GObject * object, guint prop_id,
998     GValue * value, GParamSpec * pspec)
999 {
1000   GstMsdkVPP *thiz = GST_MSDKVPP (object);
1001
1002   switch (prop_id) {
1003     case PROP_HARDWARE:
1004       g_value_set_boolean (value, thiz->hardware);
1005       break;
1006     case PROP_ASYNC_DEPTH:
1007       g_value_set_uint (value, thiz->async_depth);
1008       break;
1009     case PROP_DENOISE:
1010       g_value_set_uint (value, thiz->denoise_factor);
1011       break;
1012     case PROP_ROTATION:
1013       g_value_set_enum (value, thiz->rotation);
1014       break;
1015     case PROP_DEINTERLACE_MODE:
1016       g_value_set_enum (value, thiz->deinterlace_mode);
1017       break;
1018     case PROP_DEINTERLACE_METHOD:
1019       g_value_set_enum (value, thiz->deinterlace_method);
1020       break;
1021     case PROP_HUE:
1022       g_value_set_float (value, thiz->hue);
1023       break;
1024     case PROP_SATURATION:
1025       g_value_set_float (value, thiz->saturation);
1026       break;
1027     case PROP_BRIGHTNESS:
1028       g_value_set_float (value, thiz->brightness);
1029       break;
1030     case PROP_CONTRAST:
1031       g_value_set_float (value, thiz->contrast);
1032       break;
1033     case PROP_DETAIL:
1034       g_value_set_uint (value, thiz->detail);
1035       break;
1036     case PROP_MIRRORING:
1037       g_value_set_enum (value, thiz->mirroring);
1038       break;
1039     default:
1040       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1041       break;
1042   }
1043 }
1044
1045 static void
1046 gst_msdkvpp_finalize (GObject * object)
1047 {
1048   G_OBJECT_CLASS (parent_class)->finalize (object);
1049 }
1050
1051 static void
1052 gst_msdkvpp_set_context (GstElement * element, GstContext * context)
1053 {
1054   GstMsdkContext *msdk_context = NULL;
1055   GstMsdkVPP *thiz = GST_MSDKVPP (element);
1056
1057   if (gst_msdk_context_get_context (context, &msdk_context)) {
1058     gst_object_replace ((GstObject **) & thiz->context,
1059         (GstObject *) msdk_context);
1060     gst_object_unref (msdk_context);
1061   }
1062
1063   GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
1064 }
1065
1066 static void
1067 gst_msdkvpp_class_init (GstMsdkVPPClass * klass)
1068 {
1069   GObjectClass *gobject_class;
1070   GstElementClass *element_class;
1071   GstBaseTransformClass *trans_class;
1072   GParamSpec *obj_properties[PROP_N] = { NULL, };
1073
1074   gobject_class = G_OBJECT_CLASS (klass);
1075   element_class = GST_ELEMENT_CLASS (klass);
1076   trans_class = GST_BASE_TRANSFORM_CLASS (klass);
1077
1078   gobject_class->set_property = gst_msdkvpp_set_property;
1079   gobject_class->get_property = gst_msdkvpp_get_property;
1080   gobject_class->finalize = gst_msdkvpp_finalize;
1081
1082   element_class->set_context = gst_msdkvpp_set_context;
1083
1084   gst_element_class_add_static_pad_template (element_class,
1085       &gst_msdkvpp_src_factory);
1086   gst_element_class_add_static_pad_template (element_class,
1087       &gst_msdkvpp_sink_factory);
1088
1089   gst_element_class_set_static_metadata (element_class,
1090       "MSDK Video Postprocessor",
1091       "Filter/Converter/Video;Filter/Converter/Video/Scaler;"
1092       "Filter/Effect/Video;Filter/Effect/Video/Deinterlace",
1093       "A MediaSDK Video Postprocessing Filter",
1094       "Sreerenj Balachandrn <sreerenj.balachandran@intel.com>");
1095
1096   trans_class->start = GST_DEBUG_FUNCPTR (gst_msdkvpp_start);
1097   trans_class->stop = GST_DEBUG_FUNCPTR (gst_msdkvpp_stop);
1098   trans_class->transform_caps = GST_DEBUG_FUNCPTR (gst_msdkvpp_transform_caps);
1099   trans_class->fixate_caps = GST_DEBUG_FUNCPTR (gst_msdkvpp_fixate_caps);
1100   trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_msdkvpp_set_caps);
1101   trans_class->transform = GST_DEBUG_FUNCPTR (gst_msdkvpp_transform);
1102   trans_class->propose_allocation =
1103       GST_DEBUG_FUNCPTR (gst_msdkvpp_propose_allocation);
1104   trans_class->decide_allocation =
1105       GST_DEBUG_FUNCPTR (gst_msdkvpp_decide_allocation);
1106   trans_class->prepare_output_buffer =
1107       GST_DEBUG_FUNCPTR (gst_msdkvpp_prepare_output_buffer);
1108
1109   obj_properties[PROP_HARDWARE] =
1110       g_param_spec_boolean ("hardware", "Hardware", "Enable hardware VPP",
1111       PROP_HARDWARE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1112
1113   obj_properties[PROP_ASYNC_DEPTH] =
1114       g_param_spec_uint ("async-depth", "Async Depth",
1115       "Depth of asynchronous pipeline",
1116       1, 1, PROP_ASYNC_DEPTH_DEFAULT,
1117       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1118
1119   obj_properties[PROP_DENOISE] =
1120       g_param_spec_uint ("denoise", "Denoising factor",
1121       "Denoising Factor",
1122       0, 100, PROP_DENOISE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1123
1124   obj_properties[PROP_ROTATION] =
1125       g_param_spec_enum ("rotation", "Rotation",
1126       "Rotation Angle", gst_msdkvpp_rotation_get_type (),
1127       PROP_ROTATION_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1128
1129   obj_properties[PROP_DEINTERLACE_MODE] =
1130       g_param_spec_enum ("deinterlace-mode", "Deinterlace Mode",
1131       "Deinterlace mode to use", gst_msdkvpp_deinterlace_mode_get_type (),
1132       PROP_DEINTERLACE_MODE_DEFAULT,
1133       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1134
1135   obj_properties[PROP_DEINTERLACE_METHOD] =
1136       g_param_spec_enum ("deinterlace-method", "Deinterlace Method",
1137       "Deinterlace method to use", gst_msdkvpp_deinterlace_method_get_type (),
1138       PROP_DEINTERLACE_METHOD_DEFAULT,
1139       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1140
1141   obj_properties[PROP_HUE] =
1142       g_param_spec_float ("hue", "Hue",
1143       "The hue of the video",
1144       -180, 180, PROP_HUE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1145
1146   obj_properties[PROP_SATURATION] =
1147       g_param_spec_float ("saturation", "Saturation",
1148       "The Saturation of the video",
1149       0, 10, PROP_SATURATION_DEFAULT,
1150       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1151
1152   obj_properties[PROP_BRIGHTNESS] =
1153       g_param_spec_float ("brightness", "Brightness",
1154       "The Brightness of the video",
1155       -100, 100, PROP_BRIGHTNESS_DEFAULT,
1156       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1157
1158   obj_properties[PROP_CONTRAST] =
1159       g_param_spec_float ("contrast", "Contrast",
1160       "The Contrast of the video",
1161       0, 10, PROP_CONTRAST_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1162
1163   obj_properties[PROP_DETAIL] =
1164       g_param_spec_uint ("detail", "Detail",
1165       "The factor of detail/edge enhancement filter algorithm",
1166       0, 100, PROP_DETAIL_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1167
1168   obj_properties[PROP_MIRRORING] =
1169       g_param_spec_enum ("mirroring", "Mirroring",
1170       "The Mirroring type", gst_msdkvpp_mirroring_get_type (),
1171       PROP_MIRRORING_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1172
1173   g_object_class_install_properties (gobject_class, PROP_N, obj_properties);
1174 }
1175
1176 static void
1177 gst_msdkvpp_init (GstMsdkVPP * thiz)
1178 {
1179   thiz->hardware = PROP_HARDWARE_DEFAULT;
1180   thiz->async_depth = PROP_ASYNC_DEPTH_DEFAULT;
1181   thiz->denoise_factor = PROP_DENOISE_DEFAULT;
1182   thiz->rotation = PROP_ROTATION_DEFAULT;
1183   thiz->deinterlace_mode = PROP_DEINTERLACE_MODE_DEFAULT;
1184   thiz->deinterlace_method = PROP_DEINTERLACE_METHOD_DEFAULT;
1185   thiz->field_duration = GST_CLOCK_TIME_NONE;
1186   thiz->hue = PROP_HUE_DEFAULT;
1187   thiz->saturation = PROP_SATURATION_DEFAULT;
1188   thiz->brightness = PROP_BRIGHTNESS_DEFAULT;
1189   thiz->contrast = PROP_CONTRAST_DEFAULT;
1190   thiz->detail = PROP_DETAIL_DEFAULT;
1191   thiz->mirroring = PROP_MIRRORING_DEFAULT;
1192   gst_video_info_init (&thiz->sinkpad_info);
1193   gst_video_info_init (&thiz->srcpad_info);
1194 }