1 /* GStreamer Intel MSDK plugin
2 * Copyright (c) 2018, Intel Corporation
5 * Author: Sreerenj Balachaandran <sreerenj.balachandran@intel.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
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.
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.
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.
40 #include "gstmsdkvpp.h"
41 #include "gstmsdkbufferpool.h"
42 #include "gstmsdkvideomemory.h"
43 #include "gstmsdksystemmemory.h"
44 #include "gstmsdkcontextutil.h"
45 #include "gstmsdkvpputil.h"
47 GST_DEBUG_CATEGORY_EXTERN (gst_msdkvpp_debug);
48 #define GST_CAT_DEFAULT gst_msdkvpp_debug
50 static GstStaticPadTemplate gst_msdkvpp_sink_factory =
51 GST_STATIC_PAD_TEMPLATE ("sink",
54 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ NV12, I420, YUY2, UYVY, BGRA }")
55 ", " "interlace-mode = (string){ progressive, interleaved, mixed }"));
57 static GstStaticPadTemplate gst_msdkvpp_src_factory =
58 GST_STATIC_PAD_TEMPLATE ("src",
61 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ NV12, BGRA }") ", "
62 "interlace-mode = (string){ progressive, interleaved, mixed }"));
71 PROP_DEINTERLACE_MODE,
72 PROP_DEINTERLACE_METHOD,
82 #define PROP_HARDWARE_DEFAULT TRUE
83 #define PROP_ASYNC_DEPTH_DEFAULT 1
84 #define PROP_DENOISE_DEFAULT 0
85 #define PROP_ROTATION_DEFAULT MFX_ANGLE_0
86 #define PROP_DEINTERLACE_MODE_DEFAULT GST_MSDKVPP_DEINTERLACE_MODE_AUTO
87 #define PROP_DEINTERLACE_METHOD_DEFAULT MFX_DEINTERLACING_BOB
88 #define PROP_HUE_DEFAULT 0
89 #define PROP_SATURATION_DEFAULT 1
90 #define PROP_BRIGHTNESS_DEFAULT 0
91 #define PROP_CONTRAST_DEFAULT 1
92 #define PROP_DETAIL_DEFAULT 0
93 #define PROP_MIRRORING_DEFAULT MFX_MIRRORING_DISABLED
95 #define gst_msdkvpp_parent_class parent_class
96 G_DEFINE_TYPE (GstMsdkVPP, gst_msdkvpp, GST_TYPE_BASE_TRANSFORM);
100 mfxFrameSurface1 *surface;
105 free_msdk_surface (MsdkSurface * surface)
108 gst_buffer_unref (surface->buf);
109 g_slice_free (MsdkSurface, surface);
113 gst_msdkvpp_add_extra_param (GstMsdkVPP * thiz, mfxExtBuffer * param)
115 if (thiz->num_extra_params < MAX_EXTRA_PARAMS) {
116 thiz->extra_params[thiz->num_extra_params] = param;
117 thiz->num_extra_params++;
122 ensure_context (GstBaseTransform * trans)
124 GstMsdkVPP *thiz = GST_MSDKVPP (trans);
126 if (gst_msdk_context_prepare (GST_ELEMENT_CAST (thiz), &thiz->context)) {
127 GST_INFO_OBJECT (thiz, "Found context from neighbour %" GST_PTR_FORMAT,
130 if (gst_msdk_context_get_job_type (thiz->context) & GST_MSDK_JOB_VPP) {
131 GstMsdkContext *parent_context;
133 parent_context = thiz->context;
134 thiz->context = gst_msdk_context_new_with_parent (parent_context);
135 gst_object_unref (parent_context);
137 GST_INFO_OBJECT (thiz,
138 "Creating new context %" GST_PTR_FORMAT " with joined session",
141 gst_msdk_context_add_job_type (thiz->context, GST_MSDK_JOB_VPP);
144 if (!gst_msdk_context_ensure_context (GST_ELEMENT_CAST (thiz),
145 thiz->hardware, GST_MSDK_JOB_VPP))
147 GST_INFO_OBJECT (thiz, "Creating new context %" GST_PTR_FORMAT,
151 gst_msdk_context_add_shared_async_depth (thiz->context, thiz->async_depth);
157 create_output_buffer (GstMsdkVPP * thiz)
161 GstBufferPool *pool = thiz->srcpad_buffer_pool;
163 g_return_val_if_fail (pool != NULL, NULL);
165 if (!gst_buffer_pool_is_active (pool) &&
166 !gst_buffer_pool_set_active (pool, TRUE))
167 goto error_activate_pool;
170 ret = gst_buffer_pool_acquire_buffer (pool, &outbuf, NULL);
171 if (ret != GST_FLOW_OK || !outbuf)
172 goto error_create_buffer;
179 GST_ERROR_OBJECT (thiz, "failed to activate output video buffer pool");
184 GST_ERROR_OBJECT (thiz, "failed to create output video buffer");
190 gst_msdkvpp_prepare_output_buffer (GstBaseTransform * trans,
191 GstBuffer * inbuf, GstBuffer ** outbuf_ptr)
193 GstMsdkVPP *thiz = GST_MSDKVPP (trans);
195 if (gst_base_transform_is_passthrough (trans)) {
200 *outbuf_ptr = create_output_buffer (thiz);
201 return *outbuf_ptr ? GST_FLOW_OK : GST_FLOW_ERROR;
204 static GstBufferPool *
205 gst_msdkvpp_create_buffer_pool (GstMsdkVPP * thiz, GstPadDirection direction,
206 GstCaps * caps, guint min_num_buffers)
208 GstBufferPool *pool = NULL;
209 GstStructure *config;
210 GstAllocator *allocator = NULL;
212 GstVideoInfo *pool_info = NULL;
213 GstVideoAlignment align;
214 GstAllocationParams params = { 0, 31, 0, 0, };
215 mfxFrameAllocResponse *alloc_resp = NULL;
217 if (direction == GST_PAD_SINK) {
218 alloc_resp = &thiz->in_alloc_resp;
219 pool_info = &thiz->sinkpad_buffer_pool_info;
220 } else if (direction == GST_PAD_SRC) {
221 alloc_resp = &thiz->out_alloc_resp;
222 pool_info = &thiz->srcpad_buffer_pool_info;
225 pool = gst_msdk_buffer_pool_new (thiz->context, alloc_resp);
229 if (!gst_video_info_from_caps (&info, caps))
230 goto error_no_video_info;
232 gst_msdk_set_video_alignment (&info, &align);
233 gst_video_info_align (&info, &align);
235 if (thiz->use_video_memory)
236 allocator = gst_msdk_video_allocator_new (thiz->context, &info, alloc_resp);
238 allocator = gst_msdk_system_allocator_new (&info);
241 goto error_no_allocator;
243 config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
244 gst_buffer_pool_config_set_params (config, caps, info.size, min_num_buffers,
247 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
248 gst_buffer_pool_config_add_option (config,
249 GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
250 if (thiz->use_video_memory)
251 gst_buffer_pool_config_add_option (config,
252 GST_BUFFER_POOL_OPTION_MSDK_USE_VIDEO_MEMORY);
254 gst_buffer_pool_config_set_video_alignment (config, &align);
255 gst_buffer_pool_config_set_allocator (config, allocator, ¶ms);
256 gst_object_unref (allocator);
258 if (!gst_buffer_pool_set_config (pool, config))
259 goto error_pool_config;
261 /* Updating pool_info with algined info of allocator */
268 GST_INFO_OBJECT (thiz, "Failed to create bufferpool");
273 GST_INFO_OBJECT (thiz, "Failed to get Video info from caps");
278 GST_INFO_OBJECT (thiz, "Failed to create allocator");
280 gst_object_unref (pool);
285 GST_INFO_OBJECT (thiz, "Failed to set config");
287 gst_object_unref (pool);
289 gst_object_unref (allocator);
295 gst_msdkvpp_decide_allocation (GstBaseTransform * trans, GstQuery * query)
297 GstMsdkVPP *thiz = GST_MSDKVPP (trans);
299 GstBufferPool *pool = NULL;
300 GstStructure *config = NULL;
302 guint size = 0, min_buffers = 0, max_buffers = 0;
303 GstAllocator *allocator = NULL;
304 GstAllocationParams params;
305 gboolean update_pool = FALSE;
307 gst_query_parse_allocation (query, &caps, NULL);
309 GST_ERROR_OBJECT (thiz, "Failed to parse the decide_allocation caps");
312 if (!gst_video_info_from_caps (&info, caps)) {
313 GST_ERROR_OBJECT (thiz, "Failed to get video info");
317 if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL))
318 thiz->add_video_meta = TRUE;
320 thiz->add_video_meta = FALSE;
322 if (gst_query_get_n_allocation_pools (query) > 0) {
323 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min_buffers,
326 size = MAX (size, GST_VIDEO_INFO_SIZE (&info));
328 if (pool && !GST_IS_MSDK_BUFFER_POOL (pool)) {
329 GST_INFO_OBJECT (thiz, "ignoring non-msdk pool: %" GST_PTR_FORMAT, pool);
330 g_clear_object (&pool);
335 gst_object_unref (thiz->srcpad_buffer_pool);
337 gst_msdkvpp_create_buffer_pool (thiz, GST_PAD_SRC, caps, min_buffers);
338 thiz->srcpad_buffer_pool = pool;
340 /* get the configured pool properties inorder to set in query */
341 config = gst_buffer_pool_get_config (pool);
342 gst_buffer_pool_config_get_params (config, &caps, &size, &min_buffers,
344 if (gst_buffer_pool_config_get_allocator (config, &allocator, ¶ms))
345 gst_query_add_allocation_param (query, allocator, ¶ms);
346 gst_structure_free (config);
350 gst_query_set_nth_allocation_pool (query, 0, pool, size, min_buffers,
353 gst_query_add_allocation_pool (query, pool, size, min_buffers, max_buffers);
355 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
357 /* Fixme if downstream doesn't have videometa support, msdkvpp should
358 * copy the output buffers */
364 gst_msdkvpp_propose_allocation (GstBaseTransform * trans,
365 GstQuery * decide_query, GstQuery * query)
367 GstMsdkVPP *thiz = GST_MSDKVPP (trans);
369 GstBufferPool *pool = NULL;
370 GstAllocator *allocator = NULL;
372 GstStructure *config;
375 GstAllocationParams params;
377 gst_query_parse_allocation (query, &caps, &need_pool);
379 GST_ERROR_OBJECT (thiz, "Failed to parse the allocation caps");
383 if (!gst_video_info_from_caps (&info, caps)) {
384 GST_ERROR_OBJECT (thiz, "Failed to get video info");
388 size = MAX (info.size, GST_VIDEO_INFO_SIZE (&thiz->sinkpad_buffer_pool_info));
390 /* We already created a pool while setting the caps
391 * just to make sure the pipeline works even if there is
392 * no allocation query from upstream (theoratical ??).Provide the
393 * same pool in query if required/possible */
394 if (!gst_video_info_is_equal (&thiz->sinkpad_buffer_pool_info, &info)) {
395 gst_object_unref (thiz->sinkpad_buffer_pool);
396 thiz->sinkpad_buffer_pool =
397 gst_msdkvpp_create_buffer_pool (thiz, GST_PAD_SINK, caps,
398 thiz->in_num_surfaces);
401 pool = thiz->sinkpad_buffer_pool;
403 config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
405 gst_buffer_pool_config_get_params (config, NULL, &size, NULL, NULL);
407 if (gst_buffer_pool_config_get_allocator (config, &allocator, ¶ms))
408 gst_query_add_allocation_param (query, allocator, ¶ms);
409 gst_structure_free (config);
411 /* if upstream does't have a pool requirement, set only
412 * size, min_buffers and max_buffers in query */
416 gst_query_add_allocation_pool (query, pool, size, thiz->in_num_surfaces, 0);
417 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
419 return GST_BASE_TRANSFORM_CLASS (parent_class)->propose_allocation (trans,
420 decide_query, query);
424 get_surface_from_pool (GstMsdkVPP * thiz, GstBufferPool * pool,
425 GstBufferPoolAcquireParams * params)
427 GstBuffer *new_buffer;
428 mfxFrameSurface1 *new_surface;
429 MsdkSurface *msdk_surface;
431 if (!gst_buffer_pool_is_active (pool) &&
432 !gst_buffer_pool_set_active (pool, TRUE)) {
433 GST_ERROR_OBJECT (pool, "failed to activate buffer pool");
437 if (gst_buffer_pool_acquire_buffer (pool, &new_buffer, params) != GST_FLOW_OK) {
438 GST_ERROR_OBJECT (pool, "failed to acquire a buffer from pool");
442 if (gst_msdk_is_msdk_buffer (new_buffer))
443 new_surface = gst_msdk_get_surface_from_buffer (new_buffer);
445 GST_ERROR_OBJECT (pool, "the acquired memory is not MSDK memory");
449 msdk_surface = g_slice_new0 (MsdkSurface);
450 msdk_surface->surface = new_surface;
451 msdk_surface->buf = new_buffer;
457 get_msdk_surface_from_input_buffer (GstMsdkVPP * thiz, GstBuffer * inbuf)
459 GstVideoFrame src_frame, out_frame;
460 MsdkSurface *msdk_surface;
462 if (gst_msdk_is_msdk_buffer (inbuf)) {
463 msdk_surface = g_slice_new0 (MsdkSurface);
464 msdk_surface->surface = gst_msdk_get_surface_from_buffer (inbuf);
465 msdk_surface->buf = gst_buffer_ref (inbuf);
469 /* If upstream hasn't accpeted the proposed msdk bufferpool,
470 * just copy frame to msdk buffer and take a surface from it.
473 get_surface_from_pool (thiz, thiz->sinkpad_buffer_pool, NULL)))
476 if (!gst_video_frame_map (&src_frame, &thiz->sinkpad_info, inbuf,
478 GST_ERROR_OBJECT (thiz, "failed to map the frame for source");
482 if (!gst_video_frame_map (&out_frame, &thiz->sinkpad_buffer_pool_info,
483 msdk_surface->buf, GST_MAP_WRITE)) {
484 GST_ERROR_OBJECT (thiz, "failed to map the frame for destination");
485 gst_video_frame_unmap (&src_frame);
489 if (!gst_video_frame_copy (&out_frame, &src_frame)) {
490 GST_ERROR_OBJECT (thiz, "failed to copy frame");
491 gst_video_frame_unmap (&out_frame);
492 gst_video_frame_unmap (&src_frame);
496 gst_video_frame_unmap (&out_frame);
497 gst_video_frame_unmap (&src_frame);
506 gst_msdkvpp_transform (GstBaseTransform * trans, GstBuffer * inbuf,
509 GstMsdkVPP *thiz = GST_MSDKVPP (trans);
511 mfxSyncPoint sync_point = NULL;
513 MsdkSurface *in_surface = NULL;
514 MsdkSurface *out_surface = NULL;
516 in_surface = get_msdk_surface_from_input_buffer (thiz, inbuf);
518 return GST_FLOW_ERROR;
520 if (gst_msdk_is_msdk_buffer (outbuf)) {
521 out_surface = g_slice_new0 (MsdkSurface);
522 out_surface->surface = gst_msdk_get_surface_from_buffer (outbuf);
524 GST_ERROR ("Failed to get msdk outsurface!");
525 return GST_FLOW_ERROR;
528 session = gst_msdk_context_get_session (thiz->context);
531 MFXVideoVPP_RunFrameVPPAsync (session, in_surface->surface,
532 out_surface->surface, NULL, &sync_point);
533 if (status != MFX_WRN_DEVICE_BUSY)
535 /* If device is busy, wait 1ms and retry, as per MSDK's recomendation */
539 if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA
540 && status != MFX_ERR_MORE_SURFACE)
543 /* No output generated */
544 if (status == MFX_ERR_MORE_DATA)
545 goto error_more_data;
547 MFXVideoCORE_SyncOperation (session, sync_point, 10000);
549 /* More than one output buffers are generated */
550 if (status == MFX_ERR_MORE_SURFACE)
551 status = MFX_ERR_NONE;
553 gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
555 free_msdk_surface (in_surface);
559 GST_ERROR_OBJECT (thiz, "MSDK Failed to do VPP");
560 free_msdk_surface (in_surface);
561 free_msdk_surface (out_surface);
562 return GST_FLOW_ERROR;
565 GST_WARNING_OBJECT (thiz,
566 "MSDK Requries additional input for processing, "
567 "Retruning FLOW_DROPPED since no output buffer was generated");
568 free_msdk_surface (in_surface);
569 return GST_BASE_TRANSFORM_FLOW_DROPPED;
573 gst_msdkvpp_close (GstMsdkVPP * thiz)
580 GST_DEBUG_OBJECT (thiz, "Closing VPP 0x%p", thiz->context);
581 status = MFXVideoVPP_Close (gst_msdk_context_get_session (thiz->context));
582 if (status != MFX_ERR_NONE && status != MFX_ERR_NOT_INITIALIZED) {
583 GST_WARNING_OBJECT (thiz, "Encoder close failed (%s)",
584 msdk_status_to_string (status));
588 gst_object_replace ((GstObject **) & thiz->context, NULL);
590 memset (&thiz->param, 0, sizeof (thiz->param));
592 if (thiz->sinkpad_buffer_pool)
593 gst_object_unref (thiz->sinkpad_buffer_pool);
594 thiz->sinkpad_buffer_pool = NULL;
595 if (thiz->srcpad_buffer_pool)
596 gst_object_unref (thiz->srcpad_buffer_pool);
597 thiz->srcpad_buffer_pool = NULL;
599 thiz->field_duration = GST_CLOCK_TIME_NONE;
600 gst_video_info_init (&thiz->sinkpad_info);
601 gst_video_info_init (&thiz->srcpad_info);
605 ensure_filters (GstMsdkVPP * thiz)
610 if (thiz->flags & GST_MSDK_FLAG_DENOISE) {
611 mfxExtVPPDenoise *mfx_denoise = &thiz->mfx_denoise;
612 mfx_denoise->Header.BufferId = MFX_EXTBUFF_VPP_DENOISE;
613 mfx_denoise->Header.BufferSz = sizeof (mfxExtVPPDenoise);
614 mfx_denoise->DenoiseFactor = thiz->denoise_factor;
615 gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_denoise);
616 thiz->max_filter_algorithms[n_filters] = MFX_EXTBUFF_VPP_DENOISE;
621 if (thiz->flags & GST_MSDK_FLAG_ROTATION) {
622 mfxExtVPPRotation *mfx_rotation = &thiz->mfx_rotation;
623 mfx_rotation->Header.BufferId = MFX_EXTBUFF_VPP_ROTATION;
624 mfx_rotation->Header.BufferSz = sizeof (mfxExtVPPRotation);
625 mfx_rotation->Angle = thiz->rotation;
626 gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_rotation);
627 thiz->max_filter_algorithms[n_filters] = MFX_EXTBUFF_VPP_ROTATION;
632 if (thiz->flags & GST_MSDK_FLAG_DEINTERLACE) {
633 mfxExtVPPDeinterlacing *mfx_deinterlace = &thiz->mfx_deinterlace;
634 mfx_deinterlace->Header.BufferId = MFX_EXTBUFF_VPP_DEINTERLACING;
635 mfx_deinterlace->Header.BufferSz = sizeof (mfxExtVPPDeinterlacing);
636 mfx_deinterlace->Mode = thiz->deinterlace_method;
637 gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_deinterlace);
638 thiz->max_filter_algorithms[n_filters] = MFX_EXTBUFF_VPP_DEINTERLACING;
642 /* Colorbalance(ProcAmp) */
643 if (thiz->flags & (GST_MSDK_FLAG_HUE | GST_MSDK_FLAG_SATURATION |
644 GST_MSDK_FLAG_BRIGHTNESS | GST_MSDK_FLAG_CONTRAST)) {
645 mfxExtVPPProcAmp *mfx_procamp = &thiz->mfx_procamp;
646 mfx_procamp->Header.BufferId = MFX_EXTBUFF_VPP_PROCAMP;
647 mfx_procamp->Header.BufferSz = sizeof (mfxExtVPPProcAmp);
648 mfx_procamp->Hue = thiz->hue;
649 mfx_procamp->Saturation = thiz->saturation;
650 mfx_procamp->Brightness = thiz->brightness;
651 mfx_procamp->Contrast = thiz->contrast;
652 gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_procamp);
653 thiz->max_filter_algorithms[n_filters] = MFX_EXTBUFF_VPP_PROCAMP;
657 /* Detail/Edge enhancement */
658 if (thiz->flags & GST_MSDK_FLAG_DETAIL) {
659 mfxExtVPPDetail *mfx_detail = &thiz->mfx_detail;
660 mfx_detail->Header.BufferId = MFX_EXTBUFF_VPP_DETAIL;
661 mfx_detail->Header.BufferSz = sizeof (mfxExtVPPDetail);
662 mfx_detail->DetailFactor = thiz->detail;
663 gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_detail);
664 thiz->max_filter_algorithms[n_filters] = MFX_EXTBUFF_VPP_DETAIL;
670 mfxExtVPPDoUse *mfx_vpp_douse = &thiz->mfx_vpp_douse;
671 mfx_vpp_douse->Header.BufferId = MFX_EXTBUFF_VPP_DOUSE;
672 mfx_vpp_douse->Header.BufferSz = sizeof (mfxExtVPPDoUse);
673 mfx_vpp_douse->NumAlg = n_filters;
674 mfx_vpp_douse->AlgList = thiz->max_filter_algorithms;
675 gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_vpp_douse);
679 if (thiz->flags & GST_MSDK_FLAG_MIRRORING) {
680 mfxExtVPPMirroring *mfx_mirroring = &thiz->mfx_mirroring;
681 mfx_mirroring->Header.BufferId = MFX_EXTBUFF_VPP_MIRRORING;
682 mfx_mirroring->Header.BufferSz = sizeof (mfxExtVPPMirroring);
683 mfx_mirroring->Type = thiz->mirroring;
684 gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_mirroring);
685 thiz->max_filter_algorithms[n_filters] = MFX_EXTBUFF_VPP_MIRRORING;
691 gst_msdkvpp_set_passthrough (GstMsdkVPP * thiz)
693 gboolean passthrough = TRUE;
695 /* no passthrough if any of the filter algorithm is enabled */
699 /* no passthrough if there is change in out width,height or format */
700 if (GST_VIDEO_INFO_WIDTH (&thiz->sinkpad_info) !=
701 GST_VIDEO_INFO_WIDTH (&thiz->srcpad_info)
702 || GST_VIDEO_INFO_HEIGHT (&thiz->sinkpad_info) !=
703 GST_VIDEO_INFO_HEIGHT (&thiz->srcpad_info)
704 || GST_VIDEO_INFO_FORMAT (&thiz->sinkpad_info) !=
705 GST_VIDEO_INFO_FORMAT (&thiz->srcpad_info))
708 GST_OBJECT_UNLOCK (thiz);
709 gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (thiz), passthrough);
710 GST_OBJECT_LOCK (thiz);
714 gst_msdkvpp_initialize (GstMsdkVPP * thiz)
718 mfxFrameAllocRequest request[2];
720 if (!thiz->context) {
721 GST_WARNING_OBJECT (thiz, "No MSDK Context");
725 GST_OBJECT_LOCK (thiz);
726 session = gst_msdk_context_get_session (thiz->context);
728 if (thiz->use_video_memory) {
729 gst_msdk_set_frame_allocator (thiz->context);
730 thiz->param.IOPattern =
731 MFX_IOPATTERN_IN_VIDEO_MEMORY | MFX_IOPATTERN_OUT_VIDEO_MEMORY;
733 thiz->param.IOPattern =
734 MFX_IOPATTERN_IN_SYSTEM_MEMORY | MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
737 /* update input video attributes */
738 gst_msdk_set_mfx_frame_info_from_video_info (&thiz->param.vpp.In,
739 &thiz->sinkpad_info);
741 /* update output video attributes, only CSC and Scaling are supported for now */
742 gst_msdk_set_mfx_frame_info_from_video_info (&thiz->param.vpp.Out,
744 thiz->param.vpp.Out.FrameRateExtN =
745 GST_VIDEO_INFO_FPS_N (&thiz->sinkpad_info);
746 thiz->param.vpp.Out.FrameRateExtD =
747 GST_VIDEO_INFO_FPS_D (&thiz->sinkpad_info);
749 /* set vpp out picstruct as progressive if deinterlacing enabled */
750 if (thiz->flags & GST_MSDK_FLAG_DEINTERLACE)
751 thiz->param.vpp.Out.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
753 /* validate parameters and allow the Media SDK to make adjustments */
754 status = MFXVideoVPP_Query (session, &thiz->param, &thiz->param);
755 if (status < MFX_ERR_NONE) {
756 GST_ERROR_OBJECT (thiz, "Video VPP Query failed (%s)",
757 msdk_status_to_string (status));
759 } else if (status > MFX_ERR_NONE) {
760 GST_WARNING_OBJECT (thiz, "Video VPP Query returned: %s",
761 msdk_status_to_string (status));
764 /* Enable the required filters */
765 ensure_filters (thiz);
767 /* set passthrough according to filter operation change */
768 gst_msdkvpp_set_passthrough (thiz);
770 /* Add exteneded buffers */
771 if (thiz->num_extra_params) {
772 thiz->param.NumExtParam = thiz->num_extra_params;
773 thiz->param.ExtParam = thiz->extra_params;
776 status = MFXVideoVPP_QueryIOSurf (session, &thiz->param, request);
777 if (status < MFX_ERR_NONE) {
778 GST_ERROR_OBJECT (thiz, "VPP Query IO surfaces failed (%s)",
779 msdk_status_to_string (status));
781 } else if (status > MFX_ERR_NONE) {
782 GST_WARNING_OBJECT (thiz, "VPP Query IO surfaces returned: %s",
783 msdk_status_to_string (status));
786 if (thiz->use_video_memory) {
787 /* Input surface pool pre-allocation */
788 gst_msdk_frame_alloc (thiz->context, &(request[0]), &thiz->in_alloc_resp);
789 /* Output surface pool pre-allocation */
790 gst_msdk_frame_alloc (thiz->context, &(request[1]), &thiz->out_alloc_resp);
793 thiz->in_num_surfaces = request[0].NumFrameSuggested;
794 thiz->out_num_surfaces = request[1].NumFrameSuggested;
797 status = MFXVideoVPP_Init (session, &thiz->param);
798 if (status < MFX_ERR_NONE) {
799 GST_ERROR_OBJECT (thiz, "Init failed (%s)", msdk_status_to_string (status));
801 } else if (status > MFX_ERR_NONE) {
802 GST_WARNING_OBJECT (thiz, "Init returned: %s",
803 msdk_status_to_string (status));
806 GST_OBJECT_UNLOCK (thiz);
810 GST_OBJECT_UNLOCK (thiz);
812 gst_object_replace ((GstObject **) & thiz->context, NULL);
817 gst_msdkvpp_set_caps (GstBaseTransform * trans, GstCaps * caps,
820 GstMsdkVPP *thiz = GST_MSDKVPP (trans);
821 GstVideoInfo in_info, out_info;
822 gboolean sinkpad_info_changed = FALSE;
823 gboolean srcpad_info_changed = FALSE;
824 gboolean deinterlace;
826 gst_video_info_from_caps (&in_info, caps);
827 gst_video_info_from_caps (&out_info, out_caps);
829 if (!gst_video_info_is_equal (&in_info, &thiz->sinkpad_info))
830 sinkpad_info_changed = TRUE;
831 if (!gst_video_info_is_equal (&out_info, &thiz->srcpad_info))
832 srcpad_info_changed = TRUE;
834 thiz->sinkpad_info = in_info;
835 thiz->srcpad_info = out_info;
837 thiz->use_video_memory = TRUE;
839 thiz->use_video_memory = FALSE;
842 if (!sinkpad_info_changed && !srcpad_info_changed)
845 /* check for deinterlace requirement */
846 deinterlace = gst_msdkvpp_is_deinterlace_enabled (thiz, &in_info);
848 thiz->flags |= GST_MSDK_FLAG_DEINTERLACE;
849 thiz->field_duration = GST_VIDEO_INFO_FPS_N (&in_info) > 0 ?
850 gst_util_uint64_scale (GST_SECOND, GST_VIDEO_INFO_FPS_D (&in_info),
851 (1 + deinterlace) * GST_VIDEO_INFO_FPS_N (&in_info)) : 0;
853 if (!gst_msdkvpp_initialize (thiz))
856 /* Ensure sinkpad buffer pool */
857 thiz->sinkpad_buffer_pool =
858 gst_msdkvpp_create_buffer_pool (thiz, GST_PAD_SINK, caps,
859 thiz->in_num_surfaces);
860 if (!thiz->sinkpad_buffer_pool) {
861 GST_ERROR_OBJECT (thiz, "Failed to ensure the sinkpad buffer pool");
864 /* Ensure a srcpad buffer pool */
865 thiz->srcpad_buffer_pool =
866 gst_msdkvpp_create_buffer_pool (thiz, GST_PAD_SRC, out_caps,
867 thiz->out_num_surfaces);
868 if (!thiz->srcpad_buffer_pool) {
869 GST_ERROR_OBJECT (thiz, "Failed to ensure the srcpad buffer pool");
877 gst_msdkvpp_fixate_caps (GstBaseTransform * trans,
878 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
880 GstMsdkVPP *thiz = GST_MSDKVPP (trans);
881 GstCaps *result = NULL;
883 if (direction == GST_PAD_SRC)
884 result = gst_caps_fixate (result);
886 result = gst_msdkvpp_fixate_srccaps (thiz, caps, othercaps);
889 GST_DEBUG_OBJECT (trans, "fixated to %" GST_PTR_FORMAT, result);
890 gst_caps_unref (othercaps);
894 /* Generic code for now, requires changes in future when we
895 * add hardware query for supported formats, Framerate control etc */
897 gst_msdkvpp_transform_caps (GstBaseTransform * trans,
898 GstPadDirection direction, GstCaps * caps, GstCaps * filter)
902 GST_DEBUG_OBJECT (trans,
903 "Transforming caps %" GST_PTR_FORMAT " in direction %s", caps,
904 (direction == GST_PAD_SINK) ? "sink" : "src");
906 if (direction == GST_PAD_SRC)
907 out_caps = gst_static_pad_template_get_caps (&gst_msdkvpp_sink_factory);
909 out_caps = gst_static_pad_template_get_caps (&gst_msdkvpp_src_factory);
911 if (out_caps && filter) {
912 GstCaps *intersection;
914 intersection = gst_caps_intersect_full (out_caps, filter,
915 GST_CAPS_INTERSECT_FIRST);
916 gst_caps_unref (out_caps);
917 out_caps = intersection;
920 GST_DEBUG_OBJECT (trans, "returning caps: %" GST_PTR_FORMAT, out_caps);
925 gst_msdkvpp_start (GstBaseTransform * trans)
927 if (!ensure_context (trans))
933 gst_msdkvpp_stop (GstBaseTransform * trans)
935 gst_msdkvpp_close (GST_MSDKVPP (trans));
940 gst_msdkvpp_set_property (GObject * object, guint prop_id,
941 const GValue * value, GParamSpec * pspec)
943 GstMsdkVPP *thiz = GST_MSDKVPP (object);
947 thiz->hardware = g_value_get_boolean (value);
949 case PROP_ASYNC_DEPTH:
950 thiz->async_depth = g_value_get_uint (value);
953 thiz->denoise_factor = g_value_get_uint (value);
954 thiz->flags |= GST_MSDK_FLAG_DENOISE;
957 thiz->rotation = g_value_get_enum (value);
958 thiz->flags |= GST_MSDK_FLAG_ROTATION;
960 case PROP_DEINTERLACE_MODE:
961 thiz->deinterlace_mode = g_value_get_enum (value);
963 case PROP_DEINTERLACE_METHOD:
964 thiz->deinterlace_method = g_value_get_enum (value);
967 thiz->hue = g_value_get_float (value);
968 thiz->flags |= GST_MSDK_FLAG_HUE;
970 case PROP_SATURATION:
971 thiz->saturation = g_value_get_float (value);
972 thiz->flags |= GST_MSDK_FLAG_SATURATION;
974 case PROP_BRIGHTNESS:
975 thiz->brightness = g_value_get_float (value);
976 thiz->flags |= GST_MSDK_FLAG_BRIGHTNESS;
979 thiz->contrast = g_value_get_float (value);
980 thiz->flags |= GST_MSDK_FLAG_CONTRAST;
983 thiz->detail = g_value_get_uint (value);
984 thiz->flags |= GST_MSDK_FLAG_DETAIL;
987 thiz->mirroring = g_value_get_enum (value);
988 thiz->flags |= GST_MSDK_FLAG_MIRRORING;
991 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
997 gst_msdkvpp_get_property (GObject * object, guint prop_id,
998 GValue * value, GParamSpec * pspec)
1000 GstMsdkVPP *thiz = GST_MSDKVPP (object);
1004 g_value_set_boolean (value, thiz->hardware);
1006 case PROP_ASYNC_DEPTH:
1007 g_value_set_uint (value, thiz->async_depth);
1010 g_value_set_uint (value, thiz->denoise_factor);
1013 g_value_set_enum (value, thiz->rotation);
1015 case PROP_DEINTERLACE_MODE:
1016 g_value_set_enum (value, thiz->deinterlace_mode);
1018 case PROP_DEINTERLACE_METHOD:
1019 g_value_set_enum (value, thiz->deinterlace_method);
1022 g_value_set_float (value, thiz->hue);
1024 case PROP_SATURATION:
1025 g_value_set_float (value, thiz->saturation);
1027 case PROP_BRIGHTNESS:
1028 g_value_set_float (value, thiz->brightness);
1031 g_value_set_float (value, thiz->contrast);
1034 g_value_set_uint (value, thiz->detail);
1036 case PROP_MIRRORING:
1037 g_value_set_enum (value, thiz->mirroring);
1040 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1046 gst_msdkvpp_finalize (GObject * object)
1048 G_OBJECT_CLASS (parent_class)->finalize (object);
1052 gst_msdkvpp_set_context (GstElement * element, GstContext * context)
1054 GstMsdkContext *msdk_context = NULL;
1055 GstMsdkVPP *thiz = GST_MSDKVPP (element);
1057 if (gst_msdk_context_get_context (context, &msdk_context)) {
1058 gst_object_replace ((GstObject **) & thiz->context,
1059 (GstObject *) msdk_context);
1060 gst_object_unref (msdk_context);
1063 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
1067 gst_msdkvpp_class_init (GstMsdkVPPClass * klass)
1069 GObjectClass *gobject_class;
1070 GstElementClass *element_class;
1071 GstBaseTransformClass *trans_class;
1072 GParamSpec *obj_properties[PROP_N] = { NULL, };
1074 gobject_class = G_OBJECT_CLASS (klass);
1075 element_class = GST_ELEMENT_CLASS (klass);
1076 trans_class = GST_BASE_TRANSFORM_CLASS (klass);
1078 gobject_class->set_property = gst_msdkvpp_set_property;
1079 gobject_class->get_property = gst_msdkvpp_get_property;
1080 gobject_class->finalize = gst_msdkvpp_finalize;
1082 element_class->set_context = gst_msdkvpp_set_context;
1084 gst_element_class_add_static_pad_template (element_class,
1085 &gst_msdkvpp_src_factory);
1086 gst_element_class_add_static_pad_template (element_class,
1087 &gst_msdkvpp_sink_factory);
1089 gst_element_class_set_static_metadata (element_class,
1090 "MSDK Video Postprocessor",
1091 "Filter/Converter/Video;Filter/Converter/Video/Scaler;"
1092 "Filter/Effect/Video;Filter/Effect/Video/Deinterlace",
1093 "A MediaSDK Video Postprocessing Filter",
1094 "Sreerenj Balachandrn <sreerenj.balachandran@intel.com>");
1096 trans_class->start = GST_DEBUG_FUNCPTR (gst_msdkvpp_start);
1097 trans_class->stop = GST_DEBUG_FUNCPTR (gst_msdkvpp_stop);
1098 trans_class->transform_caps = GST_DEBUG_FUNCPTR (gst_msdkvpp_transform_caps);
1099 trans_class->fixate_caps = GST_DEBUG_FUNCPTR (gst_msdkvpp_fixate_caps);
1100 trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_msdkvpp_set_caps);
1101 trans_class->transform = GST_DEBUG_FUNCPTR (gst_msdkvpp_transform);
1102 trans_class->propose_allocation =
1103 GST_DEBUG_FUNCPTR (gst_msdkvpp_propose_allocation);
1104 trans_class->decide_allocation =
1105 GST_DEBUG_FUNCPTR (gst_msdkvpp_decide_allocation);
1106 trans_class->prepare_output_buffer =
1107 GST_DEBUG_FUNCPTR (gst_msdkvpp_prepare_output_buffer);
1109 obj_properties[PROP_HARDWARE] =
1110 g_param_spec_boolean ("hardware", "Hardware", "Enable hardware VPP",
1111 PROP_HARDWARE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1113 obj_properties[PROP_ASYNC_DEPTH] =
1114 g_param_spec_uint ("async-depth", "Async Depth",
1115 "Depth of asynchronous pipeline",
1116 1, 1, PROP_ASYNC_DEPTH_DEFAULT,
1117 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1119 obj_properties[PROP_DENOISE] =
1120 g_param_spec_uint ("denoise", "Denoising factor",
1122 0, 100, PROP_DENOISE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1124 obj_properties[PROP_ROTATION] =
1125 g_param_spec_enum ("rotation", "Rotation",
1126 "Rotation Angle", gst_msdkvpp_rotation_get_type (),
1127 PROP_ROTATION_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1129 obj_properties[PROP_DEINTERLACE_MODE] =
1130 g_param_spec_enum ("deinterlace-mode", "Deinterlace Mode",
1131 "Deinterlace mode to use", gst_msdkvpp_deinterlace_mode_get_type (),
1132 PROP_DEINTERLACE_MODE_DEFAULT,
1133 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1135 obj_properties[PROP_DEINTERLACE_METHOD] =
1136 g_param_spec_enum ("deinterlace-method", "Deinterlace Method",
1137 "Deinterlace method to use", gst_msdkvpp_deinterlace_method_get_type (),
1138 PROP_DEINTERLACE_METHOD_DEFAULT,
1139 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1141 obj_properties[PROP_HUE] =
1142 g_param_spec_float ("hue", "Hue",
1143 "The hue of the video",
1144 -180, 180, PROP_HUE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1146 obj_properties[PROP_SATURATION] =
1147 g_param_spec_float ("saturation", "Saturation",
1148 "The Saturation of the video",
1149 0, 10, PROP_SATURATION_DEFAULT,
1150 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1152 obj_properties[PROP_BRIGHTNESS] =
1153 g_param_spec_float ("brightness", "Brightness",
1154 "The Brightness of the video",
1155 -100, 100, PROP_BRIGHTNESS_DEFAULT,
1156 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1158 obj_properties[PROP_CONTRAST] =
1159 g_param_spec_float ("contrast", "Contrast",
1160 "The Contrast of the video",
1161 0, 10, PROP_CONTRAST_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1163 obj_properties[PROP_DETAIL] =
1164 g_param_spec_uint ("detail", "Detail",
1165 "The factor of detail/edge enhancement filter algorithm",
1166 0, 100, PROP_DETAIL_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1168 obj_properties[PROP_MIRRORING] =
1169 g_param_spec_enum ("mirroring", "Mirroring",
1170 "The Mirroring type", gst_msdkvpp_mirroring_get_type (),
1171 PROP_MIRRORING_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1173 g_object_class_install_properties (gobject_class, PROP_N, obj_properties);
1177 gst_msdkvpp_init (GstMsdkVPP * thiz)
1179 thiz->hardware = PROP_HARDWARE_DEFAULT;
1180 thiz->async_depth = PROP_ASYNC_DEPTH_DEFAULT;
1181 thiz->denoise_factor = PROP_DENOISE_DEFAULT;
1182 thiz->rotation = PROP_ROTATION_DEFAULT;
1183 thiz->deinterlace_mode = PROP_DEINTERLACE_MODE_DEFAULT;
1184 thiz->deinterlace_method = PROP_DEINTERLACE_METHOD_DEFAULT;
1185 thiz->field_duration = GST_CLOCK_TIME_NONE;
1186 thiz->hue = PROP_HUE_DEFAULT;
1187 thiz->saturation = PROP_SATURATION_DEFAULT;
1188 thiz->brightness = PROP_BRIGHTNESS_DEFAULT;
1189 thiz->contrast = PROP_CONTRAST_DEFAULT;
1190 thiz->detail = PROP_DETAIL_DEFAULT;
1191 thiz->mirroring = PROP_MIRRORING_DEFAULT;
1192 gst_video_info_init (&thiz->sinkpad_info);
1193 gst_video_info_init (&thiz->srcpad_info);