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