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