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