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