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