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