2 * gstvaapipostproc.c - VA-API video postprocessing
4 * Copyright (C) 2012-2013 Intel Corporation
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either version 2.1
9 * of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free
18 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
23 * SECTION:gstvaapipostproc
24 * @short_description: A video postprocessing filter
26 * vaapipostproc consists in various postprocessing algorithms to be
27 * applied to VA surfaces. So far, only basic bob deinterlacing is
31 #include "gst/vaapi/sysdeps.h"
32 #include <gst/video/video.h>
33 #include <gst/video/videocontext.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 GST_VAAPI_SURFACE_CAPS ", "
52 GST_CAPS_INTERLACED_MODES "; "
53 #if GST_CHECK_VERSION(1,0,0)
54 GST_VIDEO_CAPS_MAKE(GST_VIDEO_FORMATS_ALL) ", "
57 "width = " GST_VIDEO_SIZE_RANGE ", "
58 "height = " GST_VIDEO_SIZE_RANGE ", "
59 "framerate = " GST_VIDEO_FPS_RANGE ", "
61 GST_CAPS_INTERLACED_MODES;
63 static const char gst_vaapipostproc_src_caps_str[] =
64 GST_VAAPI_SURFACE_CAPS ", "
65 GST_CAPS_INTERLACED_FALSE;
67 static GstStaticPadTemplate gst_vaapipostproc_sink_factory =
68 GST_STATIC_PAD_TEMPLATE(
72 GST_STATIC_CAPS(gst_vaapipostproc_sink_caps_str));
74 static GstStaticPadTemplate gst_vaapipostproc_src_factory =
75 GST_STATIC_PAD_TEMPLATE(
79 GST_STATIC_CAPS(gst_vaapipostproc_src_caps_str));
81 /* GstImplementsInterface interface */
82 #if !GST_CHECK_VERSION(1,0,0)
84 gst_vaapipostproc_implements_interface_supported(
85 GstImplementsInterface *iface,
89 return (type == GST_TYPE_VIDEO_CONTEXT);
93 gst_vaapipostproc_implements_iface_init(GstImplementsInterfaceClass *iface)
95 iface->supported = gst_vaapipostproc_implements_interface_supported;
99 /* GstVideoContext interface */
101 gst_vaapipostproc_set_video_context(
102 GstVideoContext *context,
107 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(context);
109 gst_vaapi_set_display(type, value, &postproc->display);
111 if (postproc->uploader)
112 gst_vaapi_uploader_ensure_display(postproc->uploader, postproc->display);
116 gst_video_context_interface_init(GstVideoContextInterface *iface)
118 iface->set_context = gst_vaapipostproc_set_video_context;
121 #define GstVideoContextClass GstVideoContextInterface
122 G_DEFINE_TYPE_WITH_CODE(
125 GST_TYPE_BASE_TRANSFORM,
126 #if !GST_CHECK_VERSION(1,0,0)
127 G_IMPLEMENT_INTERFACE(GST_TYPE_IMPLEMENTS_INTERFACE,
128 gst_vaapipostproc_implements_iface_init);
130 G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_CONTEXT,
131 gst_video_context_interface_init))
139 PROP_FORCE_ASPECT_RATIO,
140 PROP_DEINTERLACE_MODE,
141 PROP_DEINTERLACE_METHOD,
144 #define DEFAULT_FORMAT GST_VIDEO_FORMAT_ENCODED
145 #define DEFAULT_DEINTERLACE_MODE GST_VAAPI_DEINTERLACE_MODE_AUTO
146 #define DEFAULT_DEINTERLACE_METHOD GST_VAAPI_DEINTERLACE_METHOD_BOB
148 #define GST_VAAPI_TYPE_DEINTERLACE_MODE \
149 gst_vaapi_deinterlace_mode_get_type()
152 gst_vaapi_deinterlace_mode_get_type(void)
154 static GType deinterlace_mode_type = 0;
156 static const GEnumValue mode_types[] = {
157 { GST_VAAPI_DEINTERLACE_MODE_AUTO,
158 "Auto detection", "auto" },
159 { GST_VAAPI_DEINTERLACE_MODE_INTERLACED,
160 "Force deinterlacing", "interlaced" },
161 { GST_VAAPI_DEINTERLACE_MODE_DISABLED,
162 "Never deinterlace", "disabled" },
166 if (!deinterlace_mode_type) {
167 deinterlace_mode_type =
168 g_enum_register_static("GstVaapiDeinterlaceMode", mode_types);
170 return deinterlace_mode_type;
173 static GstVaapiFilterOpInfo *
174 find_filter_op(GPtrArray *filter_ops, GstVaapiFilterOp op)
179 for (i = 0; i < filter_ops->len; i++) {
180 GstVaapiFilterOpInfo * const filter_op =
181 g_ptr_array_index(filter_ops, i);
182 if (filter_op->op == op)
189 static inline gboolean
190 gst_vaapipostproc_ensure_display(GstVaapiPostproc *postproc)
192 return gst_vaapi_ensure_display(postproc, GST_VAAPI_DISPLAY_TYPE_ANY,
197 gst_vaapipostproc_ensure_uploader(GstVaapiPostproc *postproc)
199 if (!gst_vaapipostproc_ensure_display(postproc))
202 if (!postproc->uploader) {
203 postproc->uploader = gst_vaapi_uploader_new(postproc->display);
204 if (!postproc->uploader)
208 if (!gst_vaapi_uploader_ensure_display(postproc->uploader,
215 gst_vaapipostproc_ensure_uploader_caps(GstVaapiPostproc *postproc)
217 #if !GST_CHECK_VERSION(1,0,0)
218 if (postproc->is_raw_yuv && !gst_vaapi_uploader_ensure_caps(
219 postproc->uploader, postproc->sinkpad_caps, NULL))
226 gst_vaapipostproc_ensure_filter(GstVaapiPostproc *postproc)
228 if (postproc->filter)
231 if (!gst_vaapipostproc_ensure_display(postproc))
234 postproc->filter = gst_vaapi_filter_new(postproc->display);
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_vaapipostproc_ensure_display(postproc))
261 if (!gst_vaapipostproc_ensure_uploader(postproc))
263 if (!gst_vaapipostproc_ensure_uploader_caps(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);
286 gst_vaapipostproc_destroy(GstVaapiPostproc *postproc)
288 #if GST_CHECK_VERSION(1,0,0)
289 g_clear_object(&postproc->sinkpad_buffer_pool);
291 g_clear_object(&postproc->uploader);
292 gst_vaapipostproc_destroy_filter(postproc);
293 gst_vaapi_display_replace(&postproc->display, NULL);
295 gst_caps_replace(&postproc->allowed_sinkpad_caps, NULL);
296 gst_caps_replace(&postproc->sinkpad_caps, NULL);
297 gst_caps_replace(&postproc->allowed_srcpad_caps, NULL);
298 gst_caps_replace(&postproc->srcpad_caps, NULL);
302 gst_vaapipostproc_start(GstBaseTransform *trans)
304 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
306 if (!gst_vaapipostproc_ensure_display(postproc))
312 gst_vaapipostproc_stop(GstBaseTransform *trans)
314 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
316 gst_vaapi_display_replace(&postproc->display, NULL);
321 is_interlaced_buffer(GstVaapiPostproc *postproc, GstBuffer *buf)
323 if (!(postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE))
326 switch (GST_VIDEO_INFO_INTERLACE_MODE(&postproc->sinkpad_info)) {
327 case GST_VIDEO_INTERLACE_MODE_MIXED:
328 #if GST_CHECK_VERSION(1,0,0)
329 if (!GST_BUFFER_FLAG_IS_SET(buf, GST_VIDEO_BUFFER_FLAG_INTERLACED))
332 if (GST_BUFFER_FLAG_IS_SET(buf, GST_VIDEO_BUFFER_PROGRESSIVE))
343 create_output_buffer(GstVaapiPostproc *postproc)
347 /* Create a raw VA video buffer without GstVaapiVideoMeta attached
348 to it yet, as this will be done next in the transform() hook */
349 outbuf = gst_vaapi_video_buffer_new_empty();
351 goto error_create_buffer;
353 #if !GST_CHECK_VERSION(1,0,0)
354 gst_buffer_set_caps(outbuf, postproc->srcpad_caps);
361 GST_ERROR("failed to create output video buffer");
367 append_output_buffer_metadata(GstBuffer *outbuf, GstBuffer *inbuf, guint flags)
369 gst_buffer_copy_into(outbuf, inbuf, flags |
370 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_META | GST_BUFFER_COPY_MEMORY,
374 static GstVaapiDeinterlaceMethod
375 get_next_deint_method(GstVaapiDeinterlaceMethod deint_method)
377 switch (deint_method) {
378 case GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED:
379 deint_method = GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE;
382 /* Default to basic "bob" for all others */
383 deint_method = GST_VAAPI_DEINTERLACE_METHOD_BOB;
390 set_best_deint_method(GstVaapiPostproc *postproc, guint flags,
391 GstVaapiDeinterlaceMethod *deint_method_ptr)
393 GstVaapiDeinterlaceMethod deint_method = postproc->deinterlace_method;
397 success = gst_vaapi_filter_set_deinterlacing(postproc->filter,
398 deint_method, flags);
399 if (success || deint_method == GST_VAAPI_DEINTERLACE_METHOD_BOB)
401 deint_method = get_next_deint_method(deint_method);
403 *deint_method_ptr = deint_method;
408 gst_vaapipostproc_process_vpp(GstBaseTransform *trans, GstBuffer *inbuf,
411 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
412 GstVaapiVideoMeta *inbuf_meta, *outbuf_meta;
413 GstVaapiSurface *inbuf_surface, *outbuf_surface;
414 GstVaapiFilterStatus status;
415 GstClockTime timestamp;
418 guint flags, deint_flags;
421 /* Validate filters */
422 if ((postproc->flags & GST_VAAPI_POSTPROC_FLAG_FORMAT) &&
423 !gst_vaapi_filter_set_format(postproc->filter, postproc->format))
424 return GST_FLOW_NOT_SUPPORTED;
426 inbuf_meta = gst_buffer_get_vaapi_video_meta(inbuf);
428 goto error_invalid_buffer;
429 inbuf_surface = gst_vaapi_video_meta_get_surface(inbuf_meta);
431 timestamp = GST_BUFFER_TIMESTAMP(inbuf);
432 tff = GST_BUFFER_FLAG_IS_SET(inbuf, GST_VIDEO_BUFFER_FLAG_TFF);
433 deint = is_interlaced_buffer(postproc, inbuf);
435 flags = gst_vaapi_video_meta_get_render_flags(inbuf_meta) &
436 ~(GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD|
437 GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD);
440 if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE) {
441 fieldbuf = create_output_buffer(postproc);
443 goto error_create_buffer;
445 outbuf_meta = gst_vaapi_video_meta_new_from_pool(postproc->filter_pool);
447 goto error_create_meta;
448 outbuf_surface = gst_vaapi_video_meta_get_surface(outbuf_meta);
451 GstVaapiDeinterlaceMethod deint_method;
452 deint_flags = (tff ? GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD : 0);
453 if (!set_best_deint_method(postproc, flags, &deint_method))
454 goto error_op_deinterlace;
455 if (deint_method != postproc->deinterlace_method) {
456 GST_DEBUG("unsupported deinterlace-method %u. Using %u instead",
457 postproc->deinterlace_method, deint_method);
458 postproc->deinterlace_method = deint_method;
462 status = gst_vaapi_filter_process(postproc->filter, inbuf_surface,
463 outbuf_surface, flags);
464 if (status != GST_VAAPI_FILTER_STATUS_SUCCESS)
465 goto error_process_vpp;
467 gst_buffer_set_vaapi_video_meta(fieldbuf, outbuf_meta);
468 gst_vaapi_video_meta_unref(outbuf_meta);
470 GST_BUFFER_TIMESTAMP(fieldbuf) = timestamp;
471 GST_BUFFER_DURATION(fieldbuf) = postproc->field_duration;
472 ret = gst_pad_push(trans->srcpad, fieldbuf);
473 if (ret != GST_FLOW_OK)
474 goto error_push_buffer;
479 outbuf_meta = gst_vaapi_video_meta_new_from_pool(postproc->filter_pool);
481 goto error_create_meta;
482 outbuf_surface = gst_vaapi_video_meta_get_surface(outbuf_meta);
485 deint_flags = (tff ? 0 : GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD);
486 if (!gst_vaapi_filter_set_deinterlacing(postproc->filter,
487 postproc->deinterlace_method, deint_flags))
488 goto error_op_deinterlace;
491 status = gst_vaapi_filter_process(postproc->filter, inbuf_surface,
492 outbuf_surface, flags);
493 if (status != GST_VAAPI_FILTER_STATUS_SUCCESS)
494 goto error_process_vpp;
496 if (!(postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE))
497 gst_buffer_copy_into(outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
499 GST_BUFFER_TIMESTAMP(outbuf) = timestamp + postproc->field_duration;
500 GST_BUFFER_DURATION(outbuf) = postproc->field_duration;
502 gst_buffer_set_vaapi_video_meta(outbuf, outbuf_meta);
503 gst_vaapi_video_meta_unref(outbuf_meta);
507 error_invalid_buffer:
509 GST_ERROR("failed to validate source buffer");
510 return GST_FLOW_ERROR;
514 GST_ERROR("failed to create output buffer");
515 return GST_FLOW_ERROR;
519 GST_ERROR("failed to create new output buffer meta");
520 gst_buffer_replace(&fieldbuf, NULL);
521 gst_vaapi_video_meta_unref(outbuf_meta);
522 return GST_FLOW_ERROR;
524 error_op_deinterlace:
526 GST_ERROR("failed to apply deinterlacing filter");
527 gst_buffer_replace(&fieldbuf, NULL);
528 gst_vaapi_video_meta_unref(outbuf_meta);
529 return GST_FLOW_NOT_SUPPORTED;
533 GST_ERROR("failed to apply VPP filters (error %d)", status);
534 gst_buffer_replace(&fieldbuf, NULL);
535 gst_vaapi_video_meta_unref(outbuf_meta);
536 return GST_FLOW_ERROR;
540 if (ret != GST_FLOW_FLUSHING)
541 GST_ERROR("failed to push output buffer to video sink");
542 return GST_FLOW_ERROR;
547 gst_vaapipostproc_process(GstBaseTransform *trans, GstBuffer *inbuf,
550 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
551 GstVaapiVideoMeta *meta;
552 GstClockTime timestamp;
555 guint fieldbuf_flags, outbuf_flags, flags;
558 meta = gst_buffer_get_vaapi_video_meta(inbuf);
560 goto error_invalid_buffer;
562 timestamp = GST_BUFFER_TIMESTAMP(inbuf);
563 tff = GST_BUFFER_FLAG_IS_SET(inbuf, GST_VIDEO_BUFFER_FLAG_TFF);
564 deint = is_interlaced_buffer(postproc, inbuf);
566 flags = gst_vaapi_video_meta_get_render_flags(meta) &
567 ~(GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD|
568 GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD);
571 fieldbuf = create_output_buffer(postproc);
573 goto error_create_buffer;
574 append_output_buffer_metadata(fieldbuf, inbuf, 0);
576 meta = gst_buffer_get_vaapi_video_meta(fieldbuf);
577 fieldbuf_flags = flags;
578 fieldbuf_flags |= deint ? (
580 GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD :
581 GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD) :
582 GST_VAAPI_PICTURE_STRUCTURE_FRAME;
583 gst_vaapi_video_meta_set_render_flags(meta, fieldbuf_flags);
585 GST_BUFFER_TIMESTAMP(fieldbuf) = timestamp;
586 GST_BUFFER_DURATION(fieldbuf) = postproc->field_duration;
587 ret = gst_pad_push(trans->srcpad, fieldbuf);
588 if (ret != GST_FLOW_OK)
589 goto error_push_buffer;
592 append_output_buffer_metadata(outbuf, inbuf, 0);
594 meta = gst_buffer_get_vaapi_video_meta(outbuf);
595 outbuf_flags = flags;
596 outbuf_flags |= deint ? (
598 GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD :
599 GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD) :
600 GST_VAAPI_PICTURE_STRUCTURE_FRAME;
601 gst_vaapi_video_meta_set_render_flags(meta, outbuf_flags);
603 GST_BUFFER_TIMESTAMP(outbuf) = timestamp + postproc->field_duration;
604 GST_BUFFER_DURATION(outbuf) = postproc->field_duration;
608 error_invalid_buffer:
610 GST_ERROR("failed to validate source buffer");
611 return GST_FLOW_ERROR;
615 GST_ERROR("failed to create output buffer");
620 if (ret != GST_FLOW_FLUSHING)
621 GST_ERROR("failed to push output buffer to video sink");
627 gst_vaapipostproc_passthrough(GstBaseTransform *trans, GstBuffer *inbuf,
630 GstVaapiVideoMeta *meta;
632 /* No video processing needed, simply copy buffer metadata */
633 meta = gst_buffer_get_vaapi_video_meta(inbuf);
635 goto error_invalid_buffer;
637 append_output_buffer_metadata(outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS);
641 error_invalid_buffer:
643 GST_ERROR("failed to validate source buffer");
644 return GST_FLOW_ERROR;
649 is_deinterlace_enabled(GstVaapiPostproc *postproc, GstVideoInfo *vip)
651 gboolean deinterlace;
653 switch (postproc->deinterlace_mode) {
654 case GST_VAAPI_DEINTERLACE_MODE_AUTO:
655 deinterlace = GST_VIDEO_INFO_IS_INTERLACED(vip);
657 case GST_VAAPI_DEINTERLACE_MODE_INTERLACED:
668 video_info_changed(GstVideoInfo *old_vip, GstVideoInfo *new_vip)
670 if (GST_VIDEO_INFO_FORMAT(old_vip) != GST_VIDEO_INFO_FORMAT(new_vip))
672 if (GST_VIDEO_INFO_INTERLACE_MODE(old_vip) !=
673 GST_VIDEO_INFO_INTERLACE_MODE(new_vip))
675 if (GST_VIDEO_INFO_WIDTH(old_vip) != GST_VIDEO_INFO_WIDTH(new_vip))
677 if (GST_VIDEO_INFO_HEIGHT(old_vip) != GST_VIDEO_INFO_HEIGHT(new_vip))
683 gst_vaapipostproc_update_sink_caps(GstVaapiPostproc *postproc, GstCaps *caps,
684 gboolean *caps_changed_ptr)
687 gboolean deinterlace;
689 if (!gst_video_info_from_caps(&vi, caps))
692 if (video_info_changed(&vi, &postproc->sinkpad_info))
693 postproc->sinkpad_info = vi, *caps_changed_ptr = TRUE;
695 deinterlace = is_deinterlace_enabled(postproc, &vi);
697 postproc->flags |= GST_VAAPI_POSTPROC_FLAG_DEINTERLACE;
698 postproc->field_duration = gst_util_uint64_scale(
699 GST_SECOND, GST_VIDEO_INFO_FPS_D(&vi),
700 (1 + deinterlace) * GST_VIDEO_INFO_FPS_N(&vi));
702 postproc->is_raw_yuv = GST_VIDEO_INFO_IS_YUV(&vi);
703 #if !GST_CHECK_VERSION(1,0,0)
704 if (postproc->is_raw_yuv) {
705 /* Ensure the uploader is set up for upstream allocated buffers */
706 GstVaapiUploader * const uploader = postproc->uploader;
707 if (!gst_vaapi_uploader_ensure_display(uploader, postproc->display))
709 if (!gst_vaapi_uploader_ensure_caps(uploader, caps, NULL))
717 gst_vaapipostproc_update_src_caps(GstVaapiPostproc *postproc, GstCaps *caps,
718 gboolean *caps_changed_ptr)
722 if (!gst_video_info_from_caps(&vi, caps))
725 if (video_info_changed(&vi, &postproc->srcpad_info))
726 postproc->srcpad_info = vi, *caps_changed_ptr = TRUE;
728 if (postproc->format != GST_VIDEO_INFO_FORMAT(&postproc->sinkpad_info))
729 postproc->flags |= GST_VAAPI_POSTPROC_FLAG_FORMAT;
731 if ((postproc->width || postproc->height) &&
732 postproc->width != GST_VIDEO_INFO_WIDTH(&postproc->sinkpad_info) &&
733 postproc->height != GST_VIDEO_INFO_HEIGHT(&postproc->sinkpad_info))
734 postproc->flags |= GST_VAAPI_POSTPROC_FLAG_SIZE;
739 ensure_allowed_sinkpad_caps(GstVaapiPostproc *postproc)
741 GstCaps *out_caps, *yuv_caps;
743 if (postproc->allowed_sinkpad_caps)
747 out_caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS ", "
748 GST_CAPS_INTERLACED_MODES);
750 GST_ERROR("failed to create VA sink caps");
754 /* Append YUV caps */
755 if (gst_vaapipostproc_ensure_uploader(postproc)) {
756 yuv_caps = gst_vaapi_uploader_get_caps(postproc->uploader);
758 gst_caps_append(out_caps, gst_caps_ref(yuv_caps));
760 GST_WARNING("failed to create YUV sink caps");
762 postproc->allowed_sinkpad_caps = out_caps;
764 /* XXX: append VA/VPP filters */
768 /* Build list of supported formats */
770 build_format_list_value(GArray *formats, GValue *out_value)
772 GValue v_format = { 0, };
774 #if GST_CHECK_VERSION(1,0,0)
777 g_value_init(out_value, GST_TYPE_LIST);
779 g_value_init(&v_format, G_TYPE_STRING);
780 g_value_set_string(&v_format, "encoded");
781 gst_value_list_append_value(out_value, &v_format);
783 for (i = 0; i < formats->len; i++) {
784 GstVideoFormat const format =
785 g_array_index(formats, GstVideoFormat, i);
787 str = gst_vaapi_video_format_to_string(format);
790 g_value_set_string(&v_format, str);
791 gst_value_list_append_value(out_value, &v_format);
796 g_value_init(out_value, GST_TYPE_LIST);
797 g_value_init(&v_format, GST_TYPE_FOURCC);
798 for (i = 0; i < formats->len; i++) {
799 GstVideoFormat const format =
800 g_array_index(formats, GstVideoFormat, i);
802 fourcc = gst_video_format_to_fourcc(format);
805 gst_value_set_fourcc(&v_format, fourcc);
806 gst_value_list_append_value(out_value, &v_format);
810 g_value_unset(&v_format);
814 /* Fixup output caps so that to reflect the supported set of pixel formats */
816 expand_allowed_srcpad_caps(GstVaapiPostproc *postproc, GstCaps *caps)
818 GValue value = { 0, };
819 guint i, num_structures;
822 had_filter = postproc->filter != NULL;
823 if (!had_filter && !gst_vaapipostproc_ensure_filter(postproc))
825 if (!gst_vaapipostproc_ensure_filter_caps(postproc))
828 /* Reset "format" field for each structure */
829 if (!build_format_list_value(postproc->filter_formats, &value))
832 num_structures = gst_caps_get_size(caps);
833 for (i = 0; i < num_structures; i++) {
834 GstStructure * const structure = gst_caps_get_structure(caps, i);
837 gst_structure_set_value(structure, "format", &value);
839 g_value_unset(&value);
843 gst_vaapipostproc_destroy_filter(postproc);
848 ensure_allowed_srcpad_caps(GstVaapiPostproc *postproc)
852 if (postproc->allowed_srcpad_caps)
855 /* Create initial caps from pad template */
856 out_caps = gst_caps_from_string(gst_vaapipostproc_src_caps_str);
858 GST_ERROR("failed to create VA src caps");
862 postproc->allowed_srcpad_caps =
863 expand_allowed_srcpad_caps(postproc, out_caps);
864 return postproc->allowed_srcpad_caps != NULL;
868 find_best_size(GstVaapiPostproc *postproc, GstVideoInfo *vip,
869 guint *width_ptr, guint *height_ptr)
873 width = GST_VIDEO_INFO_WIDTH(vip);
874 height = GST_VIDEO_INFO_HEIGHT(vip);
875 if (postproc->width && postproc->height) {
876 width = postproc->width;
877 height = postproc->height;
879 else if (postproc->keep_aspect) {
880 const gdouble ratio = (gdouble)width / height;
881 if (postproc->width) {
882 width = postproc->width;
883 height = postproc->width / ratio;
885 else if (postproc->height) {
886 height = postproc->height;
887 width = postproc->height * ratio;
890 else if (postproc->width)
891 width = postproc->width;
892 else if (postproc->height)
893 height = postproc->height;
896 *height_ptr = height;
900 gst_vaapipostproc_transform_caps_impl(GstBaseTransform *trans,
901 GstPadDirection direction, GstCaps *caps)
903 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
905 GstVideoFormat format;
909 /* Generate the sink pad caps, that could be fixated afterwards */
910 if (direction == GST_PAD_SRC) {
911 if (!ensure_allowed_sinkpad_caps(postproc))
913 return gst_caps_ref(postproc->allowed_sinkpad_caps);
916 /* Generate complete set of src pad caps if non-fixated sink pad
918 if (!gst_caps_is_fixed(caps)) {
919 if (!ensure_allowed_srcpad_caps(postproc))
921 return gst_caps_ref(postproc->allowed_srcpad_caps);
924 /* Generate the expected src pad caps, from the current fixated
926 if (!gst_video_info_from_caps(&vi, caps))
929 // Set double framerate in interlaced mode
930 if (is_deinterlace_enabled(postproc, &vi)) {
931 gint fps_n = GST_VIDEO_INFO_FPS_N(&vi);
932 gint fps_d = GST_VIDEO_INFO_FPS_D(&vi);
933 if (!gst_util_fraction_multiply(fps_n, fps_d, 2, 1, &fps_n, &fps_d))
935 GST_VIDEO_INFO_FPS_N(&vi) = fps_n;
936 GST_VIDEO_INFO_FPS_D(&vi) = fps_d;
939 // Signal the other pad that we only generate progressive frames
940 GST_VIDEO_INFO_INTERLACE_MODE(&vi) = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
942 // Update size from user-specified parameters
943 format = GST_VIDEO_FORMAT_ENCODED;
944 find_best_size(postproc, &vi, &width, &height);
945 gst_video_info_set_format(&vi, format, width, height);
947 /* XXX: gst_video_info_to_caps() from GStreamer 0.10 does not
948 reconstruct suitable caps for "encoded" video formats */
949 out_caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS_NAME);
953 gst_caps_set_simple(out_caps,
954 "type", G_TYPE_STRING, "vaapi",
955 "opengl", G_TYPE_BOOLEAN, USE_GLX,
956 "width", G_TYPE_INT, GST_VIDEO_INFO_WIDTH(&vi),
957 "height", G_TYPE_INT, GST_VIDEO_INFO_HEIGHT(&vi),
958 "framerate", GST_TYPE_FRACTION, GST_VIDEO_INFO_FPS_N(&vi),
959 GST_VIDEO_INFO_FPS_D(&vi),
960 "pixel-aspect-ratio", GST_TYPE_FRACTION, GST_VIDEO_INFO_PAR_N(&vi),
961 GST_VIDEO_INFO_PAR_D(&vi),
964 gst_caps_set_interlaced(out_caps, &vi);
968 #if GST_CHECK_VERSION(1,0,0)
970 gst_vaapipostproc_transform_caps(GstBaseTransform *trans,
971 GstPadDirection direction, GstCaps *caps, GstCaps *filter)
975 caps = gst_vaapipostproc_transform_caps_impl(trans, direction, caps);
976 if (caps && filter) {
977 out_caps = gst_caps_intersect_full(caps, filter,
978 GST_CAPS_INTERSECT_FIRST);
979 gst_caps_unref(caps);
985 #define gst_vaapipostproc_transform_caps \
986 gst_vaapipostproc_transform_caps_impl
989 #if GST_CHECK_VERSION(1,0,0)
990 typedef gsize GstBaseTransformSizeType;
992 typedef guint GstBaseTransformSizeType;
996 gst_vaapipostproc_transform_size(GstBaseTransform *trans,
997 GstPadDirection direction, GstCaps *caps, GstBaseTransformSizeType size,
998 GstCaps *othercaps, GstBaseTransformSizeType *othersize)
1000 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
1002 if (direction == GST_PAD_SINK || !postproc->is_raw_yuv)
1010 get_source_buffer(GstVaapiPostproc *postproc, GstBuffer *inbuf)
1012 GstVaapiVideoMeta *meta;
1014 #if GST_CHECK_VERSION(1,0,0)
1015 GstVideoFrame src_frame, out_frame;
1018 meta = gst_buffer_get_vaapi_video_meta(inbuf);
1020 return gst_buffer_ref(inbuf);
1022 #if GST_CHECK_VERSION(1,0,0)
1023 if (!postproc->is_raw_yuv)
1024 goto error_invalid_buffer;
1026 if (!postproc->sinkpad_buffer_pool)
1029 if (!gst_buffer_pool_set_active(postproc->sinkpad_buffer_pool, TRUE))
1030 goto error_active_pool;
1033 if (gst_buffer_pool_acquire_buffer(postproc->sinkpad_buffer_pool,
1034 &outbuf, NULL) != GST_FLOW_OK)
1035 goto error_create_buffer;
1037 if (!gst_video_frame_map(&src_frame, &postproc->sinkpad_info, inbuf,
1039 goto error_map_src_buffer;
1041 if (!gst_video_frame_map(&out_frame, &postproc->sinkpad_info, outbuf,
1043 goto error_map_dst_buffer;
1045 if (!gst_video_frame_copy(&out_frame, &src_frame))
1046 goto error_copy_buffer;
1048 gst_video_frame_unmap(&out_frame);
1049 gst_video_frame_unmap(&src_frame);
1050 gst_buffer_copy_into(outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
1054 error_invalid_buffer:
1056 GST_ERROR("failed to validate source buffer");
1061 GST_ERROR("no buffer pool was negotiated");
1066 GST_ERROR("failed to activate buffer pool");
1069 error_map_dst_buffer:
1071 gst_video_frame_unmap(&src_frame);
1074 error_map_src_buffer:
1076 GST_ERROR("failed to map buffer");
1077 gst_buffer_unref(outbuf);
1081 outbuf = gst_vaapi_uploader_get_buffer(postproc->uploader);
1083 goto error_create_buffer;
1084 if (!gst_vaapi_uploader_process(postproc->uploader, inbuf, outbuf))
1085 goto error_copy_buffer;
1087 gst_buffer_copy_metadata(outbuf, inbuf,
1088 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
1093 error_create_buffer:
1095 GST_ERROR("failed to create buffer");
1100 GST_ERROR("failed to upload buffer to VA surface");
1101 #if GST_CHECK_VERSION(1,0,0)
1102 gst_video_frame_unmap(&out_frame);
1103 gst_video_frame_unmap(&src_frame);
1105 gst_buffer_unref(outbuf);
1110 static GstFlowReturn
1111 gst_vaapipostproc_transform(GstBaseTransform *trans, GstBuffer *inbuf,
1114 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
1118 buf = get_source_buffer(postproc, inbuf);
1120 return GST_FLOW_ERROR;
1122 ret = GST_FLOW_NOT_SUPPORTED;
1123 if (postproc->flags) {
1124 /* Use VA/VPP extensions to process this frame */
1125 if (postproc->use_vpp &&
1126 postproc->flags != GST_VAAPI_POSTPROC_FLAG_DEINTERLACE) {
1127 ret = gst_vaapipostproc_process_vpp(trans, buf, outbuf);
1128 if (ret != GST_FLOW_NOT_SUPPORTED)
1130 GST_WARNING("unsupported VPP filters. Disabling");
1131 postproc->use_vpp = FALSE;
1134 /* Only append picture structure meta data (top/bottom field) */
1135 if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE) {
1136 ret = gst_vaapipostproc_process(trans, buf, outbuf);
1137 if (ret != GST_FLOW_NOT_SUPPORTED)
1142 /* Fallback: passthrough to the downstream element as is */
1143 ret = gst_vaapipostproc_passthrough(trans, buf, outbuf);
1146 gst_buffer_unref(buf);
1150 static GstFlowReturn
1151 gst_vaapipostproc_prepare_output_buffer(GstBaseTransform *trans,
1153 #if !GST_CHECK_VERSION(1,0,0)
1154 gint size, GstCaps *caps,
1156 GstBuffer **outbuf_ptr)
1158 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
1160 *outbuf_ptr = create_output_buffer(postproc);
1161 return *outbuf_ptr ? GST_FLOW_OK : GST_FLOW_ERROR;
1165 ensure_sinkpad_buffer_pool(GstVaapiPostproc *postproc, GstCaps *caps)
1167 #if GST_CHECK_VERSION(1,0,0)
1168 GstBufferPool *pool;
1170 GstStructure *config;
1174 if (!gst_vaapipostproc_ensure_display(postproc))
1177 if (postproc->sinkpad_buffer_pool) {
1178 config = gst_buffer_pool_get_config(postproc->sinkpad_buffer_pool);
1179 gst_buffer_pool_config_get_params(config, &pool_caps, NULL, NULL, NULL);
1180 need_pool = !gst_caps_is_equal(caps, pool_caps);
1181 gst_structure_free(config);
1184 g_clear_object(&postproc->sinkpad_buffer_pool);
1185 postproc->sinkpad_buffer_size = 0;
1188 pool = gst_vaapi_video_buffer_pool_new(postproc->display);
1190 goto error_create_pool;
1192 gst_video_info_init(&vi);
1193 gst_video_info_from_caps(&vi, caps);
1194 if (GST_VIDEO_INFO_FORMAT(&vi) == GST_VIDEO_FORMAT_ENCODED) {
1195 GST_DEBUG("assume sink pad buffer pool format is NV12");
1196 gst_video_info_set_format(&vi, GST_VIDEO_FORMAT_NV12,
1197 GST_VIDEO_INFO_WIDTH(&vi), GST_VIDEO_INFO_HEIGHT(&vi));
1199 postproc->sinkpad_buffer_size = vi.size;
1201 config = gst_buffer_pool_get_config(pool);
1202 gst_buffer_pool_config_set_params(config, caps,
1203 postproc->sinkpad_buffer_size, 0, 0);
1204 gst_buffer_pool_config_add_option(config,
1205 GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META);
1206 gst_buffer_pool_config_add_option(config,
1207 GST_BUFFER_POOL_OPTION_VIDEO_META);
1208 if (!gst_buffer_pool_set_config(pool, config))
1209 goto error_pool_config;
1210 postproc->sinkpad_buffer_pool = pool;
1216 GST_ERROR("failed to create buffer pool");
1221 GST_ERROR("failed to reset buffer pool config");
1222 gst_object_unref(pool);
1231 ensure_srcpad_buffer_pool(GstVaapiPostproc *postproc, GstCaps *caps)
1234 GstVaapiVideoPool *pool;
1236 gst_video_info_init(&vi);
1237 gst_video_info_from_caps(&vi, caps);
1238 gst_video_info_set_format(&vi, postproc->format,
1239 GST_VIDEO_INFO_WIDTH(&vi), GST_VIDEO_INFO_HEIGHT(&vi));
1241 if (!video_info_changed(&vi, &postproc->filter_pool_info))
1243 postproc->filter_pool_info = vi;
1245 pool = gst_vaapi_surface_pool_new(postproc->display,
1246 &postproc->filter_pool_info);
1250 gst_vaapi_video_pool_replace(&postproc->filter_pool, pool);
1251 gst_vaapi_video_pool_unref(pool);
1256 gst_vaapipostproc_set_caps(GstBaseTransform *trans, GstCaps *caps,
1259 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
1260 gboolean caps_changed = FALSE;
1262 if (!gst_vaapipostproc_update_sink_caps(postproc, caps, &caps_changed))
1264 if (!gst_vaapipostproc_update_src_caps(postproc, out_caps, &caps_changed))
1268 gst_vaapipostproc_destroy(postproc);
1269 gst_caps_replace(&postproc->sinkpad_caps, caps);
1270 gst_caps_replace(&postproc->srcpad_caps, out_caps);
1271 if (!gst_vaapipostproc_create(postproc))
1275 if (!ensure_sinkpad_buffer_pool(postproc, caps))
1277 if (!ensure_srcpad_buffer_pool(postproc, out_caps))
1283 gst_vaapipostproc_query(GstBaseTransform *trans, GstPadDirection direction,
1286 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
1288 GST_INFO_OBJECT(trans, "query type `%s'", GST_QUERY_TYPE_NAME(query));
1290 if (gst_vaapi_reply_to_query(query, postproc->display)) {
1291 GST_DEBUG("sharing display %p", postproc->display);
1295 return GST_BASE_TRANSFORM_CLASS(gst_vaapipostproc_parent_class)->query(
1296 trans, direction, query);
1299 #if GST_CHECK_VERSION(1,0,0)
1301 gst_vaapipostproc_propose_allocation(GstBaseTransform *trans,
1302 GstQuery *decide_query, GstQuery *query)
1304 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
1305 GstCaps *caps = NULL;
1308 /* Let vaapidecode allocate the video buffers */
1309 if (!postproc->is_raw_yuv)
1312 gst_query_parse_allocation(query, &caps, &need_pool);
1317 if (!ensure_sinkpad_buffer_pool(postproc, caps))
1319 gst_query_add_allocation_pool(query, postproc->sinkpad_buffer_pool,
1320 postproc->sinkpad_buffer_size, 0, 0);
1323 gst_query_add_allocation_meta(query,
1324 GST_VAAPI_VIDEO_META_API_TYPE, NULL);
1325 gst_query_add_allocation_meta(query,
1326 GST_VIDEO_META_API_TYPE, NULL);
1327 gst_query_add_allocation_meta(query,
1328 GST_VIDEO_CROP_META_API_TYPE, NULL);
1329 gst_query_add_allocation_meta(query,
1330 GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, NULL);
1336 GST_ERROR("no caps specified");
1343 gst_vaapipostproc_finalize(GObject *object)
1345 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(object);
1347 gst_vaapipostproc_destroy(postproc);
1349 G_OBJECT_CLASS(gst_vaapipostproc_parent_class)->finalize(object);
1353 gst_vaapipostproc_set_property(
1356 const GValue *value,
1360 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(object);
1364 postproc->format = g_value_get_enum(value);
1367 postproc->width = g_value_get_uint(value);
1370 postproc->height = g_value_get_uint(value);
1372 case PROP_FORCE_ASPECT_RATIO:
1373 postproc->keep_aspect = g_value_get_boolean(value);
1375 case PROP_DEINTERLACE_MODE:
1376 postproc->deinterlace_mode = g_value_get_enum(value);
1378 case PROP_DEINTERLACE_METHOD:
1379 postproc->deinterlace_method = g_value_get_enum(value);
1382 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
1388 gst_vaapipostproc_get_property(
1395 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(object);
1399 g_value_set_enum(value, postproc->format);
1402 g_value_set_uint(value, postproc->width);
1405 g_value_set_uint(value, postproc->height);
1407 case PROP_FORCE_ASPECT_RATIO:
1408 g_value_set_boolean(value, postproc->keep_aspect);
1410 case PROP_DEINTERLACE_MODE:
1411 g_value_set_enum(value, postproc->deinterlace_mode);
1413 case PROP_DEINTERLACE_METHOD:
1414 g_value_set_enum(value, postproc->deinterlace_method);
1417 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
1423 gst_vaapipostproc_class_init(GstVaapiPostprocClass *klass)
1425 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
1426 GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
1427 GstBaseTransformClass * const trans_class = GST_BASE_TRANSFORM_CLASS(klass);
1428 GstPadTemplate *pad_template;
1429 GPtrArray *filter_ops;
1430 GstVaapiFilterOpInfo *filter_op;
1432 GST_DEBUG_CATEGORY_INIT(gst_debug_vaapipostproc,
1433 GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
1435 object_class->finalize = gst_vaapipostproc_finalize;
1436 object_class->set_property = gst_vaapipostproc_set_property;
1437 object_class->get_property = gst_vaapipostproc_get_property;
1438 trans_class->start = gst_vaapipostproc_start;
1439 trans_class->stop = gst_vaapipostproc_stop;
1440 trans_class->transform_caps = gst_vaapipostproc_transform_caps;
1441 trans_class->transform_size = gst_vaapipostproc_transform_size;
1442 trans_class->transform = gst_vaapipostproc_transform;
1443 trans_class->set_caps = gst_vaapipostproc_set_caps;
1444 trans_class->query = gst_vaapipostproc_query;
1446 #if GST_CHECK_VERSION(1,0,0)
1447 trans_class->propose_allocation = gst_vaapipostproc_propose_allocation;
1450 trans_class->prepare_output_buffer =
1451 gst_vaapipostproc_prepare_output_buffer;
1453 gst_element_class_set_static_metadata(element_class,
1454 "VA-API video postprocessing",
1455 "Filter/Converter/Video",
1457 "Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
1460 pad_template = gst_static_pad_template_get(&gst_vaapipostproc_sink_factory);
1461 gst_element_class_add_pad_template(element_class, pad_template);
1464 pad_template = gst_static_pad_template_get(&gst_vaapipostproc_src_factory);
1465 gst_element_class_add_pad_template(element_class, pad_template);
1468 * GstVaapiPostproc:deinterlace-mode:
1470 * This selects whether the deinterlacing should always be applied or if
1471 * they should only be applied on content that has the "interlaced" flag
1474 g_object_class_install_property
1476 PROP_DEINTERLACE_MODE,
1477 g_param_spec_enum("deinterlace-mode",
1479 "Deinterlace mode to use",
1480 GST_VAAPI_TYPE_DEINTERLACE_MODE,
1481 DEFAULT_DEINTERLACE_MODE,
1482 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1485 * GstVaapiPostproc:deinterlace-method:
1487 * This selects the deinterlacing method to apply.
1489 g_object_class_install_property
1491 PROP_DEINTERLACE_METHOD,
1492 g_param_spec_enum("deinterlace-method",
1493 "Deinterlace method",
1494 "Deinterlace method to use",
1495 GST_VAAPI_TYPE_DEINTERLACE_METHOD,
1496 DEFAULT_DEINTERLACE_METHOD,
1497 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1499 filter_ops = gst_vaapi_filter_get_operations(NULL);
1504 * GstVaapiPostproc:format:
1506 * The forced output pixel format, expressed as a #GstVideoFormat.
1508 filter_op = find_filter_op(filter_ops, GST_VAAPI_FILTER_OP_FORMAT);
1510 g_object_class_install_property(object_class,
1511 PROP_FORMAT, filter_op->pspec);
1514 * GstVaapiPostproc:width:
1516 * The forced output width in pixels. If set to zero, the width is
1517 * calculated from the height if aspect ration is preserved, or
1518 * inherited from the sink caps width
1520 g_object_class_install_property
1523 g_param_spec_uint("width",
1525 "Forced output width",
1527 G_PARAM_READWRITE));
1530 * GstVaapiPostproc:height:
1532 * The forced output height in pixels. If set to zero, the height
1533 * is calculated from the width if aspect ration is preserved, or
1534 * inherited from the sink caps height
1536 g_object_class_install_property
1539 g_param_spec_uint("height",
1541 "Forced output height",
1543 G_PARAM_READWRITE));
1546 * GstVaapiPostproc:force-aspect-ratio:
1548 * When enabled, scaling respects video aspect ratio; when
1549 * disabled, the video is distorted to fit the width and height
1552 g_object_class_install_property
1554 PROP_FORCE_ASPECT_RATIO,
1555 g_param_spec_boolean("force-aspect-ratio",
1556 "Force aspect ratio",
1557 "When enabled, scaling will respect original aspect ratio",
1559 G_PARAM_READWRITE));
1561 g_ptr_array_unref(filter_ops);
1565 gst_vaapipostproc_init(GstVaapiPostproc *postproc)
1567 postproc->format = DEFAULT_FORMAT;
1568 postproc->deinterlace_mode = DEFAULT_DEINTERLACE_MODE;
1569 postproc->deinterlace_method = DEFAULT_DEINTERLACE_METHOD;
1570 postproc->field_duration = GST_CLOCK_TIME_NONE;
1571 postproc->keep_aspect = TRUE;
1573 gst_video_info_init(&postproc->sinkpad_info);
1574 gst_video_info_init(&postproc->srcpad_info);
1575 gst_video_info_init(&postproc->filter_pool_info);