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