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