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"
46 #include "msdk-enums.h"
48 GST_DEBUG_CATEGORY_EXTERN (gst_msdkvpp_debug);
49 #define GST_CAT_DEFAULT gst_msdkvpp_debug
51 static GstStaticPadTemplate gst_msdkvpp_sink_factory =
52 GST_STATIC_PAD_TEMPLATE ("sink",
55 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ NV12, I420, YUY2, UYVY, BGRA }")
56 ", " "interlace-mode = (string){ progressive, interleaved, mixed }"));
58 static GstStaticPadTemplate gst_msdkvpp_src_factory =
59 GST_STATIC_PAD_TEMPLATE ("src",
62 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ NV12, BGRA }") ", "
63 "interlace-mode = (string){ progressive, interleaved, mixed }"));
72 PROP_DEINTERLACE_MODE,
73 PROP_DEINTERLACE_METHOD,
77 #define PROP_HARDWARE_DEFAULT TRUE
78 #define PROP_ASYNC_DEPTH_DEFAULT 1
79 #define PROP_DENOISE_DEFAULT 0
80 #define PROP_ROTATION_DEFAULT MFX_ANGLE_0
81 #define PROP_DEINTERLACE_MODE_DEFAULT GST_MSDKVPP_DEINTERLACE_MODE_AUTO
82 #define PROP_DEINTERLACE_METHOD_DEFAULT MFX_DEINTERLACING_BOB
84 #define gst_msdkvpp_parent_class parent_class
85 G_DEFINE_TYPE (GstMsdkVPP, gst_msdkvpp, GST_TYPE_BASE_TRANSFORM);
89 mfxFrameSurface1 *surface;
94 free_msdk_surface (MsdkSurface * surface)
97 gst_buffer_unref (surface->buf);
98 g_slice_free (MsdkSurface, surface);
102 gst_msdkvpp_add_extra_param (GstMsdkVPP * thiz, mfxExtBuffer * param)
104 if (thiz->num_extra_params < MAX_EXTRA_PARAMS) {
105 thiz->extra_params[thiz->num_extra_params] = param;
106 thiz->num_extra_params++;
111 ensure_context (GstBaseTransform * trans)
113 GstMsdkVPP *thiz = GST_MSDKVPP (trans);
115 if (gst_msdk_context_prepare (GST_ELEMENT_CAST (thiz), &thiz->context)) {
116 GST_INFO_OBJECT (thiz, "Found context from neighbour %" GST_PTR_FORMAT,
119 if (gst_msdk_context_get_job_type (thiz->context) & GST_MSDK_JOB_VPP) {
120 GstMsdkContext *parent_context;
122 parent_context = thiz->context;
123 thiz->context = gst_msdk_context_new_with_parent (parent_context);
124 gst_object_unref (parent_context);
126 GST_INFO_OBJECT (thiz,
127 "Creating new context %" GST_PTR_FORMAT " with joined session",
130 gst_msdk_context_add_job_type (thiz->context, GST_MSDK_JOB_VPP);
133 if (!gst_msdk_context_ensure_context (GST_ELEMENT_CAST (thiz),
134 thiz->hardware, GST_MSDK_JOB_VPP))
136 GST_INFO_OBJECT (thiz, "Creating new context %" GST_PTR_FORMAT,
140 gst_msdk_context_add_shared_async_depth (thiz->context, thiz->async_depth);
146 create_output_buffer (GstMsdkVPP * thiz)
150 GstBufferPool *pool = thiz->srcpad_buffer_pool;
152 g_return_val_if_fail (pool != NULL, NULL);
154 if (!gst_buffer_pool_is_active (pool) &&
155 !gst_buffer_pool_set_active (pool, TRUE))
156 goto error_activate_pool;
159 ret = gst_buffer_pool_acquire_buffer (pool, &outbuf, NULL);
160 if (ret != GST_FLOW_OK || !outbuf)
161 goto error_create_buffer;
168 GST_ERROR_OBJECT (thiz, "failed to activate output video buffer pool");
173 GST_ERROR_OBJECT (thiz, "failed to create output video buffer");
179 gst_msdkvpp_prepare_output_buffer (GstBaseTransform * trans,
180 GstBuffer * inbuf, GstBuffer ** outbuf_ptr)
182 GstMsdkVPP *thiz = GST_MSDKVPP (trans);
184 if (gst_base_transform_is_passthrough (trans)) {
189 *outbuf_ptr = create_output_buffer (thiz);
190 return *outbuf_ptr ? GST_FLOW_OK : GST_FLOW_ERROR;
193 static GstBufferPool *
194 gst_msdkvpp_create_buffer_pool (GstMsdkVPP * thiz, GstPadDirection direction,
195 GstCaps * caps, guint min_num_buffers)
197 GstBufferPool *pool = NULL;
198 GstStructure *config;
199 GstAllocator *allocator = NULL;
201 GstVideoInfo *pool_info = NULL;
202 GstVideoAlignment align;
203 GstAllocationParams params = { 0, 31, 0, 0, };
204 mfxFrameAllocResponse *alloc_resp = NULL;
206 if (direction == GST_PAD_SINK) {
207 alloc_resp = &thiz->in_alloc_resp;
208 pool_info = &thiz->sinkpad_buffer_pool_info;
209 } else if (direction == GST_PAD_SRC) {
210 alloc_resp = &thiz->out_alloc_resp;
211 pool_info = &thiz->srcpad_buffer_pool_info;
214 pool = gst_msdk_buffer_pool_new (thiz->context, alloc_resp);
218 if (!gst_video_info_from_caps (&info, caps))
219 goto error_no_video_info;
221 gst_msdk_set_video_alignment (&info, &align);
222 gst_video_info_align (&info, &align);
224 if (thiz->use_video_memory)
225 allocator = gst_msdk_video_allocator_new (thiz->context, &info, alloc_resp);
227 allocator = gst_msdk_system_allocator_new (&info);
230 goto error_no_allocator;
232 config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
233 gst_buffer_pool_config_set_params (config, caps, info.size, min_num_buffers,
236 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
237 gst_buffer_pool_config_add_option (config,
238 GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
239 if (thiz->use_video_memory)
240 gst_buffer_pool_config_add_option (config,
241 GST_BUFFER_POOL_OPTION_MSDK_USE_VIDEO_MEMORY);
243 gst_buffer_pool_config_set_video_alignment (config, &align);
244 gst_buffer_pool_config_set_allocator (config, allocator, ¶ms);
245 gst_object_unref (allocator);
247 if (!gst_buffer_pool_set_config (pool, config))
248 goto error_pool_config;
250 /* Updating pool_info with algined info of allocator */
257 GST_INFO_OBJECT (thiz, "Failed to create bufferpool");
262 GST_INFO_OBJECT (thiz, "Failed to get Video info from caps");
267 GST_INFO_OBJECT (thiz, "Failed to create allocator");
269 gst_object_unref (pool);
274 GST_INFO_OBJECT (thiz, "Failed to set config");
276 gst_object_unref (pool);
278 gst_object_unref (allocator);
284 gst_msdkvpp_decide_allocation (GstBaseTransform * trans, GstQuery * query)
286 GstMsdkVPP *thiz = GST_MSDKVPP (trans);
288 GstBufferPool *pool = NULL;
289 GstStructure *config = NULL;
291 guint size = 0, min_buffers = 0, max_buffers = 0;
292 GstAllocator *allocator = NULL;
293 GstAllocationParams params;
294 gboolean update_pool = FALSE;
296 gst_query_parse_allocation (query, &caps, NULL);
298 GST_ERROR_OBJECT (thiz, "Failed to parse the decide_allocation caps");
301 if (!gst_video_info_from_caps (&info, caps)) {
302 GST_ERROR_OBJECT (thiz, "Failed to get video info");
306 if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL))
307 thiz->add_video_meta = TRUE;
309 thiz->add_video_meta = FALSE;
311 if (gst_query_get_n_allocation_pools (query) > 0) {
312 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min_buffers,
315 size = MAX (size, GST_VIDEO_INFO_SIZE (&info));
317 if (pool && !GST_IS_MSDK_BUFFER_POOL (pool)) {
318 GST_INFO_OBJECT (thiz, "ignoring non-msdk pool: %" GST_PTR_FORMAT, pool);
319 g_clear_object (&pool);
324 gst_object_unref (thiz->srcpad_buffer_pool);
326 gst_msdkvpp_create_buffer_pool (thiz, GST_PAD_SRC, caps, min_buffers);
327 thiz->srcpad_buffer_pool = pool;
329 /* get the configured pool properties inorder to set in query */
330 config = gst_buffer_pool_get_config (pool);
331 gst_buffer_pool_config_get_params (config, &caps, &size, &min_buffers,
333 if (gst_buffer_pool_config_get_allocator (config, &allocator, ¶ms))
334 gst_query_add_allocation_param (query, allocator, ¶ms);
335 gst_structure_free (config);
339 gst_query_set_nth_allocation_pool (query, 0, pool, size, min_buffers,
342 gst_query_add_allocation_pool (query, pool, size, min_buffers, max_buffers);
344 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
346 /* Fixme if downstream doesn't have videometa support, msdkvpp should
347 * copy the output buffers */
353 gst_msdkvpp_propose_allocation (GstBaseTransform * trans,
354 GstQuery * decide_query, GstQuery * query)
356 GstMsdkVPP *thiz = GST_MSDKVPP (trans);
358 GstBufferPool *pool = NULL;
359 GstAllocator *allocator = NULL;
361 GstStructure *config;
364 GstAllocationParams params;
366 gst_query_parse_allocation (query, &caps, &need_pool);
368 GST_ERROR_OBJECT (thiz, "Failed to parse the allocation caps");
372 if (!gst_video_info_from_caps (&info, caps)) {
373 GST_ERROR_OBJECT (thiz, "Failed to get video info");
377 size = MAX (info.size, GST_VIDEO_INFO_SIZE (&thiz->sinkpad_buffer_pool_info));
379 /* We already created a pool while setting the caps
380 * just to make sure the pipeline works even if there is
381 * no allocation query from upstream (theoratical ??).Provide the
382 * same pool in query if required/possible */
383 if (!gst_video_info_is_equal (&thiz->sinkpad_buffer_pool_info, &info)) {
384 gst_object_unref (thiz->sinkpad_buffer_pool);
385 thiz->sinkpad_buffer_pool =
386 gst_msdkvpp_create_buffer_pool (thiz, GST_PAD_SINK, caps,
387 thiz->in_num_surfaces);
390 pool = thiz->sinkpad_buffer_pool;
392 config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
394 gst_buffer_pool_config_get_params (config, NULL, &size, NULL, NULL);
396 if (gst_buffer_pool_config_get_allocator (config, &allocator, ¶ms))
397 gst_query_add_allocation_param (query, allocator, ¶ms);
398 gst_structure_free (config);
400 /* if upstream does't have a pool requirement, set only
401 * size, min_buffers and max_buffers in query */
405 gst_query_add_allocation_pool (query, pool, size, thiz->in_num_surfaces, 0);
406 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
408 return GST_BASE_TRANSFORM_CLASS (parent_class)->propose_allocation (trans,
409 decide_query, query);
413 get_surface_from_pool (GstMsdkVPP * thiz, GstBufferPool * pool,
414 GstBufferPoolAcquireParams * params)
416 GstBuffer *new_buffer;
417 mfxFrameSurface1 *new_surface;
418 MsdkSurface *msdk_surface;
420 if (!gst_buffer_pool_is_active (pool) &&
421 !gst_buffer_pool_set_active (pool, TRUE)) {
422 GST_ERROR_OBJECT (pool, "failed to activate buffer pool");
426 if (gst_buffer_pool_acquire_buffer (pool, &new_buffer, params) != GST_FLOW_OK) {
427 GST_ERROR_OBJECT (pool, "failed to acquire a buffer from pool");
431 if (gst_msdk_is_msdk_buffer (new_buffer))
432 new_surface = gst_msdk_get_surface_from_buffer (new_buffer);
434 GST_ERROR_OBJECT (pool, "the acquired memory is not MSDK memory");
438 msdk_surface = g_slice_new0 (MsdkSurface);
439 msdk_surface->surface = new_surface;
440 msdk_surface->buf = new_buffer;
446 get_msdk_surface_from_input_buffer (GstMsdkVPP * thiz, GstBuffer * inbuf)
448 GstVideoFrame src_frame, out_frame;
449 MsdkSurface *msdk_surface;
451 if (gst_msdk_is_msdk_buffer (inbuf)) {
452 msdk_surface = g_slice_new0 (MsdkSurface);
453 msdk_surface->surface = gst_msdk_get_surface_from_buffer (inbuf);
454 msdk_surface->buf = gst_buffer_ref (inbuf);
458 /* If upstream hasn't accpeted the proposed msdk bufferpool,
459 * just copy frame to msdk buffer and take a surface from it.
462 get_surface_from_pool (thiz, thiz->sinkpad_buffer_pool, NULL)))
465 if (!gst_video_frame_map (&src_frame, &thiz->sinkpad_info, inbuf,
467 GST_ERROR_OBJECT (thiz, "failed to map the frame for source");
471 if (!gst_video_frame_map (&out_frame, &thiz->sinkpad_buffer_pool_info,
472 msdk_surface->buf, GST_MAP_WRITE)) {
473 GST_ERROR_OBJECT (thiz, "failed to map the frame for destination");
474 gst_video_frame_unmap (&src_frame);
478 if (!gst_video_frame_copy (&out_frame, &src_frame)) {
479 GST_ERROR_OBJECT (thiz, "failed to copy frame");
480 gst_video_frame_unmap (&out_frame);
481 gst_video_frame_unmap (&src_frame);
485 gst_video_frame_unmap (&out_frame);
486 gst_video_frame_unmap (&src_frame);
495 gst_msdkvpp_transform (GstBaseTransform * trans, GstBuffer * inbuf,
498 GstMsdkVPP *thiz = GST_MSDKVPP (trans);
500 mfxSyncPoint sync_point = NULL;
502 MsdkSurface *in_surface = NULL;
503 MsdkSurface *out_surface = NULL;
505 in_surface = get_msdk_surface_from_input_buffer (thiz, inbuf);
507 return GST_FLOW_ERROR;
509 if (gst_msdk_is_msdk_buffer (outbuf)) {
510 out_surface = g_slice_new0 (MsdkSurface);
511 out_surface->surface = gst_msdk_get_surface_from_buffer (outbuf);
513 GST_ERROR ("Failed to get msdk outsurface!");
514 return GST_FLOW_ERROR;
517 session = gst_msdk_context_get_session (thiz->context);
520 MFXVideoVPP_RunFrameVPPAsync (session, in_surface->surface,
521 out_surface->surface, NULL, &sync_point);
522 if (status != MFX_WRN_DEVICE_BUSY)
524 /* If device is busy, wait 1ms and retry, as per MSDK's recomendation */
528 if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA
529 && status != MFX_ERR_MORE_SURFACE)
532 /* No output generated */
533 if (status == MFX_ERR_MORE_DATA)
534 goto error_more_data;
536 MFXVideoCORE_SyncOperation (session, sync_point, 10000);
538 /* More than one output buffers are generated */
539 if (status == MFX_ERR_MORE_SURFACE)
540 status = MFX_ERR_NONE;
542 gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
544 free_msdk_surface (in_surface);
548 GST_ERROR_OBJECT (thiz, "MSDK Failed to do VPP");
549 free_msdk_surface (in_surface);
550 free_msdk_surface (out_surface);
551 return GST_FLOW_ERROR;
554 GST_WARNING_OBJECT (thiz,
555 "MSDK Requries additional input for processing, "
556 "Retruning FLOW_DROPPED since no output buffer was generated");
557 free_msdk_surface (in_surface);
558 return GST_BASE_TRANSFORM_FLOW_DROPPED;
562 gst_msdkvpp_close (GstMsdkVPP * thiz)
569 GST_DEBUG_OBJECT (thiz, "Closing VPP 0x%p", thiz->context);
570 status = MFXVideoVPP_Close (gst_msdk_context_get_session (thiz->context));
571 if (status != MFX_ERR_NONE && status != MFX_ERR_NOT_INITIALIZED) {
572 GST_WARNING_OBJECT (thiz, "Encoder close failed (%s)",
573 msdk_status_to_string (status));
577 gst_object_replace ((GstObject **) & thiz->context, NULL);
579 memset (&thiz->param, 0, sizeof (thiz->param));
581 if (thiz->sinkpad_buffer_pool)
582 gst_object_unref (thiz->sinkpad_buffer_pool);
583 thiz->sinkpad_buffer_pool = NULL;
584 if (thiz->srcpad_buffer_pool)
585 gst_object_unref (thiz->srcpad_buffer_pool);
586 thiz->srcpad_buffer_pool = NULL;
588 thiz->field_duration = GST_CLOCK_TIME_NONE;
589 gst_video_info_init (&thiz->sinkpad_info);
590 gst_video_info_init (&thiz->srcpad_info);
594 ensure_filters (GstMsdkVPP * thiz)
599 if (thiz->flags & GST_MSDK_FLAG_DENOISE) {
600 mfxExtVPPDenoise *mfx_denoise = &thiz->mfx_denoise;
601 mfx_denoise->Header.BufferId = MFX_EXTBUFF_VPP_DENOISE;
602 mfx_denoise->Header.BufferSz = sizeof (mfxExtVPPDenoise);
603 mfx_denoise->DenoiseFactor = thiz->denoise_factor;
604 gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_denoise);
605 thiz->max_filter_algorithms[n_filters] = MFX_EXTBUFF_VPP_DENOISE;
610 if (thiz->flags & GST_MSDK_FLAG_ROTATION) {
611 mfxExtVPPRotation *mfx_rotation = &thiz->mfx_rotation;
612 mfx_rotation->Header.BufferId = MFX_EXTBUFF_VPP_ROTATION;
613 mfx_rotation->Header.BufferSz = sizeof (mfxExtVPPRotation);
614 mfx_rotation->Angle = thiz->rotation;
615 gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_rotation);
616 thiz->max_filter_algorithms[n_filters] = MFX_EXTBUFF_VPP_ROTATION;
621 if (thiz->flags & GST_MSDK_FLAG_DEINTERLACE) {
622 mfxExtVPPDeinterlacing *mfx_deinterlace = &thiz->mfx_deinterlace;
623 mfx_deinterlace->Header.BufferId = MFX_EXTBUFF_VPP_DEINTERLACING;
624 mfx_deinterlace->Header.BufferSz = sizeof (mfxExtVPPDeinterlacing);
625 mfx_deinterlace->Mode = thiz->deinterlace_method;
626 gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_deinterlace);
627 thiz->max_filter_algorithms[n_filters] = MFX_EXTBUFF_VPP_DEINTERLACING;
633 mfxExtVPPDoUse *mfx_vpp_douse = &thiz->mfx_vpp_douse;
634 mfx_vpp_douse->Header.BufferId = MFX_EXTBUFF_VPP_DOUSE;
635 mfx_vpp_douse->Header.BufferSz = sizeof (mfxExtVPPDoUse);
636 mfx_vpp_douse->NumAlg = n_filters;
637 mfx_vpp_douse->AlgList = thiz->max_filter_algorithms;
638 gst_msdkvpp_add_extra_param (thiz, (mfxExtBuffer *) mfx_vpp_douse);
643 gst_msdkvpp_set_passthrough (GstMsdkVPP * thiz)
645 gboolean passthrough = TRUE;
647 /* no passthrough if any of the filter algorithm is enabled */
651 /* no passthrough if there is change in out width,height or format */
652 if (GST_VIDEO_INFO_WIDTH (&thiz->sinkpad_info) !=
653 GST_VIDEO_INFO_WIDTH (&thiz->srcpad_info)
654 || GST_VIDEO_INFO_HEIGHT (&thiz->sinkpad_info) !=
655 GST_VIDEO_INFO_HEIGHT (&thiz->srcpad_info)
656 || GST_VIDEO_INFO_FORMAT (&thiz->sinkpad_info) !=
657 GST_VIDEO_INFO_FORMAT (&thiz->srcpad_info))
660 GST_OBJECT_UNLOCK (thiz);
661 gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (thiz), passthrough);
662 GST_OBJECT_LOCK (thiz);
666 gst_msdkvpp_initialize (GstMsdkVPP * thiz)
670 mfxFrameAllocRequest request[2];
672 if (!thiz->context) {
673 GST_WARNING_OBJECT (thiz, "No MSDK Context");
677 GST_OBJECT_LOCK (thiz);
678 session = gst_msdk_context_get_session (thiz->context);
680 if (thiz->use_video_memory) {
681 gst_msdk_set_frame_allocator (thiz->context);
682 thiz->param.IOPattern =
683 MFX_IOPATTERN_IN_VIDEO_MEMORY | MFX_IOPATTERN_OUT_VIDEO_MEMORY;
685 thiz->param.IOPattern =
686 MFX_IOPATTERN_IN_SYSTEM_MEMORY | MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
689 /* update input video attributes */
690 gst_msdk_set_mfx_frame_info_from_video_info (&thiz->param.vpp.In,
691 &thiz->sinkpad_info);
693 /* update output video attributes, only CSC and Scaling are supported for now */
694 gst_msdk_set_mfx_frame_info_from_video_info (&thiz->param.vpp.Out,
696 thiz->param.vpp.Out.FrameRateExtN =
697 GST_VIDEO_INFO_FPS_N (&thiz->sinkpad_info);
698 thiz->param.vpp.Out.FrameRateExtD =
699 GST_VIDEO_INFO_FPS_D (&thiz->sinkpad_info);
701 /* set vpp out picstruct as progressive if deinterlacing enabled */
702 if (thiz->flags & GST_MSDK_FLAG_DEINTERLACE)
703 thiz->param.vpp.Out.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
705 /* validate parameters and allow the Media SDK to make adjustments */
706 status = MFXVideoVPP_Query (session, &thiz->param, &thiz->param);
707 if (status < MFX_ERR_NONE) {
708 GST_ERROR_OBJECT (thiz, "Video VPP Query failed (%s)",
709 msdk_status_to_string (status));
711 } else if (status > MFX_ERR_NONE) {
712 GST_WARNING_OBJECT (thiz, "Video VPP Query returned: %s",
713 msdk_status_to_string (status));
716 /* Enable the required filters */
717 ensure_filters (thiz);
719 /* set passthrough according to filter operation change */
720 gst_msdkvpp_set_passthrough (thiz);
722 /* Add exteneded buffers */
723 if (thiz->num_extra_params) {
724 thiz->param.NumExtParam = thiz->num_extra_params;
725 thiz->param.ExtParam = thiz->extra_params;
728 status = MFXVideoVPP_QueryIOSurf (session, &thiz->param, request);
729 if (status < MFX_ERR_NONE) {
730 GST_ERROR_OBJECT (thiz, "VPP Query IO surfaces failed (%s)",
731 msdk_status_to_string (status));
733 } else if (status > MFX_ERR_NONE) {
734 GST_WARNING_OBJECT (thiz, "VPP Query IO surfaces returned: %s",
735 msdk_status_to_string (status));
738 if (thiz->use_video_memory) {
739 /* Input surface pool pre-allocation */
740 gst_msdk_frame_alloc (thiz->context, &(request[0]), &thiz->in_alloc_resp);
741 /* Output surface pool pre-allocation */
742 gst_msdk_frame_alloc (thiz->context, &(request[1]), &thiz->out_alloc_resp);
745 thiz->in_num_surfaces = request[0].NumFrameSuggested;
746 thiz->out_num_surfaces = request[1].NumFrameSuggested;
749 status = MFXVideoVPP_Init (session, &thiz->param);
750 if (status < MFX_ERR_NONE) {
751 GST_ERROR_OBJECT (thiz, "Init failed (%s)", msdk_status_to_string (status));
753 } else if (status > MFX_ERR_NONE) {
754 GST_WARNING_OBJECT (thiz, "Init returned: %s",
755 msdk_status_to_string (status));
758 GST_OBJECT_UNLOCK (thiz);
762 GST_OBJECT_UNLOCK (thiz);
764 gst_object_replace ((GstObject **) & thiz->context, NULL);
769 gst_msdkvpp_set_caps (GstBaseTransform * trans, GstCaps * caps,
772 GstMsdkVPP *thiz = GST_MSDKVPP (trans);
773 GstVideoInfo in_info, out_info;
774 gboolean sinkpad_info_changed = FALSE;
775 gboolean srcpad_info_changed = FALSE;
776 gboolean deinterlace;
778 gst_video_info_from_caps (&in_info, caps);
779 gst_video_info_from_caps (&out_info, out_caps);
781 if (!gst_video_info_is_equal (&in_info, &thiz->sinkpad_info))
782 sinkpad_info_changed = TRUE;
783 if (!gst_video_info_is_equal (&out_info, &thiz->srcpad_info))
784 srcpad_info_changed = TRUE;
786 thiz->sinkpad_info = in_info;
787 thiz->srcpad_info = out_info;
789 thiz->use_video_memory = TRUE;
791 thiz->use_video_memory = FALSE;
794 if (!sinkpad_info_changed && !srcpad_info_changed)
797 /* check for deinterlace requirement */
798 deinterlace = gst_msdkvpp_is_deinterlace_enabled (thiz, &in_info);
800 thiz->flags |= GST_MSDK_FLAG_DEINTERLACE;
801 thiz->field_duration = GST_VIDEO_INFO_FPS_N (&in_info) > 0 ?
802 gst_util_uint64_scale (GST_SECOND, GST_VIDEO_INFO_FPS_D (&in_info),
803 (1 + deinterlace) * GST_VIDEO_INFO_FPS_N (&in_info)) : 0;
805 if (!gst_msdkvpp_initialize (thiz))
808 /* Ensure sinkpad buffer pool */
809 thiz->sinkpad_buffer_pool =
810 gst_msdkvpp_create_buffer_pool (thiz, GST_PAD_SINK, caps,
811 thiz->in_num_surfaces);
812 if (!thiz->sinkpad_buffer_pool) {
813 GST_ERROR_OBJECT (thiz, "Failed to ensure the sinkpad buffer pool");
816 /* Ensure a srcpad buffer pool */
817 thiz->srcpad_buffer_pool =
818 gst_msdkvpp_create_buffer_pool (thiz, GST_PAD_SRC, out_caps,
819 thiz->out_num_surfaces);
820 if (!thiz->srcpad_buffer_pool) {
821 GST_ERROR_OBJECT (thiz, "Failed to ensure the srcpad buffer pool");
829 gst_msdkvpp_fixate_caps (GstBaseTransform * trans,
830 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
832 GstMsdkVPP *thiz = GST_MSDKVPP (trans);
833 GstCaps *result = NULL;
835 if (direction == GST_PAD_SRC)
836 result = gst_caps_fixate (result);
838 result = gst_msdkvpp_fixate_srccaps (thiz, caps, othercaps);
841 GST_DEBUG_OBJECT (trans, "fixated to %" GST_PTR_FORMAT, result);
842 gst_caps_unref (othercaps);
846 /* Generic code for now, requires changes in future when we
847 * add hardware query for supported formats, Framerate control etc */
849 gst_msdkvpp_transform_caps (GstBaseTransform * trans,
850 GstPadDirection direction, GstCaps * caps, GstCaps * filter)
854 GST_DEBUG_OBJECT (trans,
855 "Transforming caps %" GST_PTR_FORMAT " in direction %s", caps,
856 (direction == GST_PAD_SINK) ? "sink" : "src");
858 if (direction == GST_PAD_SRC)
859 out_caps = gst_static_pad_template_get_caps (&gst_msdkvpp_sink_factory);
861 out_caps = gst_static_pad_template_get_caps (&gst_msdkvpp_src_factory);
863 if (out_caps && filter) {
864 GstCaps *intersection;
866 intersection = gst_caps_intersect_full (out_caps, filter,
867 GST_CAPS_INTERSECT_FIRST);
868 gst_caps_unref (out_caps);
869 out_caps = intersection;
872 GST_DEBUG_OBJECT (trans, "returning caps: %" GST_PTR_FORMAT, out_caps);
877 gst_msdkvpp_start (GstBaseTransform * trans)
879 if (!ensure_context (trans))
885 gst_msdkvpp_stop (GstBaseTransform * trans)
887 gst_msdkvpp_close (GST_MSDKVPP (trans));
892 gst_msdkvpp_set_property (GObject * object, guint prop_id,
893 const GValue * value, GParamSpec * pspec)
895 GstMsdkVPP *thiz = GST_MSDKVPP (object);
899 thiz->hardware = g_value_get_boolean (value);
901 case PROP_ASYNC_DEPTH:
902 thiz->async_depth = g_value_get_uint (value);
905 thiz->denoise_factor = g_value_get_uint (value);
906 thiz->flags |= GST_MSDK_FLAG_DENOISE;
909 thiz->rotation = g_value_get_enum (value);
910 thiz->flags |= GST_MSDK_FLAG_ROTATION;
912 case PROP_DEINTERLACE_MODE:
913 thiz->deinterlace_mode = g_value_get_enum (value);
915 case PROP_DEINTERLACE_METHOD:
916 thiz->deinterlace_method = g_value_get_enum (value);
919 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
925 gst_msdkvpp_get_property (GObject * object, guint prop_id,
926 GValue * value, GParamSpec * pspec)
928 GstMsdkVPP *thiz = GST_MSDKVPP (object);
932 g_value_set_boolean (value, thiz->hardware);
934 case PROP_ASYNC_DEPTH:
935 g_value_set_uint (value, thiz->async_depth);
938 g_value_set_uint (value, thiz->denoise_factor);
941 g_value_set_enum (value, thiz->rotation);
943 case PROP_DEINTERLACE_MODE:
944 g_value_set_enum (value, thiz->deinterlace_mode);
946 case PROP_DEINTERLACE_METHOD:
947 g_value_set_enum (value, thiz->deinterlace_method);
950 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
956 gst_msdkvpp_finalize (GObject * object)
958 G_OBJECT_CLASS (parent_class)->finalize (object);
962 gst_msdkvpp_set_context (GstElement * element, GstContext * context)
964 GstMsdkContext *msdk_context = NULL;
965 GstMsdkVPP *thiz = GST_MSDKVPP (element);
967 if (gst_msdk_context_get_context (context, &msdk_context)) {
968 gst_object_replace ((GstObject **) & thiz->context,
969 (GstObject *) msdk_context);
970 gst_object_unref (msdk_context);
973 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
977 gst_msdkvpp_class_init (GstMsdkVPPClass * klass)
979 GObjectClass *gobject_class;
980 GstElementClass *element_class;
981 GstBaseTransformClass *trans_class;
982 GParamSpec *obj_properties[PROP_N] = { NULL, };
984 gobject_class = G_OBJECT_CLASS (klass);
985 element_class = GST_ELEMENT_CLASS (klass);
986 trans_class = GST_BASE_TRANSFORM_CLASS (klass);
988 gobject_class->set_property = gst_msdkvpp_set_property;
989 gobject_class->get_property = gst_msdkvpp_get_property;
990 gobject_class->finalize = gst_msdkvpp_finalize;
992 element_class->set_context = gst_msdkvpp_set_context;
994 gst_element_class_add_static_pad_template (element_class,
995 &gst_msdkvpp_src_factory);
996 gst_element_class_add_static_pad_template (element_class,
997 &gst_msdkvpp_sink_factory);
999 gst_element_class_set_static_metadata (element_class,
1000 "MSDK Video Postprocessor",
1001 "Filter/Converter/Video;Filter/Converter/Video/Scaler;"
1002 "Filter/Effect/Video;Filter/Effect/Video/Deinterlace",
1003 "A MediaSDK Video Postprocessing Filter",
1004 "Sreerenj Balachandrn <sreerenj.balachandran@intel.com>");
1006 trans_class->start = GST_DEBUG_FUNCPTR (gst_msdkvpp_start);
1007 trans_class->stop = GST_DEBUG_FUNCPTR (gst_msdkvpp_stop);
1008 trans_class->transform_caps = GST_DEBUG_FUNCPTR (gst_msdkvpp_transform_caps);
1009 trans_class->fixate_caps = GST_DEBUG_FUNCPTR (gst_msdkvpp_fixate_caps);
1010 trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_msdkvpp_set_caps);
1011 trans_class->transform = GST_DEBUG_FUNCPTR (gst_msdkvpp_transform);
1012 trans_class->propose_allocation =
1013 GST_DEBUG_FUNCPTR (gst_msdkvpp_propose_allocation);
1014 trans_class->decide_allocation =
1015 GST_DEBUG_FUNCPTR (gst_msdkvpp_decide_allocation);
1016 trans_class->prepare_output_buffer =
1017 GST_DEBUG_FUNCPTR (gst_msdkvpp_prepare_output_buffer);
1019 obj_properties[PROP_HARDWARE] =
1020 g_param_spec_boolean ("hardware", "Hardware", "Enable hardware VPP",
1021 PROP_HARDWARE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1023 obj_properties[PROP_ASYNC_DEPTH] =
1024 g_param_spec_uint ("async-depth", "Async Depth",
1025 "Depth of asynchronous pipeline",
1026 1, 1, PROP_ASYNC_DEPTH_DEFAULT,
1027 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1029 obj_properties[PROP_DENOISE] =
1030 g_param_spec_uint ("denoise", "Denoising factor",
1032 0, 100, PROP_DENOISE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1034 obj_properties[PROP_ROTATION] =
1035 g_param_spec_enum ("rotation", "Rotation",
1036 "Rotation Angle", gst_msdkvpp_rotation_get_type (),
1037 PROP_ROTATION_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1039 obj_properties[PROP_DEINTERLACE_MODE] =
1040 g_param_spec_enum ("deinterlace-mode", "Deinterlace Mode",
1041 "Deinterlace mode to use", gst_msdkvpp_deinterlace_mode_get_type (),
1042 PROP_DEINTERLACE_MODE_DEFAULT,
1043 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1045 obj_properties[PROP_DEINTERLACE_METHOD] =
1046 g_param_spec_enum ("deinterlace-method", "Deinterlace Method",
1047 "Deinterlace method to use", gst_msdkvpp_deinterlace_method_get_type (),
1048 PROP_DEINTERLACE_METHOD_DEFAULT,
1049 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1051 g_object_class_install_properties (gobject_class, PROP_N, obj_properties);
1055 gst_msdkvpp_init (GstMsdkVPP * thiz)
1057 thiz->hardware = PROP_HARDWARE_DEFAULT;
1058 thiz->async_depth = PROP_ASYNC_DEPTH_DEFAULT;
1059 thiz->denoise_factor = PROP_DENOISE_DEFAULT;
1060 thiz->rotation = PROP_ROTATION_DEFAULT;
1061 thiz->deinterlace_mode = PROP_DEINTERLACE_MODE_DEFAULT;
1062 thiz->deinterlace_method = PROP_DEINTERLACE_METHOD_DEFAULT;
1063 thiz->field_duration = GST_CLOCK_TIME_NONE;
1064 gst_video_info_init (&thiz->sinkpad_info);
1065 gst_video_info_init (&thiz->srcpad_info);