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