2 * gstvaapipostproc.c - VA-API video postprocessing
4 * Copyright (C) 2012-2014 Intel Corporation
5 * Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public License
9 * as published by the Free Software Foundation; either version 2.1
10 * of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301 USA
24 * SECTION:gstvaapipostproc
25 * @short_description: A video postprocessing filter
27 * vaapipostproc consists in various postprocessing algorithms to be
28 * applied to VA surfaces. So far, only basic bob deinterlacing is
32 #include "gst/vaapi/sysdeps.h"
33 #include <gst/video/video.h>
35 #include "gstvaapipostproc.h"
36 #include "gstvaapipluginutil.h"
37 #include "gstvaapivideobuffer.h"
38 #if GST_CHECK_VERSION(1,0,0)
39 #include "gstvaapivideobufferpool.h"
40 #include "gstvaapivideomemory.h"
43 #define GST_PLUGIN_NAME "vaapipostproc"
44 #define GST_PLUGIN_DESC "A video postprocessing filter"
46 GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapipostproc);
47 #define GST_CAT_DEFAULT gst_debug_vaapipostproc
49 /* Default templates */
50 static const char gst_vaapipostproc_sink_caps_str[] =
51 #if GST_CHECK_VERSION(1,1,0)
52 GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
53 GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, "{ ENCODED, NV12, I420, YV12 }") ", "
55 GST_VAAPI_SURFACE_CAPS ", "
57 GST_CAPS_INTERLACED_MODES "; "
58 #if GST_CHECK_VERSION(1,0,0)
59 GST_VIDEO_CAPS_MAKE(GST_VIDEO_FORMATS_ALL) ", "
62 "width = " GST_VIDEO_SIZE_RANGE ", "
63 "height = " GST_VIDEO_SIZE_RANGE ", "
64 "framerate = " GST_VIDEO_FPS_RANGE ", "
66 GST_CAPS_INTERLACED_MODES;
68 static const char gst_vaapipostproc_src_caps_str[] =
69 #if GST_CHECK_VERSION(1,1,0)
70 GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
71 GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, "{ ENCODED, NV12, I420, YV12 }") ", "
73 GST_VAAPI_SURFACE_CAPS ", "
75 GST_CAPS_INTERLACED_FALSE;
77 static GstStaticPadTemplate gst_vaapipostproc_sink_factory =
78 GST_STATIC_PAD_TEMPLATE(
82 GST_STATIC_CAPS(gst_vaapipostproc_sink_caps_str));
84 static GstStaticPadTemplate gst_vaapipostproc_src_factory =
85 GST_STATIC_PAD_TEMPLATE(
89 GST_STATIC_CAPS(gst_vaapipostproc_src_caps_str));
91 G_DEFINE_TYPE_WITH_CODE(
94 GST_TYPE_BASE_TRANSFORM,
95 GST_VAAPI_PLUGIN_BASE_INIT_INTERFACES)
103 PROP_FORCE_ASPECT_RATIO,
104 PROP_DEINTERLACE_MODE,
105 PROP_DEINTERLACE_METHOD,
114 #define DEFAULT_FORMAT GST_VIDEO_FORMAT_ENCODED
115 #define DEFAULT_DEINTERLACE_MODE GST_VAAPI_DEINTERLACE_MODE_AUTO
116 #define DEFAULT_DEINTERLACE_METHOD GST_VAAPI_DEINTERLACE_METHOD_BOB
118 #define GST_VAAPI_TYPE_DEINTERLACE_MODE \
119 gst_vaapi_deinterlace_mode_get_type()
122 gst_vaapi_deinterlace_mode_get_type(void)
124 static GType deinterlace_mode_type = 0;
126 static const GEnumValue mode_types[] = {
127 { GST_VAAPI_DEINTERLACE_MODE_AUTO,
128 "Auto detection", "auto" },
129 { GST_VAAPI_DEINTERLACE_MODE_INTERLACED,
130 "Force deinterlacing", "interlaced" },
131 { GST_VAAPI_DEINTERLACE_MODE_DISABLED,
132 "Never deinterlace", "disabled" },
136 if (!deinterlace_mode_type) {
137 deinterlace_mode_type =
138 g_enum_register_static("GstVaapiDeinterlaceMode", mode_types);
140 return deinterlace_mode_type;
144 ds_reset(GstVaapiDeinterlaceState *ds)
148 for (i = 0; i < G_N_ELEMENTS(ds->buffers); i++)
149 gst_buffer_replace(&ds->buffers[i], NULL);
150 ds->buffers_index = 0;
151 ds->num_surfaces = 0;
157 ds_add_buffer(GstVaapiDeinterlaceState *ds, GstBuffer *buf)
159 gst_buffer_replace(&ds->buffers[ds->buffers_index], buf);
160 ds->buffers_index = (ds->buffers_index + 1) % G_N_ELEMENTS(ds->buffers);
163 static inline GstBuffer *
164 ds_get_buffer(GstVaapiDeinterlaceState *ds, guint index)
166 /* Note: the index increases towards older buffers.
167 i.e. buffer at index 0 means the immediately preceding buffer
168 in the history, buffer at index 1 means the one preceding the
169 surface at index 0, etc. */
170 const guint n = ds->buffers_index + G_N_ELEMENTS(ds->buffers) - index - 1;
171 return ds->buffers[n % G_N_ELEMENTS(ds->buffers)];
175 ds_set_surfaces(GstVaapiDeinterlaceState *ds)
177 GstVaapiVideoMeta *meta;
180 ds->num_surfaces = 0;
181 for (i = 0; i < G_N_ELEMENTS(ds->buffers); i++) {
182 GstBuffer * const buf = ds_get_buffer(ds, i);
186 meta = gst_buffer_get_vaapi_video_meta(buf);
187 ds->surfaces[ds->num_surfaces++] =
188 gst_vaapi_video_meta_get_surface(meta);
192 static GstVaapiFilterOpInfo *
193 find_filter_op(GPtrArray *filter_ops, GstVaapiFilterOp op)
198 for (i = 0; i < filter_ops->len; i++) {
199 GstVaapiFilterOpInfo * const filter_op =
200 g_ptr_array_index(filter_ops, i);
201 if (filter_op->op == op)
208 static inline gboolean
209 gst_vaapipostproc_ensure_display(GstVaapiPostproc *postproc)
211 return gst_vaapi_plugin_base_ensure_display(GST_VAAPI_PLUGIN_BASE(postproc));
215 gst_vaapipostproc_ensure_uploader(GstVaapiPostproc *postproc)
217 if (!gst_vaapipostproc_ensure_display(postproc))
219 if (!gst_vaapi_plugin_base_ensure_uploader(GST_VAAPI_PLUGIN_BASE(postproc)))
225 gst_vaapipostproc_ensure_filter(GstVaapiPostproc *postproc)
227 if (postproc->filter)
230 if (!gst_vaapipostproc_ensure_display(postproc))
233 postproc->filter = gst_vaapi_filter_new(
234 GST_VAAPI_PLUGIN_BASE_DISPLAY(postproc));
235 if (!postproc->filter)
241 gst_vaapipostproc_ensure_filter_caps(GstVaapiPostproc *postproc)
243 if (!gst_vaapipostproc_ensure_filter(postproc))
246 postproc->filter_ops = gst_vaapi_filter_get_operations(postproc->filter);
247 if (!postproc->filter_ops)
250 postproc->filter_formats = gst_vaapi_filter_get_formats(postproc->filter);
251 if (!postproc->filter_formats)
257 gst_vaapipostproc_create(GstVaapiPostproc *postproc)
259 if (!gst_vaapi_plugin_base_open(GST_VAAPI_PLUGIN_BASE(postproc)))
261 if (!gst_vaapipostproc_ensure_display(postproc))
263 if (!gst_vaapipostproc_ensure_uploader(postproc))
265 if (gst_vaapipostproc_ensure_filter(postproc))
266 postproc->use_vpp = TRUE;
271 gst_vaapipostproc_destroy_filter(GstVaapiPostproc *postproc)
273 if (postproc->filter_formats) {
274 g_array_unref(postproc->filter_formats);
275 postproc->filter_formats = NULL;
278 if (postproc->filter_ops) {
279 g_ptr_array_unref(postproc->filter_ops);
280 postproc->filter_ops = NULL;
282 gst_vaapi_filter_replace(&postproc->filter, NULL);
283 gst_vaapi_video_pool_replace(&postproc->filter_pool, NULL);
287 gst_vaapipostproc_destroy(GstVaapiPostproc *postproc)
289 ds_reset(&postproc->deinterlace_state);
290 gst_vaapipostproc_destroy_filter(postproc);
292 gst_caps_replace(&postproc->allowed_sinkpad_caps, NULL);
293 gst_caps_replace(&postproc->allowed_srcpad_caps, NULL);
294 gst_vaapi_plugin_base_close(GST_VAAPI_PLUGIN_BASE(postproc));
298 gst_vaapipostproc_start(GstBaseTransform *trans)
300 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
302 ds_reset(&postproc->deinterlace_state);
303 if (!gst_vaapi_plugin_base_open(GST_VAAPI_PLUGIN_BASE(postproc)))
305 if (!gst_vaapipostproc_ensure_display(postproc))
311 gst_vaapipostproc_stop(GstBaseTransform *trans)
313 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
315 ds_reset(&postproc->deinterlace_state);
316 gst_vaapi_plugin_base_close(GST_VAAPI_PLUGIN_BASE(postproc));
321 should_deinterlace_buffer(GstVaapiPostproc *postproc, GstBuffer *buf)
323 if (!(postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE) ||
324 postproc->deinterlace_mode == GST_VAAPI_DEINTERLACE_MODE_DISABLED)
327 if (postproc->deinterlace_mode == GST_VAAPI_DEINTERLACE_MODE_INTERLACED)
330 g_assert(postproc->deinterlace_mode == GST_VAAPI_DEINTERLACE_MODE_AUTO);
332 switch (GST_VIDEO_INFO_INTERLACE_MODE(&postproc->sinkpad_info)) {
333 case GST_VIDEO_INTERLACE_MODE_INTERLEAVED:
335 case GST_VIDEO_INTERLACE_MODE_PROGRESSIVE:
337 case GST_VIDEO_INTERLACE_MODE_MIXED:
338 #if GST_CHECK_VERSION(1,0,0)
339 if (GST_BUFFER_FLAG_IS_SET(buf, GST_VIDEO_BUFFER_FLAG_INTERLACED))
342 if (!GST_BUFFER_FLAG_IS_SET(buf, GST_VIDEO_BUFFER_PROGRESSIVE))
347 GST_ERROR("unhandled \"interlace-mode\", disabling deinterlacing" );
354 create_output_buffer(GstVaapiPostproc *postproc)
358 /* Create a raw VA video buffer without GstVaapiVideoMeta attached
359 to it yet, as this will be done next in the transform() hook */
360 outbuf = gst_vaapi_video_buffer_new_empty();
362 goto error_create_buffer;
364 #if !GST_CHECK_VERSION(1,0,0)
365 gst_buffer_set_caps(outbuf, GST_VAAPI_PLUGIN_BASE_SRC_PAD_CAPS(postproc));
372 GST_ERROR("failed to create output video buffer");
378 append_output_buffer_metadata(GstBuffer *outbuf, GstBuffer *inbuf, guint flags)
380 gst_buffer_copy_into(outbuf, inbuf, flags |
381 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_META | GST_BUFFER_COPY_MEMORY,
386 deint_method_is_advanced(GstVaapiDeinterlaceMethod deint_method)
388 gboolean is_advanced;
390 switch (deint_method) {
391 case GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE:
392 case GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED:
402 static GstVaapiDeinterlaceMethod
403 get_next_deint_method(GstVaapiDeinterlaceMethod deint_method)
405 switch (deint_method) {
406 case GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED:
407 deint_method = GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE;
410 /* Default to basic "bob" for all others */
411 deint_method = GST_VAAPI_DEINTERLACE_METHOD_BOB;
418 set_best_deint_method(GstVaapiPostproc *postproc, guint flags,
419 GstVaapiDeinterlaceMethod *deint_method_ptr)
421 GstVaapiDeinterlaceMethod deint_method = postproc->deinterlace_method;
425 success = gst_vaapi_filter_set_deinterlacing(postproc->filter,
426 deint_method, flags);
427 if (success || deint_method == GST_VAAPI_DEINTERLACE_METHOD_BOB)
429 deint_method = get_next_deint_method(deint_method);
431 *deint_method_ptr = deint_method;
436 gst_vaapipostproc_process_vpp(GstBaseTransform *trans, GstBuffer *inbuf,
439 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
440 GstVaapiDeinterlaceState * const ds = &postproc->deinterlace_state;
441 GstVaapiVideoMeta *inbuf_meta, *outbuf_meta;
442 GstVaapiSurface *inbuf_surface, *outbuf_surface;
443 GstVaapiFilterStatus status;
444 GstClockTime timestamp;
447 GstVaapiDeinterlaceMethod deint_method;
448 guint flags, deint_flags;
449 gboolean tff, deint, deint_refs, deint_changed;
450 GstVaapiRectangle *crop_rect = NULL;
451 #if GST_CHECK_VERSION(1,0,0)
452 GstVaapiRectangle tmp_rect;
455 /* Validate filters */
456 if ((postproc->flags & GST_VAAPI_POSTPROC_FLAG_FORMAT) &&
457 !gst_vaapi_filter_set_format(postproc->filter, postproc->format))
458 return GST_FLOW_NOT_SUPPORTED;
460 if ((postproc->flags & GST_VAAPI_POSTPROC_FLAG_DENOISE) &&
461 !gst_vaapi_filter_set_denoising_level(postproc->filter,
462 postproc->denoise_level))
463 return GST_FLOW_NOT_SUPPORTED;
465 if ((postproc->flags & GST_VAAPI_POSTPROC_FLAG_SHARPEN) &&
466 !gst_vaapi_filter_set_sharpening_level(postproc->filter,
467 postproc->sharpen_level))
468 return GST_FLOW_NOT_SUPPORTED;
470 if ((postproc->flags & GST_VAAPI_POSTPROC_FLAG_HUE) &&
471 !gst_vaapi_filter_set_hue(postproc->filter,
473 return GST_FLOW_NOT_SUPPORTED;
475 if ((postproc->flags & GST_VAAPI_POSTPROC_FLAG_SATURATION) &&
476 !gst_vaapi_filter_set_saturation(postproc->filter,
477 postproc->saturation))
478 return GST_FLOW_NOT_SUPPORTED;
480 if ((postproc->flags & GST_VAAPI_POSTPROC_FLAG_BRIGHTNESS) &&
481 !gst_vaapi_filter_set_brightness(postproc->filter,
482 postproc->brightness))
483 return GST_FLOW_NOT_SUPPORTED;
485 if ((postproc->flags & GST_VAAPI_POSTPROC_FLAG_CONTRAST) &&
486 !gst_vaapi_filter_set_contrast(postproc->filter,
488 return GST_FLOW_NOT_SUPPORTED;
490 inbuf_meta = gst_buffer_get_vaapi_video_meta(inbuf);
492 goto error_invalid_buffer;
493 inbuf_surface = gst_vaapi_video_meta_get_surface(inbuf_meta);
495 #if GST_CHECK_VERSION(1,0,0)
496 GstVideoCropMeta * const crop_meta =
497 gst_buffer_get_video_crop_meta(inbuf);
499 crop_rect = &tmp_rect;
500 crop_rect->x = crop_meta->x;
501 crop_rect->y = crop_meta->y;
502 crop_rect->width = crop_meta->width;
503 crop_rect->height = crop_meta->height;
507 crop_rect = (GstVaapiRectangle *)
508 gst_vaapi_video_meta_get_render_rect(inbuf_meta);
510 timestamp = GST_BUFFER_TIMESTAMP(inbuf);
511 tff = GST_BUFFER_FLAG_IS_SET(inbuf, GST_VIDEO_BUFFER_FLAG_TFF);
512 deint = should_deinterlace_buffer(postproc, inbuf);
514 /* Drop references if deinterlacing conditions changed */
515 deint_changed = deint != ds->deint;
516 if (deint_changed || (ds->num_surfaces > 0 && tff != ds->tff))
519 deint_method = postproc->deinterlace_method;
520 deint_refs = deint_method_is_advanced(deint_method);
522 GstBuffer * const prev_buf = ds_get_buffer(ds, 0);
523 GstClockTime prev_pts, pts = GST_BUFFER_TIMESTAMP(inbuf);
524 /* Reset deinterlacing state when there is a discontinuity */
525 if (prev_buf && (prev_pts = GST_BUFFER_TIMESTAMP(prev_buf)) != pts) {
526 const GstClockTimeDiff pts_diff = GST_CLOCK_DIFF(prev_pts, pts);
527 if (pts_diff < 0 || (postproc->field_duration > 0 &&
528 pts_diff > postproc->field_duration * 2))
536 flags = gst_vaapi_video_meta_get_render_flags(inbuf_meta) &
537 ~GST_VAAPI_PICTURE_STRUCTURE_MASK;
540 if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE) {
541 fieldbuf = create_output_buffer(postproc);
543 goto error_create_buffer;
545 outbuf_meta = gst_vaapi_video_meta_new_from_pool(postproc->filter_pool);
547 goto error_create_meta;
548 outbuf_surface = gst_vaapi_video_meta_get_surface(outbuf_meta);
551 deint_flags = (tff ? GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD : 0);
553 deint_flags |= GST_VAAPI_DEINTERLACE_FLAG_TFF;
554 if (!set_best_deint_method(postproc, deint_flags, &deint_method))
555 goto error_op_deinterlace;
557 if (deint_method != postproc->deinterlace_method) {
558 GST_DEBUG("unsupported deinterlace-method %u. Using %u instead",
559 postproc->deinterlace_method, deint_method);
560 postproc->deinterlace_method = deint_method;
561 deint_refs = deint_method_is_advanced(deint_method);
566 if (!gst_vaapi_filter_set_deinterlacing_references(
567 postproc->filter, ds->surfaces, ds->num_surfaces,
569 goto error_op_deinterlace;
572 else if (deint_changed) {
573 // Reset internal filter to non-deinterlacing mode
574 deint_method = GST_VAAPI_DEINTERLACE_METHOD_NONE;
575 if (!gst_vaapi_filter_set_deinterlacing(postproc->filter,
577 goto error_op_deinterlace;
580 gst_vaapi_filter_set_cropping_rectangle(postproc->filter, crop_rect);
581 status = gst_vaapi_filter_process(postproc->filter, inbuf_surface,
582 outbuf_surface, flags);
583 if (status != GST_VAAPI_FILTER_STATUS_SUCCESS)
584 goto error_process_vpp;
586 gst_buffer_set_vaapi_video_meta(fieldbuf, outbuf_meta);
587 gst_vaapi_video_meta_unref(outbuf_meta);
589 GST_BUFFER_TIMESTAMP(fieldbuf) = timestamp;
590 GST_BUFFER_DURATION(fieldbuf) = postproc->field_duration;
591 ret = gst_pad_push(trans->srcpad, fieldbuf);
592 if (ret != GST_FLOW_OK)
593 goto error_push_buffer;
598 outbuf_meta = gst_vaapi_video_meta_new_from_pool(postproc->filter_pool);
600 goto error_create_meta;
601 outbuf_surface = gst_vaapi_video_meta_get_surface(outbuf_meta);
604 deint_flags = (tff ? 0 : GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD);
606 deint_flags |= GST_VAAPI_DEINTERLACE_FLAG_TFF;
607 if (!gst_vaapi_filter_set_deinterlacing(postproc->filter,
608 deint_method, deint_flags))
609 goto error_op_deinterlace;
611 if (deint_refs && !gst_vaapi_filter_set_deinterlacing_references(
612 postproc->filter, ds->surfaces, ds->num_surfaces, NULL, 0))
613 goto error_op_deinterlace;
615 else if (deint_changed && !gst_vaapi_filter_set_deinterlacing(
616 postproc->filter, deint_method, 0))
617 goto error_op_deinterlace;
619 gst_vaapi_filter_set_cropping_rectangle(postproc->filter, crop_rect);
620 status = gst_vaapi_filter_process(postproc->filter, inbuf_surface,
621 outbuf_surface, flags);
622 if (status != GST_VAAPI_FILTER_STATUS_SUCCESS)
623 goto error_process_vpp;
625 if (!(postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE))
626 gst_buffer_copy_into(outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
628 GST_BUFFER_TIMESTAMP(outbuf) = timestamp + postproc->field_duration;
629 GST_BUFFER_DURATION(outbuf) = postproc->field_duration;
631 gst_buffer_set_vaapi_video_meta(outbuf, outbuf_meta);
632 gst_vaapi_video_meta_unref(outbuf_meta);
634 if (deint && deint_refs)
635 ds_add_buffer(ds, inbuf);
639 error_invalid_buffer:
641 GST_ERROR("failed to validate source buffer");
642 return GST_FLOW_ERROR;
646 GST_ERROR("failed to create output buffer");
647 return GST_FLOW_ERROR;
651 GST_ERROR("failed to create new output buffer meta");
652 gst_buffer_replace(&fieldbuf, NULL);
653 gst_vaapi_video_meta_unref(outbuf_meta);
654 return GST_FLOW_ERROR;
656 error_op_deinterlace:
658 GST_ERROR("failed to apply deinterlacing filter");
659 gst_buffer_replace(&fieldbuf, NULL);
660 gst_vaapi_video_meta_unref(outbuf_meta);
661 return GST_FLOW_NOT_SUPPORTED;
665 GST_ERROR("failed to apply VPP filters (error %d)", status);
666 gst_buffer_replace(&fieldbuf, NULL);
667 gst_vaapi_video_meta_unref(outbuf_meta);
668 return GST_FLOW_ERROR;
672 if (ret != GST_FLOW_FLUSHING)
673 GST_ERROR("failed to push output buffer to video sink");
674 return GST_FLOW_ERROR;
679 gst_vaapipostproc_process(GstBaseTransform *trans, GstBuffer *inbuf,
682 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
683 GstVaapiVideoMeta *meta;
684 GstClockTime timestamp;
687 guint fieldbuf_flags, outbuf_flags, flags;
690 meta = gst_buffer_get_vaapi_video_meta(inbuf);
692 goto error_invalid_buffer;
694 timestamp = GST_BUFFER_TIMESTAMP(inbuf);
695 tff = GST_BUFFER_FLAG_IS_SET(inbuf, GST_VIDEO_BUFFER_FLAG_TFF);
696 deint = should_deinterlace_buffer(postproc, inbuf);
698 flags = gst_vaapi_video_meta_get_render_flags(meta) &
699 ~GST_VAAPI_PICTURE_STRUCTURE_MASK;
702 fieldbuf = create_output_buffer(postproc);
704 goto error_create_buffer;
705 append_output_buffer_metadata(fieldbuf, inbuf, 0);
707 meta = gst_buffer_get_vaapi_video_meta(fieldbuf);
708 fieldbuf_flags = flags;
709 fieldbuf_flags |= deint ? (
711 GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD :
712 GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD) :
713 GST_VAAPI_PICTURE_STRUCTURE_FRAME;
714 gst_vaapi_video_meta_set_render_flags(meta, fieldbuf_flags);
716 GST_BUFFER_TIMESTAMP(fieldbuf) = timestamp;
717 GST_BUFFER_DURATION(fieldbuf) = postproc->field_duration;
718 ret = gst_pad_push(trans->srcpad, fieldbuf);
719 if (ret != GST_FLOW_OK)
720 goto error_push_buffer;
723 append_output_buffer_metadata(outbuf, inbuf, 0);
725 meta = gst_buffer_get_vaapi_video_meta(outbuf);
726 outbuf_flags = flags;
727 outbuf_flags |= deint ? (
729 GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD :
730 GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD) :
731 GST_VAAPI_PICTURE_STRUCTURE_FRAME;
732 gst_vaapi_video_meta_set_render_flags(meta, outbuf_flags);
734 GST_BUFFER_TIMESTAMP(outbuf) = timestamp + postproc->field_duration;
735 GST_BUFFER_DURATION(outbuf) = postproc->field_duration;
739 error_invalid_buffer:
741 GST_ERROR("failed to validate source buffer");
742 return GST_FLOW_ERROR;
746 GST_ERROR("failed to create output buffer");
751 if (ret != GST_FLOW_FLUSHING)
752 GST_ERROR("failed to push output buffer to video sink");
758 gst_vaapipostproc_passthrough(GstBaseTransform *trans, GstBuffer *inbuf,
761 GstVaapiVideoMeta *meta;
763 /* No video processing needed, simply copy buffer metadata */
764 meta = gst_buffer_get_vaapi_video_meta(inbuf);
766 goto error_invalid_buffer;
768 append_output_buffer_metadata(outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS);
772 error_invalid_buffer:
774 GST_ERROR("failed to validate source buffer");
775 return GST_FLOW_ERROR;
780 is_deinterlace_enabled(GstVaapiPostproc *postproc, GstVideoInfo *vip)
782 gboolean deinterlace;
784 switch (postproc->deinterlace_mode) {
785 case GST_VAAPI_DEINTERLACE_MODE_AUTO:
786 deinterlace = GST_VIDEO_INFO_IS_INTERLACED(vip);
788 case GST_VAAPI_DEINTERLACE_MODE_INTERLACED:
799 video_info_changed(GstVideoInfo *old_vip, GstVideoInfo *new_vip)
801 if (GST_VIDEO_INFO_FORMAT(old_vip) != GST_VIDEO_INFO_FORMAT(new_vip))
803 if (GST_VIDEO_INFO_INTERLACE_MODE(old_vip) !=
804 GST_VIDEO_INFO_INTERLACE_MODE(new_vip))
806 if (GST_VIDEO_INFO_WIDTH(old_vip) != GST_VIDEO_INFO_WIDTH(new_vip))
808 if (GST_VIDEO_INFO_HEIGHT(old_vip) != GST_VIDEO_INFO_HEIGHT(new_vip))
814 gst_vaapipostproc_update_sink_caps(GstVaapiPostproc *postproc, GstCaps *caps,
815 gboolean *caps_changed_ptr)
818 gboolean deinterlace;
820 if (!gst_video_info_from_caps(&vi, caps))
823 if (video_info_changed(&vi, &postproc->sinkpad_info))
824 postproc->sinkpad_info = vi, *caps_changed_ptr = TRUE;
826 deinterlace = is_deinterlace_enabled(postproc, &vi);
828 postproc->flags |= GST_VAAPI_POSTPROC_FLAG_DEINTERLACE;
829 postproc->field_duration = GST_VIDEO_INFO_FPS_N(&vi) > 0 ?
830 gst_util_uint64_scale(GST_SECOND, GST_VIDEO_INFO_FPS_D(&vi),
831 (1 + deinterlace) * GST_VIDEO_INFO_FPS_N(&vi)) : 0;
833 postproc->is_raw_yuv = GST_VIDEO_INFO_IS_YUV(&vi);
838 gst_vaapipostproc_update_src_caps(GstVaapiPostproc *postproc, GstCaps *caps,
839 gboolean *caps_changed_ptr)
843 if (!gst_video_info_from_caps(&vi, caps))
846 if (video_info_changed(&vi, &postproc->srcpad_info))
847 postproc->srcpad_info = vi, *caps_changed_ptr = TRUE;
849 if (postproc->format != GST_VIDEO_INFO_FORMAT(&postproc->sinkpad_info))
850 postproc->flags |= GST_VAAPI_POSTPROC_FLAG_FORMAT;
852 if ((postproc->width || postproc->height) &&
853 postproc->width != GST_VIDEO_INFO_WIDTH(&postproc->sinkpad_info) &&
854 postproc->height != GST_VIDEO_INFO_HEIGHT(&postproc->sinkpad_info))
855 postproc->flags |= GST_VAAPI_POSTPROC_FLAG_SIZE;
860 ensure_allowed_sinkpad_caps(GstVaapiPostproc *postproc)
862 GstCaps *out_caps, *yuv_caps;
864 if (postproc->allowed_sinkpad_caps)
868 #if GST_CHECK_VERSION(1,1,0)
869 out_caps = gst_static_pad_template_get_caps(
870 &gst_vaapipostproc_sink_factory);
872 out_caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS ", "
873 GST_CAPS_INTERLACED_MODES);
876 GST_ERROR("failed to create VA sink caps");
880 /* Append YUV caps */
881 if (gst_vaapipostproc_ensure_uploader(postproc)) {
882 yuv_caps = GST_VAAPI_PLUGIN_BASE_UPLOADER_CAPS(postproc);
884 out_caps = gst_caps_make_writable(out_caps);
885 gst_caps_append(out_caps, gst_caps_copy(yuv_caps));
888 GST_WARNING("failed to create YUV sink caps");
890 postproc->allowed_sinkpad_caps = out_caps;
892 /* XXX: append VA/VPP filters */
896 /* Fixup output caps so that to reflect the supported set of pixel formats */
898 expand_allowed_srcpad_caps(GstVaapiPostproc *postproc, GstCaps *caps)
900 GValue value = G_VALUE_INIT, v_format = G_VALUE_INIT;
901 guint i, num_structures;
904 had_filter = postproc->filter != NULL;
905 if (!had_filter && !gst_vaapipostproc_ensure_filter(postproc))
907 if (!gst_vaapipostproc_ensure_filter_caps(postproc))
910 /* Reset "format" field for each structure */
911 if (!gst_vaapi_value_set_format_list(&value, postproc->filter_formats))
913 if (gst_vaapi_value_set_format(&v_format, GST_VIDEO_FORMAT_ENCODED)) {
914 gst_value_list_prepend_value(&value, &v_format);
915 g_value_unset(&v_format);
918 num_structures = gst_caps_get_size(caps);
919 for (i = 0; i < num_structures; i++) {
920 GstStructure * const structure = gst_caps_get_structure(caps, i);
923 gst_structure_set_value(structure, "format", &value);
925 g_value_unset(&value);
929 gst_vaapipostproc_destroy_filter(postproc);
934 ensure_allowed_srcpad_caps(GstVaapiPostproc *postproc)
938 if (postproc->allowed_srcpad_caps)
941 /* Create initial caps from pad template */
942 out_caps = gst_caps_from_string(gst_vaapipostproc_src_caps_str);
944 GST_ERROR("failed to create VA src caps");
948 postproc->allowed_srcpad_caps =
949 expand_allowed_srcpad_caps(postproc, out_caps);
950 return postproc->allowed_srcpad_caps != NULL;
954 find_best_size(GstVaapiPostproc *postproc, GstVideoInfo *vip,
955 guint *width_ptr, guint *height_ptr)
959 width = GST_VIDEO_INFO_WIDTH(vip);
960 height = GST_VIDEO_INFO_HEIGHT(vip);
961 if (postproc->width && postproc->height) {
962 width = postproc->width;
963 height = postproc->height;
965 else if (postproc->keep_aspect) {
966 const gdouble ratio = (gdouble)width / height;
967 if (postproc->width) {
968 width = postproc->width;
969 height = postproc->width / ratio;
971 else if (postproc->height) {
972 height = postproc->height;
973 width = postproc->height * ratio;
976 else if (postproc->width)
977 width = postproc->width;
978 else if (postproc->height)
979 height = postproc->height;
982 *height_ptr = height;
986 gst_vaapipostproc_transform_caps_impl(GstBaseTransform *trans,
987 GstPadDirection direction, GstCaps *caps)
989 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
991 GstVideoFormat format;
995 /* Generate the sink pad caps, that could be fixated afterwards */
996 if (direction == GST_PAD_SRC) {
997 if (!ensure_allowed_sinkpad_caps(postproc))
999 return gst_caps_ref(postproc->allowed_sinkpad_caps);
1002 /* Generate complete set of src pad caps if non-fixated sink pad
1003 caps are provided */
1004 if (!gst_caps_is_fixed(caps)) {
1005 if (!ensure_allowed_srcpad_caps(postproc))
1007 return gst_caps_ref(postproc->allowed_srcpad_caps);
1010 /* Generate the expected src pad caps, from the current fixated
1012 if (!gst_video_info_from_caps(&vi, caps))
1015 // Set double framerate in interlaced mode
1016 if (is_deinterlace_enabled(postproc, &vi)) {
1017 gint fps_n = GST_VIDEO_INFO_FPS_N(&vi);
1018 gint fps_d = GST_VIDEO_INFO_FPS_D(&vi);
1019 if (!gst_util_fraction_multiply(fps_n, fps_d, 2, 1, &fps_n, &fps_d))
1021 GST_VIDEO_INFO_FPS_N(&vi) = fps_n;
1022 GST_VIDEO_INFO_FPS_D(&vi) = fps_d;
1025 // Signal the other pad that we only generate progressive frames
1026 GST_VIDEO_INFO_INTERLACE_MODE(&vi) = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
1028 // Update size from user-specified parameters
1029 #if GST_CHECK_VERSION(1,1,0)
1030 format = postproc->format;
1032 format = GST_VIDEO_FORMAT_ENCODED;
1034 find_best_size(postproc, &vi, &width, &height);
1035 gst_video_info_set_format(&vi, format, width, height);
1037 #if GST_CHECK_VERSION(1,1,0)
1038 out_caps = gst_video_info_to_caps(&vi);
1042 gst_caps_set_features(out_caps, 0,
1043 gst_caps_features_new(GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, NULL));
1045 /* XXX: gst_video_info_to_caps() from GStreamer 0.10 does not
1046 reconstruct suitable caps for "encoded" video formats */
1047 out_caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS_NAME);
1051 gst_caps_set_simple(out_caps,
1052 "type", G_TYPE_STRING, "vaapi",
1053 "opengl", G_TYPE_BOOLEAN, USE_GLX,
1054 "width", G_TYPE_INT, GST_VIDEO_INFO_WIDTH(&vi),
1055 "height", G_TYPE_INT, GST_VIDEO_INFO_HEIGHT(&vi),
1056 "framerate", GST_TYPE_FRACTION, GST_VIDEO_INFO_FPS_N(&vi),
1057 GST_VIDEO_INFO_FPS_D(&vi),
1058 "pixel-aspect-ratio", GST_TYPE_FRACTION, GST_VIDEO_INFO_PAR_N(&vi),
1059 GST_VIDEO_INFO_PAR_D(&vi),
1062 gst_caps_set_interlaced(out_caps, &vi);
1067 #if GST_CHECK_VERSION(1,0,0)
1069 gst_vaapipostproc_transform_caps(GstBaseTransform *trans,
1070 GstPadDirection direction, GstCaps *caps, GstCaps *filter)
1074 caps = gst_vaapipostproc_transform_caps_impl(trans, direction, caps);
1075 if (caps && filter) {
1076 out_caps = gst_caps_intersect_full(caps, filter,
1077 GST_CAPS_INTERSECT_FIRST);
1078 gst_caps_unref(caps);
1084 #define gst_vaapipostproc_transform_caps \
1085 gst_vaapipostproc_transform_caps_impl
1088 #if GST_CHECK_VERSION(1,0,0)
1089 typedef gsize GstBaseTransformSizeType;
1091 typedef guint GstBaseTransformSizeType;
1095 gst_vaapipostproc_transform_size(GstBaseTransform *trans,
1096 GstPadDirection direction, GstCaps *caps, GstBaseTransformSizeType size,
1097 GstCaps *othercaps, GstBaseTransformSizeType *othersize)
1099 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
1101 if (direction == GST_PAD_SINK || !postproc->is_raw_yuv)
1108 static GstFlowReturn
1109 gst_vaapipostproc_transform(GstBaseTransform *trans, GstBuffer *inbuf,
1112 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
1116 ret = gst_vaapi_plugin_base_get_input_buffer(
1117 GST_VAAPI_PLUGIN_BASE(postproc), inbuf, &buf);
1118 if (ret != GST_FLOW_OK)
1119 return GST_FLOW_ERROR;
1121 ret = GST_FLOW_NOT_SUPPORTED;
1122 if (postproc->flags) {
1123 /* Use VA/VPP extensions to process this frame */
1124 if (postproc->use_vpp &&
1125 postproc->flags != GST_VAAPI_POSTPROC_FLAG_DEINTERLACE) {
1126 ret = gst_vaapipostproc_process_vpp(trans, buf, outbuf);
1127 if (ret != GST_FLOW_NOT_SUPPORTED)
1129 GST_WARNING("unsupported VPP filters. Disabling");
1130 postproc->use_vpp = FALSE;
1133 /* Only append picture structure meta data (top/bottom field) */
1134 if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE) {
1135 ret = gst_vaapipostproc_process(trans, buf, outbuf);
1136 if (ret != GST_FLOW_NOT_SUPPORTED)
1141 /* Fallback: passthrough to the downstream element as is */
1142 ret = gst_vaapipostproc_passthrough(trans, buf, outbuf);
1145 gst_buffer_unref(buf);
1149 static GstFlowReturn
1150 gst_vaapipostproc_prepare_output_buffer(GstBaseTransform *trans,
1152 #if !GST_CHECK_VERSION(1,0,0)
1153 gint size, GstCaps *caps,
1155 GstBuffer **outbuf_ptr)
1157 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
1159 *outbuf_ptr = create_output_buffer(postproc);
1160 return *outbuf_ptr ? GST_FLOW_OK : GST_FLOW_ERROR;
1164 ensure_srcpad_buffer_pool(GstVaapiPostproc *postproc, GstCaps *caps)
1167 GstVaapiVideoPool *pool;
1169 gst_video_info_init(&vi);
1170 gst_video_info_from_caps(&vi, caps);
1171 gst_video_info_set_format(&vi, postproc->format,
1172 GST_VIDEO_INFO_WIDTH(&vi), GST_VIDEO_INFO_HEIGHT(&vi));
1174 if (postproc->filter_pool && !video_info_changed(&vi, &postproc->filter_pool_info))
1176 postproc->filter_pool_info = vi;
1178 pool = gst_vaapi_surface_pool_new(GST_VAAPI_PLUGIN_BASE_DISPLAY(postproc),
1179 &postproc->filter_pool_info);
1183 gst_vaapi_video_pool_replace(&postproc->filter_pool, pool);
1184 gst_vaapi_video_pool_unref(pool);
1189 gst_vaapipostproc_set_caps(GstBaseTransform *trans, GstCaps *caps,
1192 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
1193 gboolean caps_changed = FALSE;
1195 if (!gst_vaapipostproc_update_sink_caps(postproc, caps, &caps_changed))
1197 if (!gst_vaapipostproc_update_src_caps(postproc, out_caps, &caps_changed))
1201 gst_vaapipostproc_destroy(postproc);
1202 if (!gst_vaapipostproc_create(postproc))
1204 if (!gst_vaapi_plugin_base_set_caps(GST_VAAPI_PLUGIN_BASE(trans),
1209 if (!ensure_srcpad_buffer_pool(postproc, out_caps))
1215 gst_vaapipostproc_query(GstBaseTransform *trans, GstPadDirection direction,
1218 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
1220 GST_INFO_OBJECT(trans, "query type `%s'", GST_QUERY_TYPE_NAME(query));
1222 if (gst_vaapi_reply_to_query(query, GST_VAAPI_PLUGIN_BASE_DISPLAY(postproc))) {
1223 GST_DEBUG("sharing display %p", GST_VAAPI_PLUGIN_BASE_DISPLAY(postproc));
1227 return GST_BASE_TRANSFORM_CLASS(gst_vaapipostproc_parent_class)->query(
1228 trans, direction, query);
1231 #if GST_CHECK_VERSION(1,0,0)
1233 gst_vaapipostproc_propose_allocation(GstBaseTransform *trans,
1234 GstQuery *decide_query, GstQuery *query)
1236 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
1237 GstVaapiPluginBase * const plugin = GST_VAAPI_PLUGIN_BASE(trans);
1239 /* Let vaapidecode allocate the video buffers */
1240 if (!postproc->is_raw_yuv)
1242 if (!gst_vaapi_plugin_base_propose_allocation(plugin, query))
1249 gst_vaapipostproc_finalize(GObject *object)
1251 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(object);
1253 gst_vaapipostproc_destroy(postproc);
1255 gst_vaapi_plugin_base_finalize(GST_VAAPI_PLUGIN_BASE(postproc));
1256 G_OBJECT_CLASS(gst_vaapipostproc_parent_class)->finalize(object);
1260 gst_vaapipostproc_set_property(
1263 const GValue *value,
1267 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(object);
1271 postproc->format = g_value_get_enum(value);
1274 postproc->width = g_value_get_uint(value);
1277 postproc->height = g_value_get_uint(value);
1279 case PROP_FORCE_ASPECT_RATIO:
1280 postproc->keep_aspect = g_value_get_boolean(value);
1282 case PROP_DEINTERLACE_MODE:
1283 postproc->deinterlace_mode = g_value_get_enum(value);
1285 case PROP_DEINTERLACE_METHOD:
1286 postproc->deinterlace_method = g_value_get_enum(value);
1289 postproc->denoise_level = g_value_get_float(value);
1290 postproc->flags |= GST_VAAPI_POSTPROC_FLAG_DENOISE;
1293 postproc->sharpen_level = g_value_get_float(value);
1294 postproc->flags |= GST_VAAPI_POSTPROC_FLAG_SHARPEN;
1297 postproc->hue = g_value_get_float(value);
1298 postproc->flags |= GST_VAAPI_POSTPROC_FLAG_HUE;
1300 case PROP_SATURATION:
1301 postproc->saturation = g_value_get_float(value);
1302 postproc->flags |= GST_VAAPI_POSTPROC_FLAG_SATURATION;
1304 case PROP_BRIGHTNESS:
1305 postproc->brightness = g_value_get_float(value);
1306 postproc->flags |= GST_VAAPI_POSTPROC_FLAG_BRIGHTNESS;
1309 postproc->contrast = g_value_get_float(value);
1310 postproc->flags |= GST_VAAPI_POSTPROC_FLAG_CONTRAST;
1313 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
1319 gst_vaapipostproc_get_property(
1326 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(object);
1330 g_value_set_enum(value, postproc->format);
1333 g_value_set_uint(value, postproc->width);
1336 g_value_set_uint(value, postproc->height);
1338 case PROP_FORCE_ASPECT_RATIO:
1339 g_value_set_boolean(value, postproc->keep_aspect);
1341 case PROP_DEINTERLACE_MODE:
1342 g_value_set_enum(value, postproc->deinterlace_mode);
1344 case PROP_DEINTERLACE_METHOD:
1345 g_value_set_enum(value, postproc->deinterlace_method);
1348 g_value_set_float(value, postproc->denoise_level);
1351 g_value_set_float(value, postproc->sharpen_level);
1354 g_value_set_float(value, postproc->hue);
1356 case PROP_SATURATION:
1357 g_value_set_float(value, postproc->saturation);
1359 case PROP_BRIGHTNESS:
1360 g_value_set_float(value, postproc->brightness);
1363 g_value_set_float(value, postproc->contrast);
1366 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
1372 gst_vaapipostproc_class_init(GstVaapiPostprocClass *klass)
1374 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
1375 GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
1376 GstBaseTransformClass * const trans_class = GST_BASE_TRANSFORM_CLASS(klass);
1377 GstPadTemplate *pad_template;
1378 GPtrArray *filter_ops;
1379 GstVaapiFilterOpInfo *filter_op;
1381 GST_DEBUG_CATEGORY_INIT(gst_debug_vaapipostproc,
1382 GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
1384 gst_vaapi_plugin_base_class_init(GST_VAAPI_PLUGIN_BASE_CLASS(klass));
1386 object_class->finalize = gst_vaapipostproc_finalize;
1387 object_class->set_property = gst_vaapipostproc_set_property;
1388 object_class->get_property = gst_vaapipostproc_get_property;
1389 trans_class->start = gst_vaapipostproc_start;
1390 trans_class->stop = gst_vaapipostproc_stop;
1391 trans_class->transform_caps = gst_vaapipostproc_transform_caps;
1392 trans_class->transform_size = gst_vaapipostproc_transform_size;
1393 trans_class->transform = gst_vaapipostproc_transform;
1394 trans_class->set_caps = gst_vaapipostproc_set_caps;
1395 trans_class->query = gst_vaapipostproc_query;
1397 #if GST_CHECK_VERSION(1,0,0)
1398 trans_class->propose_allocation = gst_vaapipostproc_propose_allocation;
1401 trans_class->prepare_output_buffer =
1402 gst_vaapipostproc_prepare_output_buffer;
1404 gst_element_class_set_static_metadata(element_class,
1405 "VA-API video postprocessing",
1406 "Filter/Converter/Video",
1408 "Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
1411 pad_template = gst_static_pad_template_get(&gst_vaapipostproc_sink_factory);
1412 gst_element_class_add_pad_template(element_class, pad_template);
1415 pad_template = gst_static_pad_template_get(&gst_vaapipostproc_src_factory);
1416 gst_element_class_add_pad_template(element_class, pad_template);
1419 * GstVaapiPostproc:deinterlace-mode:
1421 * This selects whether the deinterlacing should always be applied or if
1422 * they should only be applied on content that has the "interlaced" flag
1425 g_object_class_install_property
1427 PROP_DEINTERLACE_MODE,
1428 g_param_spec_enum("deinterlace-mode",
1430 "Deinterlace mode to use",
1431 GST_VAAPI_TYPE_DEINTERLACE_MODE,
1432 DEFAULT_DEINTERLACE_MODE,
1433 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1436 * GstVaapiPostproc:deinterlace-method:
1438 * This selects the deinterlacing method to apply.
1440 g_object_class_install_property
1442 PROP_DEINTERLACE_METHOD,
1443 g_param_spec_enum("deinterlace-method",
1444 "Deinterlace method",
1445 "Deinterlace method to use",
1446 GST_VAAPI_TYPE_DEINTERLACE_METHOD,
1447 DEFAULT_DEINTERLACE_METHOD,
1448 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1450 filter_ops = gst_vaapi_filter_get_operations(NULL);
1455 * GstVaapiPostproc:format:
1457 * The forced output pixel format, expressed as a #GstVideoFormat.
1459 filter_op = find_filter_op(filter_ops, GST_VAAPI_FILTER_OP_FORMAT);
1461 g_object_class_install_property(object_class,
1462 PROP_FORMAT, filter_op->pspec);
1465 * GstVaapiPostproc:width:
1467 * The forced output width in pixels. If set to zero, the width is
1468 * calculated from the height if aspect ration is preserved, or
1469 * inherited from the sink caps width
1471 g_object_class_install_property
1474 g_param_spec_uint("width",
1476 "Forced output width",
1478 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1481 * GstVaapiPostproc:height:
1483 * The forced output height in pixels. If set to zero, the height
1484 * is calculated from the width if aspect ration is preserved, or
1485 * inherited from the sink caps height
1487 g_object_class_install_property
1490 g_param_spec_uint("height",
1492 "Forced output height",
1494 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1497 * GstVaapiPostproc:force-aspect-ratio:
1499 * When enabled, scaling respects video aspect ratio; when
1500 * disabled, the video is distorted to fit the width and height
1503 g_object_class_install_property
1505 PROP_FORCE_ASPECT_RATIO,
1506 g_param_spec_boolean("force-aspect-ratio",
1507 "Force aspect ratio",
1508 "When enabled, scaling will respect original aspect ratio",
1510 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1513 * GstVaapiPostproc:denoise:
1515 * The level of noise reduction to apply.
1517 filter_op = find_filter_op(filter_ops, GST_VAAPI_FILTER_OP_DENOISE);
1519 g_object_class_install_property(object_class,
1520 PROP_DENOISE, filter_op->pspec);
1523 * GstVaapiPostproc:sharpen:
1525 * The level of sharpening to apply for positive values, or the
1526 * level of blurring for negative values.
1528 filter_op = find_filter_op(filter_ops, GST_VAAPI_FILTER_OP_SHARPEN);
1530 g_object_class_install_property(object_class,
1531 PROP_SHARPEN, filter_op->pspec);
1534 * GstVaapiPostproc:hue:
1536 * The color hue, expressed as a float value. Range is -180.0 to
1537 * 180.0. Default value is 0.0 and represents no modification.
1539 filter_op = find_filter_op(filter_ops, GST_VAAPI_FILTER_OP_HUE);
1541 g_object_class_install_property(object_class,
1542 PROP_HUE, filter_op->pspec);
1545 * GstVaapiPostproc:saturation:
1547 * The color saturation, expressed as a float value. Range is 0.0
1548 * to 2.0. Default value is 1.0 and represents no modification.
1550 filter_op = find_filter_op(filter_ops, GST_VAAPI_FILTER_OP_SATURATION);
1552 g_object_class_install_property(object_class,
1553 PROP_SATURATION, filter_op->pspec);
1556 * GstVaapiPostproc:brightness:
1558 * The color brightness, expressed as a float value. Range is -1.0
1559 * to 1.0. Default value is 0.0 and represents no modification.
1561 filter_op = find_filter_op(filter_ops, GST_VAAPI_FILTER_OP_BRIGHTNESS);
1563 g_object_class_install_property(object_class,
1564 PROP_BRIGHTNESS, filter_op->pspec);
1567 * GstVaapiPostproc:contrast:
1569 * The color contrast, expressed as a float value. Range is 0.0 to
1570 * 2.0. Default value is 1.0 and represents no modification.
1572 filter_op = find_filter_op(filter_ops, GST_VAAPI_FILTER_OP_CONTRAST);
1574 g_object_class_install_property(object_class,
1575 PROP_CONTRAST, filter_op->pspec);
1577 g_ptr_array_unref(filter_ops);
1581 gst_vaapipostproc_init(GstVaapiPostproc *postproc)
1583 gst_vaapi_plugin_base_init(GST_VAAPI_PLUGIN_BASE(postproc), GST_CAT_DEFAULT);
1585 postproc->format = DEFAULT_FORMAT;
1586 postproc->deinterlace_mode = DEFAULT_DEINTERLACE_MODE;
1587 postproc->deinterlace_method = DEFAULT_DEINTERLACE_METHOD;
1588 postproc->field_duration = GST_CLOCK_TIME_NONE;
1589 postproc->keep_aspect = TRUE;
1591 gst_video_info_init(&postproc->sinkpad_info);
1592 gst_video_info_init(&postproc->srcpad_info);
1593 gst_video_info_init(&postproc->filter_pool_info);