2 * gstvaapipostproc.c - VA-API video postprocessing
4 * Copyright (C) 2012-2013 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 "gstvaapivideocontext.h"
38 #include "gstvaapivideobuffer.h"
39 #if GST_CHECK_VERSION(1,0,0)
40 #include "gstvaapivideobufferpool.h"
41 #include "gstvaapivideomemory.h"
44 #define GST_PLUGIN_NAME "vaapipostproc"
45 #define GST_PLUGIN_DESC "A video postprocessing filter"
47 GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapipostproc);
48 #define GST_CAT_DEFAULT gst_debug_vaapipostproc
50 /* Default templates */
51 static const char gst_vaapipostproc_sink_caps_str[] =
52 #if GST_CHECK_VERSION(1,1,0)
53 GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
54 GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, "{ ENCODED, NV12, I420, YV12 }") ", "
56 GST_VAAPI_SURFACE_CAPS ", "
58 GST_CAPS_INTERLACED_MODES "; "
59 #if GST_CHECK_VERSION(1,0,0)
60 GST_VIDEO_CAPS_MAKE(GST_VIDEO_FORMATS_ALL) ", "
63 "width = " GST_VIDEO_SIZE_RANGE ", "
64 "height = " GST_VIDEO_SIZE_RANGE ", "
65 "framerate = " GST_VIDEO_FPS_RANGE ", "
67 GST_CAPS_INTERLACED_MODES;
69 static const char gst_vaapipostproc_src_caps_str[] =
70 #if GST_CHECK_VERSION(1,1,0)
71 GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
72 GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, "{ ENCODED, NV12, I420, YV12 }") ", "
74 GST_VAAPI_SURFACE_CAPS ", "
76 GST_CAPS_INTERLACED_FALSE;
78 static GstStaticPadTemplate gst_vaapipostproc_sink_factory =
79 GST_STATIC_PAD_TEMPLATE(
83 GST_STATIC_CAPS(gst_vaapipostproc_sink_caps_str));
85 static GstStaticPadTemplate gst_vaapipostproc_src_factory =
86 GST_STATIC_PAD_TEMPLATE(
90 GST_STATIC_CAPS(gst_vaapipostproc_src_caps_str));
92 /* GstVideoContext interface */
93 #if !GST_CHECK_VERSION(1,1,0)
95 gst_vaapipostproc_set_video_context(
96 GstVideoContext *context,
101 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(context);
103 gst_vaapi_set_display(type, value, &GST_VAAPI_PLUGIN_BASE_DISPLAY(postproc));
105 if (postproc->uploader)
106 gst_vaapi_uploader_ensure_display(postproc->uploader, GST_VAAPI_PLUGIN_BASE_DISPLAY(postproc));
110 gst_video_context_interface_init(GstVideoContextInterface *iface)
112 iface->set_context = gst_vaapipostproc_set_video_context;
115 #define GstVideoContextClass GstVideoContextInterface
118 G_DEFINE_TYPE_WITH_CODE(
121 GST_TYPE_BASE_TRANSFORM,
122 GST_VAAPI_PLUGIN_BASE_INIT_INTERFACES
123 #if !GST_CHECK_VERSION(1,1,0)
124 G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_CONTEXT,
125 gst_video_context_interface_init)
135 PROP_FORCE_ASPECT_RATIO,
136 PROP_DEINTERLACE_MODE,
137 PROP_DEINTERLACE_METHOD,
142 #define DEFAULT_FORMAT GST_VIDEO_FORMAT_ENCODED
143 #define DEFAULT_DEINTERLACE_MODE GST_VAAPI_DEINTERLACE_MODE_AUTO
144 #define DEFAULT_DEINTERLACE_METHOD GST_VAAPI_DEINTERLACE_METHOD_BOB
146 #define GST_VAAPI_TYPE_DEINTERLACE_MODE \
147 gst_vaapi_deinterlace_mode_get_type()
150 gst_vaapi_deinterlace_mode_get_type(void)
152 static GType deinterlace_mode_type = 0;
154 static const GEnumValue mode_types[] = {
155 { GST_VAAPI_DEINTERLACE_MODE_AUTO,
156 "Auto detection", "auto" },
157 { GST_VAAPI_DEINTERLACE_MODE_INTERLACED,
158 "Force deinterlacing", "interlaced" },
159 { GST_VAAPI_DEINTERLACE_MODE_DISABLED,
160 "Never deinterlace", "disabled" },
164 if (!deinterlace_mode_type) {
165 deinterlace_mode_type =
166 g_enum_register_static("GstVaapiDeinterlaceMode", mode_types);
168 return deinterlace_mode_type;
172 ds_reset(GstVaapiDeinterlaceState *ds)
176 for (i = 0; i < G_N_ELEMENTS(ds->buffers); i++)
177 gst_buffer_replace(&ds->buffers[i], NULL);
178 ds->buffers_index = 0;
179 ds->num_surfaces = 0;
185 ds_add_buffer(GstVaapiDeinterlaceState *ds, GstBuffer *buf)
187 gst_buffer_replace(&ds->buffers[ds->buffers_index], buf);
188 ds->buffers_index = (ds->buffers_index + 1) % G_N_ELEMENTS(ds->buffers);
191 static inline GstBuffer *
192 ds_get_buffer(GstVaapiDeinterlaceState *ds, guint index)
194 /* Note: the index increases towards older buffers.
195 i.e. buffer at index 0 means the immediately preceding buffer
196 in the history, buffer at index 1 means the one preceding the
197 surface at index 0, etc. */
198 const guint n = ds->buffers_index + G_N_ELEMENTS(ds->buffers) - index - 1;
199 return ds->buffers[n % G_N_ELEMENTS(ds->buffers)];
203 ds_set_surfaces(GstVaapiDeinterlaceState *ds)
205 GstVaapiVideoMeta *meta;
208 ds->num_surfaces = 0;
209 for (i = 0; i < G_N_ELEMENTS(ds->buffers); i++) {
210 GstBuffer * const buf = ds_get_buffer(ds, i);
214 meta = gst_buffer_get_vaapi_video_meta(buf);
215 ds->surfaces[ds->num_surfaces++] =
216 gst_vaapi_video_meta_get_surface(meta);
220 static GstVaapiFilterOpInfo *
221 find_filter_op(GPtrArray *filter_ops, GstVaapiFilterOp op)
226 for (i = 0; i < filter_ops->len; i++) {
227 GstVaapiFilterOpInfo * const filter_op =
228 g_ptr_array_index(filter_ops, i);
229 if (filter_op->op == op)
236 #if GST_CHECK_VERSION(1,1,0)
238 gst_vaapipostproc_set_context(GstElement *element, GstContext *context)
240 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(element);
241 GstVaapiDisplay *display = NULL;
243 if (gst_vaapi_video_context_get_display(context, &display)) {
244 GST_INFO_OBJECT(element, "set display %p", display);
245 GST_VAAPI_PLUGIN_BASE_DISPLAY_REPLACE(postproc, display);
246 gst_vaapi_display_unref(display);
251 static inline gboolean
252 gst_vaapipostproc_ensure_display(GstVaapiPostproc *postproc)
254 return gst_vaapi_plugin_base_ensure_display(GST_VAAPI_PLUGIN_BASE(postproc));
258 gst_vaapipostproc_ensure_uploader(GstVaapiPostproc *postproc)
260 if (!gst_vaapipostproc_ensure_display(postproc))
263 if (!postproc->uploader) {
264 postproc->uploader = gst_vaapi_uploader_new(
265 GST_VAAPI_PLUGIN_BASE_DISPLAY(postproc));
266 if (!postproc->uploader)
270 if (!gst_vaapi_uploader_ensure_display(postproc->uploader,
271 GST_VAAPI_PLUGIN_BASE_DISPLAY(postproc)))
277 gst_vaapipostproc_ensure_uploader_caps(GstVaapiPostproc *postproc)
279 #if !GST_CHECK_VERSION(1,0,0)
280 if (postproc->is_raw_yuv && !gst_vaapi_uploader_ensure_caps(
281 postproc->uploader, postproc->sinkpad_caps, NULL))
288 gst_vaapipostproc_ensure_filter(GstVaapiPostproc *postproc)
290 if (postproc->filter)
293 if (!gst_vaapipostproc_ensure_display(postproc))
296 postproc->filter = gst_vaapi_filter_new(
297 GST_VAAPI_PLUGIN_BASE_DISPLAY(postproc));
298 if (!postproc->filter)
304 gst_vaapipostproc_ensure_filter_caps(GstVaapiPostproc *postproc)
306 if (!gst_vaapipostproc_ensure_filter(postproc))
309 postproc->filter_ops = gst_vaapi_filter_get_operations(postproc->filter);
310 if (!postproc->filter_ops)
313 postproc->filter_formats = gst_vaapi_filter_get_formats(postproc->filter);
314 if (!postproc->filter_formats)
320 gst_vaapipostproc_create(GstVaapiPostproc *postproc)
322 if (!gst_vaapi_plugin_base_open(GST_VAAPI_PLUGIN_BASE(postproc)))
324 if (!gst_vaapipostproc_ensure_display(postproc))
326 if (!gst_vaapipostproc_ensure_uploader(postproc))
328 if (!gst_vaapipostproc_ensure_uploader_caps(postproc))
330 if (gst_vaapipostproc_ensure_filter(postproc))
331 postproc->use_vpp = TRUE;
336 gst_vaapipostproc_destroy_filter(GstVaapiPostproc *postproc)
338 if (postproc->filter_formats) {
339 g_array_unref(postproc->filter_formats);
340 postproc->filter_formats = NULL;
343 if (postproc->filter_ops) {
344 g_ptr_array_unref(postproc->filter_ops);
345 postproc->filter_ops = NULL;
347 gst_vaapi_filter_replace(&postproc->filter, NULL);
348 gst_vaapi_video_pool_replace(&postproc->filter_pool, NULL);
352 gst_vaapipostproc_destroy(GstVaapiPostproc *postproc)
354 ds_reset(&postproc->deinterlace_state);
355 #if GST_CHECK_VERSION(1,0,0)
356 g_clear_object(&postproc->sinkpad_buffer_pool);
358 g_clear_object(&postproc->uploader);
359 gst_vaapipostproc_destroy_filter(postproc);
361 gst_caps_replace(&postproc->allowed_sinkpad_caps, NULL);
362 gst_caps_replace(&postproc->sinkpad_caps, NULL);
363 gst_caps_replace(&postproc->allowed_srcpad_caps, NULL);
364 gst_caps_replace(&postproc->srcpad_caps, NULL);
365 gst_vaapi_plugin_base_close(GST_VAAPI_PLUGIN_BASE(postproc));
369 gst_vaapipostproc_start(GstBaseTransform *trans)
371 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
373 ds_reset(&postproc->deinterlace_state);
374 if (!gst_vaapi_plugin_base_open(GST_VAAPI_PLUGIN_BASE(postproc)))
376 if (!gst_vaapipostproc_ensure_display(postproc))
382 gst_vaapipostproc_stop(GstBaseTransform *trans)
384 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
386 ds_reset(&postproc->deinterlace_state);
387 gst_vaapi_plugin_base_close(GST_VAAPI_PLUGIN_BASE(postproc));
392 is_interlaced_buffer(GstVaapiPostproc *postproc, GstBuffer *buf)
394 if (!(postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE))
397 switch (GST_VIDEO_INFO_INTERLACE_MODE(&postproc->sinkpad_info)) {
398 case GST_VIDEO_INTERLACE_MODE_MIXED:
399 #if GST_CHECK_VERSION(1,0,0)
400 if (!GST_BUFFER_FLAG_IS_SET(buf, GST_VIDEO_BUFFER_FLAG_INTERLACED))
403 if (GST_BUFFER_FLAG_IS_SET(buf, GST_VIDEO_BUFFER_PROGRESSIVE))
414 create_output_buffer(GstVaapiPostproc *postproc)
418 /* Create a raw VA video buffer without GstVaapiVideoMeta attached
419 to it yet, as this will be done next in the transform() hook */
420 outbuf = gst_vaapi_video_buffer_new_empty();
422 goto error_create_buffer;
424 #if !GST_CHECK_VERSION(1,0,0)
425 gst_buffer_set_caps(outbuf, postproc->srcpad_caps);
432 GST_ERROR("failed to create output video buffer");
438 append_output_buffer_metadata(GstBuffer *outbuf, GstBuffer *inbuf, guint flags)
440 gst_buffer_copy_into(outbuf, inbuf, flags |
441 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_META | GST_BUFFER_COPY_MEMORY,
446 deint_method_is_advanced(GstVaapiDeinterlaceMethod deint_method)
448 gboolean is_advanced;
450 switch (deint_method) {
451 case GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE:
452 case GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED:
462 static GstVaapiDeinterlaceMethod
463 get_next_deint_method(GstVaapiDeinterlaceMethod deint_method)
465 switch (deint_method) {
466 case GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED:
467 deint_method = GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE;
470 /* Default to basic "bob" for all others */
471 deint_method = GST_VAAPI_DEINTERLACE_METHOD_BOB;
478 set_best_deint_method(GstVaapiPostproc *postproc, guint flags,
479 GstVaapiDeinterlaceMethod *deint_method_ptr)
481 GstVaapiDeinterlaceMethod deint_method = postproc->deinterlace_method;
485 success = gst_vaapi_filter_set_deinterlacing(postproc->filter,
486 deint_method, flags);
487 if (success || deint_method == GST_VAAPI_DEINTERLACE_METHOD_BOB)
489 deint_method = get_next_deint_method(deint_method);
491 *deint_method_ptr = deint_method;
496 gst_vaapipostproc_process_vpp(GstBaseTransform *trans, GstBuffer *inbuf,
499 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
500 GstVaapiDeinterlaceState * const ds = &postproc->deinterlace_state;
501 GstVaapiVideoMeta *inbuf_meta, *outbuf_meta;
502 GstVaapiSurface *inbuf_surface, *outbuf_surface;
503 GstVaapiFilterStatus status;
504 GstClockTime timestamp;
507 GstVaapiDeinterlaceMethod deint_method;
508 guint flags, deint_flags;
509 gboolean tff, deint, deint_refs, deint_changed;
511 /* Validate filters */
512 if ((postproc->flags & GST_VAAPI_POSTPROC_FLAG_FORMAT) &&
513 !gst_vaapi_filter_set_format(postproc->filter, postproc->format))
514 return GST_FLOW_NOT_SUPPORTED;
516 if ((postproc->flags & GST_VAAPI_POSTPROC_FLAG_DENOISE) &&
517 !gst_vaapi_filter_set_denoising_level(postproc->filter,
518 postproc->denoise_level))
519 return GST_FLOW_NOT_SUPPORTED;
521 if ((postproc->flags & GST_VAAPI_POSTPROC_FLAG_SHARPEN) &&
522 !gst_vaapi_filter_set_denoising_level(postproc->filter,
523 postproc->sharpen_level))
524 return GST_FLOW_NOT_SUPPORTED;
526 inbuf_meta = gst_buffer_get_vaapi_video_meta(inbuf);
528 goto error_invalid_buffer;
529 inbuf_surface = gst_vaapi_video_meta_get_surface(inbuf_meta);
531 timestamp = GST_BUFFER_TIMESTAMP(inbuf);
532 tff = GST_BUFFER_FLAG_IS_SET(inbuf, GST_VIDEO_BUFFER_FLAG_TFF);
533 deint = is_interlaced_buffer(postproc, inbuf);
535 /* Drop references if deinterlacing conditions changed */
536 deint_changed = deint != ds->deint;
537 if (deint_changed || (ds->num_surfaces > 0 && tff != ds->tff))
542 flags = gst_vaapi_video_meta_get_render_flags(inbuf_meta) &
543 ~(GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD|
544 GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD);
547 deint_method = postproc->deinterlace_method;
548 deint_refs = deint_method_is_advanced(deint_method);
549 if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE) {
550 fieldbuf = create_output_buffer(postproc);
552 goto error_create_buffer;
554 outbuf_meta = gst_vaapi_video_meta_new_from_pool(postproc->filter_pool);
556 goto error_create_meta;
557 outbuf_surface = gst_vaapi_video_meta_get_surface(outbuf_meta);
560 deint_flags = (tff ? GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD : 0);
562 deint_flags |= GST_VAAPI_DEINTERLACE_FLAG_TFF;
563 if (!set_best_deint_method(postproc, deint_flags, &deint_method))
564 goto error_op_deinterlace;
566 if (deint_method != postproc->deinterlace_method) {
567 GST_DEBUG("unsupported deinterlace-method %u. Using %u instead",
568 postproc->deinterlace_method, deint_method);
569 postproc->deinterlace_method = deint_method;
570 deint_refs = deint_method_is_advanced(deint_method);
575 if (!gst_vaapi_filter_set_deinterlacing_references(
576 postproc->filter, ds->surfaces, ds->num_surfaces,
578 goto error_op_deinterlace;
581 else if (deint_changed) {
582 // Reset internal filter to non-deinterlacing mode
583 deint_method = GST_VAAPI_DEINTERLACE_METHOD_NONE;
584 if (!gst_vaapi_filter_set_deinterlacing(postproc->filter,
586 goto error_op_deinterlace;
589 status = gst_vaapi_filter_process(postproc->filter, inbuf_surface,
590 outbuf_surface, flags);
591 if (status != GST_VAAPI_FILTER_STATUS_SUCCESS)
592 goto error_process_vpp;
594 gst_buffer_set_vaapi_video_meta(fieldbuf, outbuf_meta);
595 gst_vaapi_video_meta_unref(outbuf_meta);
597 GST_BUFFER_TIMESTAMP(fieldbuf) = timestamp;
598 GST_BUFFER_DURATION(fieldbuf) = postproc->field_duration;
599 ret = gst_pad_push(trans->srcpad, fieldbuf);
600 if (ret != GST_FLOW_OK)
601 goto error_push_buffer;
606 outbuf_meta = gst_vaapi_video_meta_new_from_pool(postproc->filter_pool);
608 goto error_create_meta;
609 outbuf_surface = gst_vaapi_video_meta_get_surface(outbuf_meta);
612 deint_flags = (tff ? 0 : GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD);
614 deint_flags |= GST_VAAPI_DEINTERLACE_FLAG_TFF;
615 if (!gst_vaapi_filter_set_deinterlacing(postproc->filter,
616 deint_method, deint_flags))
617 goto error_op_deinterlace;
619 if (deint_refs && !gst_vaapi_filter_set_deinterlacing_references(
620 postproc->filter, ds->surfaces, ds->num_surfaces, NULL, 0))
621 goto error_op_deinterlace;
623 else if (deint_changed && !gst_vaapi_filter_set_deinterlacing(
624 postproc->filter, deint_method, 0))
625 goto error_op_deinterlace;
627 status = gst_vaapi_filter_process(postproc->filter, inbuf_surface,
628 outbuf_surface, flags);
629 if (status != GST_VAAPI_FILTER_STATUS_SUCCESS)
630 goto error_process_vpp;
632 if (!(postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE))
633 gst_buffer_copy_into(outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
635 GST_BUFFER_TIMESTAMP(outbuf) = timestamp + postproc->field_duration;
636 GST_BUFFER_DURATION(outbuf) = postproc->field_duration;
638 gst_buffer_set_vaapi_video_meta(outbuf, outbuf_meta);
639 gst_vaapi_video_meta_unref(outbuf_meta);
641 if (deint && deint_refs)
642 ds_add_buffer(ds, inbuf);
646 error_invalid_buffer:
648 GST_ERROR("failed to validate source buffer");
649 return GST_FLOW_ERROR;
653 GST_ERROR("failed to create output buffer");
654 return GST_FLOW_ERROR;
658 GST_ERROR("failed to create new output buffer meta");
659 gst_buffer_replace(&fieldbuf, NULL);
660 gst_vaapi_video_meta_unref(outbuf_meta);
661 return GST_FLOW_ERROR;
663 error_op_deinterlace:
665 GST_ERROR("failed to apply deinterlacing filter");
666 gst_buffer_replace(&fieldbuf, NULL);
667 gst_vaapi_video_meta_unref(outbuf_meta);
668 return GST_FLOW_NOT_SUPPORTED;
672 GST_ERROR("failed to apply VPP filters (error %d)", status);
673 gst_buffer_replace(&fieldbuf, NULL);
674 gst_vaapi_video_meta_unref(outbuf_meta);
675 return GST_FLOW_ERROR;
679 if (ret != GST_FLOW_FLUSHING)
680 GST_ERROR("failed to push output buffer to video sink");
681 return GST_FLOW_ERROR;
686 gst_vaapipostproc_process(GstBaseTransform *trans, GstBuffer *inbuf,
689 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
690 GstVaapiVideoMeta *meta;
691 GstClockTime timestamp;
694 guint fieldbuf_flags, outbuf_flags, flags;
697 meta = gst_buffer_get_vaapi_video_meta(inbuf);
699 goto error_invalid_buffer;
701 timestamp = GST_BUFFER_TIMESTAMP(inbuf);
702 tff = GST_BUFFER_FLAG_IS_SET(inbuf, GST_VIDEO_BUFFER_FLAG_TFF);
703 deint = is_interlaced_buffer(postproc, inbuf);
705 flags = gst_vaapi_video_meta_get_render_flags(meta) &
706 ~(GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD|
707 GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD);
710 fieldbuf = create_output_buffer(postproc);
712 goto error_create_buffer;
713 append_output_buffer_metadata(fieldbuf, inbuf, 0);
715 meta = gst_buffer_get_vaapi_video_meta(fieldbuf);
716 fieldbuf_flags = flags;
717 fieldbuf_flags |= deint ? (
719 GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD :
720 GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD) :
721 GST_VAAPI_PICTURE_STRUCTURE_FRAME;
722 gst_vaapi_video_meta_set_render_flags(meta, fieldbuf_flags);
724 GST_BUFFER_TIMESTAMP(fieldbuf) = timestamp;
725 GST_BUFFER_DURATION(fieldbuf) = postproc->field_duration;
726 ret = gst_pad_push(trans->srcpad, fieldbuf);
727 if (ret != GST_FLOW_OK)
728 goto error_push_buffer;
731 append_output_buffer_metadata(outbuf, inbuf, 0);
733 meta = gst_buffer_get_vaapi_video_meta(outbuf);
734 outbuf_flags = flags;
735 outbuf_flags |= deint ? (
737 GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD :
738 GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD) :
739 GST_VAAPI_PICTURE_STRUCTURE_FRAME;
740 gst_vaapi_video_meta_set_render_flags(meta, outbuf_flags);
742 GST_BUFFER_TIMESTAMP(outbuf) = timestamp + postproc->field_duration;
743 GST_BUFFER_DURATION(outbuf) = postproc->field_duration;
747 error_invalid_buffer:
749 GST_ERROR("failed to validate source buffer");
750 return GST_FLOW_ERROR;
754 GST_ERROR("failed to create output buffer");
759 if (ret != GST_FLOW_FLUSHING)
760 GST_ERROR("failed to push output buffer to video sink");
766 gst_vaapipostproc_passthrough(GstBaseTransform *trans, GstBuffer *inbuf,
769 GstVaapiVideoMeta *meta;
771 /* No video processing needed, simply copy buffer metadata */
772 meta = gst_buffer_get_vaapi_video_meta(inbuf);
774 goto error_invalid_buffer;
776 append_output_buffer_metadata(outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS);
780 error_invalid_buffer:
782 GST_ERROR("failed to validate source buffer");
783 return GST_FLOW_ERROR;
788 is_deinterlace_enabled(GstVaapiPostproc *postproc, GstVideoInfo *vip)
790 gboolean deinterlace;
792 switch (postproc->deinterlace_mode) {
793 case GST_VAAPI_DEINTERLACE_MODE_AUTO:
794 deinterlace = GST_VIDEO_INFO_IS_INTERLACED(vip);
796 case GST_VAAPI_DEINTERLACE_MODE_INTERLACED:
807 video_info_changed(GstVideoInfo *old_vip, GstVideoInfo *new_vip)
809 if (GST_VIDEO_INFO_FORMAT(old_vip) != GST_VIDEO_INFO_FORMAT(new_vip))
811 if (GST_VIDEO_INFO_INTERLACE_MODE(old_vip) !=
812 GST_VIDEO_INFO_INTERLACE_MODE(new_vip))
814 if (GST_VIDEO_INFO_WIDTH(old_vip) != GST_VIDEO_INFO_WIDTH(new_vip))
816 if (GST_VIDEO_INFO_HEIGHT(old_vip) != GST_VIDEO_INFO_HEIGHT(new_vip))
822 gst_vaapipostproc_update_sink_caps(GstVaapiPostproc *postproc, GstCaps *caps,
823 gboolean *caps_changed_ptr)
826 gboolean deinterlace;
828 if (!gst_video_info_from_caps(&vi, caps))
831 if (video_info_changed(&vi, &postproc->sinkpad_info))
832 postproc->sinkpad_info = vi, *caps_changed_ptr = TRUE;
834 deinterlace = is_deinterlace_enabled(postproc, &vi);
836 postproc->flags |= GST_VAAPI_POSTPROC_FLAG_DEINTERLACE;
837 postproc->field_duration = gst_util_uint64_scale(
838 GST_SECOND, GST_VIDEO_INFO_FPS_D(&vi),
839 (1 + deinterlace) * GST_VIDEO_INFO_FPS_N(&vi));
841 postproc->is_raw_yuv = GST_VIDEO_INFO_IS_YUV(&vi);
842 #if !GST_CHECK_VERSION(1,0,0)
843 if (postproc->is_raw_yuv) {
844 /* Ensure the uploader is set up for upstream allocated buffers */
845 GstVaapiUploader * const uploader = postproc->uploader;
846 if (!gst_vaapi_uploader_ensure_display(uploader, GST_VAAPI_PLUGIN_BASE_DISPLAY(postproc)))
848 if (!gst_vaapi_uploader_ensure_caps(uploader, caps, NULL))
856 gst_vaapipostproc_update_src_caps(GstVaapiPostproc *postproc, GstCaps *caps,
857 gboolean *caps_changed_ptr)
861 if (!gst_video_info_from_caps(&vi, caps))
864 if (video_info_changed(&vi, &postproc->srcpad_info))
865 postproc->srcpad_info = vi, *caps_changed_ptr = TRUE;
867 if (postproc->format != GST_VIDEO_INFO_FORMAT(&postproc->sinkpad_info))
868 postproc->flags |= GST_VAAPI_POSTPROC_FLAG_FORMAT;
870 if ((postproc->width || postproc->height) &&
871 postproc->width != GST_VIDEO_INFO_WIDTH(&postproc->sinkpad_info) &&
872 postproc->height != GST_VIDEO_INFO_HEIGHT(&postproc->sinkpad_info))
873 postproc->flags |= GST_VAAPI_POSTPROC_FLAG_SIZE;
878 ensure_allowed_sinkpad_caps(GstVaapiPostproc *postproc)
880 GstCaps *out_caps, *yuv_caps;
882 if (postproc->allowed_sinkpad_caps)
886 #if GST_CHECK_VERSION(1,1,0)
887 out_caps = gst_static_pad_template_get_caps(
888 &gst_vaapipostproc_sink_factory);
890 out_caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS ", "
891 GST_CAPS_INTERLACED_MODES);
894 GST_ERROR("failed to create VA sink caps");
898 /* Append YUV caps */
899 if (gst_vaapipostproc_ensure_uploader(postproc)) {
900 yuv_caps = gst_vaapi_uploader_get_caps(postproc->uploader);
902 out_caps = gst_caps_make_writable(out_caps);
903 gst_caps_append(out_caps, gst_caps_copy(yuv_caps));
906 GST_WARNING("failed to create YUV sink caps");
908 postproc->allowed_sinkpad_caps = out_caps;
910 /* XXX: append VA/VPP filters */
914 /* Build list of supported formats */
916 build_format_list_value(GArray *formats, GValue *out_value)
918 GValue v_format = { 0, };
920 #if GST_CHECK_VERSION(1,0,0)
923 g_value_init(out_value, GST_TYPE_LIST);
925 g_value_init(&v_format, G_TYPE_STRING);
926 g_value_set_string(&v_format, "encoded");
927 gst_value_list_append_value(out_value, &v_format);
929 for (i = 0; i < formats->len; i++) {
930 GstVideoFormat const format =
931 g_array_index(formats, GstVideoFormat, i);
933 str = gst_vaapi_video_format_to_string(format);
936 g_value_set_string(&v_format, str);
937 gst_value_list_append_value(out_value, &v_format);
942 g_value_init(out_value, GST_TYPE_LIST);
943 g_value_init(&v_format, GST_TYPE_FOURCC);
944 for (i = 0; i < formats->len; i++) {
945 GstVideoFormat const format =
946 g_array_index(formats, GstVideoFormat, i);
948 fourcc = gst_video_format_to_fourcc(format);
951 gst_value_set_fourcc(&v_format, fourcc);
952 gst_value_list_append_value(out_value, &v_format);
956 g_value_unset(&v_format);
960 /* Fixup output caps so that to reflect the supported set of pixel formats */
962 expand_allowed_srcpad_caps(GstVaapiPostproc *postproc, GstCaps *caps)
964 GValue value = { 0, };
965 guint i, num_structures;
968 had_filter = postproc->filter != NULL;
969 if (!had_filter && !gst_vaapipostproc_ensure_filter(postproc))
971 if (!gst_vaapipostproc_ensure_filter_caps(postproc))
974 /* Reset "format" field for each structure */
975 if (!build_format_list_value(postproc->filter_formats, &value))
978 num_structures = gst_caps_get_size(caps);
979 for (i = 0; i < num_structures; i++) {
980 GstStructure * const structure = gst_caps_get_structure(caps, i);
983 gst_structure_set_value(structure, "format", &value);
985 g_value_unset(&value);
989 gst_vaapipostproc_destroy_filter(postproc);
994 ensure_allowed_srcpad_caps(GstVaapiPostproc *postproc)
998 if (postproc->allowed_srcpad_caps)
1001 /* Create initial caps from pad template */
1002 out_caps = gst_caps_from_string(gst_vaapipostproc_src_caps_str);
1004 GST_ERROR("failed to create VA src caps");
1008 postproc->allowed_srcpad_caps =
1009 expand_allowed_srcpad_caps(postproc, out_caps);
1010 return postproc->allowed_srcpad_caps != NULL;
1014 find_best_size(GstVaapiPostproc *postproc, GstVideoInfo *vip,
1015 guint *width_ptr, guint *height_ptr)
1017 guint width, height;
1019 width = GST_VIDEO_INFO_WIDTH(vip);
1020 height = GST_VIDEO_INFO_HEIGHT(vip);
1021 if (postproc->width && postproc->height) {
1022 width = postproc->width;
1023 height = postproc->height;
1025 else if (postproc->keep_aspect) {
1026 const gdouble ratio = (gdouble)width / height;
1027 if (postproc->width) {
1028 width = postproc->width;
1029 height = postproc->width / ratio;
1031 else if (postproc->height) {
1032 height = postproc->height;
1033 width = postproc->height * ratio;
1036 else if (postproc->width)
1037 width = postproc->width;
1038 else if (postproc->height)
1039 height = postproc->height;
1042 *height_ptr = height;
1046 gst_vaapipostproc_transform_caps_impl(GstBaseTransform *trans,
1047 GstPadDirection direction, GstCaps *caps)
1049 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
1051 GstVideoFormat format;
1053 guint width, height;
1055 /* Generate the sink pad caps, that could be fixated afterwards */
1056 if (direction == GST_PAD_SRC) {
1057 if (!ensure_allowed_sinkpad_caps(postproc))
1059 return gst_caps_ref(postproc->allowed_sinkpad_caps);
1062 /* Generate complete set of src pad caps if non-fixated sink pad
1063 caps are provided */
1064 if (!gst_caps_is_fixed(caps)) {
1065 if (!ensure_allowed_srcpad_caps(postproc))
1067 return gst_caps_ref(postproc->allowed_srcpad_caps);
1070 /* Generate the expected src pad caps, from the current fixated
1072 if (!gst_video_info_from_caps(&vi, caps))
1075 // Set double framerate in interlaced mode
1076 if (is_deinterlace_enabled(postproc, &vi)) {
1077 gint fps_n = GST_VIDEO_INFO_FPS_N(&vi);
1078 gint fps_d = GST_VIDEO_INFO_FPS_D(&vi);
1079 if (!gst_util_fraction_multiply(fps_n, fps_d, 2, 1, &fps_n, &fps_d))
1081 GST_VIDEO_INFO_FPS_N(&vi) = fps_n;
1082 GST_VIDEO_INFO_FPS_D(&vi) = fps_d;
1085 // Signal the other pad that we only generate progressive frames
1086 GST_VIDEO_INFO_INTERLACE_MODE(&vi) = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
1088 // Update size from user-specified parameters
1089 #if GST_CHECK_VERSION(1,1,0)
1090 format = postproc->format;
1092 format = GST_VIDEO_FORMAT_ENCODED;
1094 find_best_size(postproc, &vi, &width, &height);
1095 gst_video_info_set_format(&vi, format, width, height);
1097 #if GST_CHECK_VERSION(1,1,0)
1098 out_caps = gst_video_info_to_caps(&vi);
1102 gst_caps_set_features(out_caps, 0,
1103 gst_caps_features_new(GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, NULL));
1105 /* XXX: gst_video_info_to_caps() from GStreamer 0.10 does not
1106 reconstruct suitable caps for "encoded" video formats */
1107 out_caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS_NAME);
1111 gst_caps_set_simple(out_caps,
1112 "type", G_TYPE_STRING, "vaapi",
1113 "opengl", G_TYPE_BOOLEAN, USE_GLX,
1114 "width", G_TYPE_INT, GST_VIDEO_INFO_WIDTH(&vi),
1115 "height", G_TYPE_INT, GST_VIDEO_INFO_HEIGHT(&vi),
1116 "framerate", GST_TYPE_FRACTION, GST_VIDEO_INFO_FPS_N(&vi),
1117 GST_VIDEO_INFO_FPS_D(&vi),
1118 "pixel-aspect-ratio", GST_TYPE_FRACTION, GST_VIDEO_INFO_PAR_N(&vi),
1119 GST_VIDEO_INFO_PAR_D(&vi),
1122 gst_caps_set_interlaced(out_caps, &vi);
1127 #if GST_CHECK_VERSION(1,0,0)
1129 gst_vaapipostproc_transform_caps(GstBaseTransform *trans,
1130 GstPadDirection direction, GstCaps *caps, GstCaps *filter)
1134 caps = gst_vaapipostproc_transform_caps_impl(trans, direction, caps);
1135 if (caps && filter) {
1136 out_caps = gst_caps_intersect_full(caps, filter,
1137 GST_CAPS_INTERSECT_FIRST);
1138 gst_caps_unref(caps);
1144 #define gst_vaapipostproc_transform_caps \
1145 gst_vaapipostproc_transform_caps_impl
1148 #if GST_CHECK_VERSION(1,0,0)
1149 typedef gsize GstBaseTransformSizeType;
1151 typedef guint GstBaseTransformSizeType;
1155 gst_vaapipostproc_transform_size(GstBaseTransform *trans,
1156 GstPadDirection direction, GstCaps *caps, GstBaseTransformSizeType size,
1157 GstCaps *othercaps, GstBaseTransformSizeType *othersize)
1159 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
1161 if (direction == GST_PAD_SINK || !postproc->is_raw_yuv)
1169 get_source_buffer(GstVaapiPostproc *postproc, GstBuffer *inbuf)
1171 GstVaapiVideoMeta *meta;
1173 #if GST_CHECK_VERSION(1,0,0)
1174 GstVideoFrame src_frame, out_frame;
1177 meta = gst_buffer_get_vaapi_video_meta(inbuf);
1179 return gst_buffer_ref(inbuf);
1181 #if GST_CHECK_VERSION(1,0,0)
1182 if (!postproc->is_raw_yuv)
1183 goto error_invalid_buffer;
1185 if (!postproc->sinkpad_buffer_pool)
1188 if (!gst_buffer_pool_set_active(postproc->sinkpad_buffer_pool, TRUE))
1189 goto error_active_pool;
1192 if (gst_buffer_pool_acquire_buffer(postproc->sinkpad_buffer_pool,
1193 &outbuf, NULL) != GST_FLOW_OK)
1194 goto error_create_buffer;
1196 if (!gst_video_frame_map(&src_frame, &postproc->sinkpad_info, inbuf,
1198 goto error_map_src_buffer;
1200 if (!gst_video_frame_map(&out_frame, &postproc->sinkpad_info, outbuf,
1202 goto error_map_dst_buffer;
1204 if (!gst_video_frame_copy(&out_frame, &src_frame))
1205 goto error_copy_buffer;
1207 gst_video_frame_unmap(&out_frame);
1208 gst_video_frame_unmap(&src_frame);
1209 gst_buffer_copy_into(outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
1213 error_invalid_buffer:
1215 GST_ERROR("failed to validate source buffer");
1220 GST_ERROR("no buffer pool was negotiated");
1225 GST_ERROR("failed to activate buffer pool");
1228 error_map_dst_buffer:
1230 gst_video_frame_unmap(&src_frame);
1233 error_map_src_buffer:
1235 GST_ERROR("failed to map buffer");
1236 gst_buffer_unref(outbuf);
1240 outbuf = gst_vaapi_uploader_get_buffer(postproc->uploader);
1242 goto error_create_buffer;
1243 if (!gst_vaapi_uploader_process(postproc->uploader, inbuf, outbuf))
1244 goto error_copy_buffer;
1246 gst_buffer_copy_metadata(outbuf, inbuf,
1247 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
1252 error_create_buffer:
1254 GST_ERROR("failed to create buffer");
1259 GST_ERROR("failed to upload buffer to VA surface");
1260 #if GST_CHECK_VERSION(1,0,0)
1261 gst_video_frame_unmap(&out_frame);
1262 gst_video_frame_unmap(&src_frame);
1264 gst_buffer_unref(outbuf);
1269 static GstFlowReturn
1270 gst_vaapipostproc_transform(GstBaseTransform *trans, GstBuffer *inbuf,
1273 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
1277 buf = get_source_buffer(postproc, inbuf);
1279 return GST_FLOW_ERROR;
1281 ret = GST_FLOW_NOT_SUPPORTED;
1282 if (postproc->flags) {
1283 /* Use VA/VPP extensions to process this frame */
1284 if (postproc->use_vpp &&
1285 postproc->flags != GST_VAAPI_POSTPROC_FLAG_DEINTERLACE) {
1286 ret = gst_vaapipostproc_process_vpp(trans, buf, outbuf);
1287 if (ret != GST_FLOW_NOT_SUPPORTED)
1289 GST_WARNING("unsupported VPP filters. Disabling");
1290 postproc->use_vpp = FALSE;
1293 /* Only append picture structure meta data (top/bottom field) */
1294 if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE) {
1295 ret = gst_vaapipostproc_process(trans, buf, outbuf);
1296 if (ret != GST_FLOW_NOT_SUPPORTED)
1301 /* Fallback: passthrough to the downstream element as is */
1302 ret = gst_vaapipostproc_passthrough(trans, buf, outbuf);
1305 gst_buffer_unref(buf);
1309 static GstFlowReturn
1310 gst_vaapipostproc_prepare_output_buffer(GstBaseTransform *trans,
1312 #if !GST_CHECK_VERSION(1,0,0)
1313 gint size, GstCaps *caps,
1315 GstBuffer **outbuf_ptr)
1317 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
1319 *outbuf_ptr = create_output_buffer(postproc);
1320 return *outbuf_ptr ? GST_FLOW_OK : GST_FLOW_ERROR;
1324 ensure_sinkpad_buffer_pool(GstVaapiPostproc *postproc, GstCaps *caps)
1326 #if GST_CHECK_VERSION(1,0,0)
1327 GstBufferPool *pool;
1329 GstStructure *config;
1333 if (!gst_vaapipostproc_ensure_display(postproc))
1336 if (postproc->sinkpad_buffer_pool) {
1337 config = gst_buffer_pool_get_config(postproc->sinkpad_buffer_pool);
1338 gst_buffer_pool_config_get_params(config, &pool_caps, NULL, NULL, NULL);
1339 need_pool = !gst_caps_is_equal(caps, pool_caps);
1340 gst_structure_free(config);
1343 g_clear_object(&postproc->sinkpad_buffer_pool);
1344 postproc->sinkpad_buffer_size = 0;
1347 pool = gst_vaapi_video_buffer_pool_new(
1348 GST_VAAPI_PLUGIN_BASE_DISPLAY(postproc));
1350 goto error_create_pool;
1352 gst_video_info_init(&vi);
1353 gst_video_info_from_caps(&vi, caps);
1354 if (GST_VIDEO_INFO_FORMAT(&vi) == GST_VIDEO_FORMAT_ENCODED) {
1355 GST_DEBUG("assume sink pad buffer pool format is NV12");
1356 gst_video_info_set_format(&vi, GST_VIDEO_FORMAT_NV12,
1357 GST_VIDEO_INFO_WIDTH(&vi), GST_VIDEO_INFO_HEIGHT(&vi));
1359 postproc->sinkpad_buffer_size = vi.size;
1361 config = gst_buffer_pool_get_config(pool);
1362 gst_buffer_pool_config_set_params(config, caps,
1363 postproc->sinkpad_buffer_size, 0, 0);
1364 gst_buffer_pool_config_add_option(config,
1365 GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META);
1366 gst_buffer_pool_config_add_option(config,
1367 GST_BUFFER_POOL_OPTION_VIDEO_META);
1368 if (!gst_buffer_pool_set_config(pool, config))
1369 goto error_pool_config;
1370 postproc->sinkpad_buffer_pool = pool;
1376 GST_ERROR("failed to create buffer pool");
1381 GST_ERROR("failed to reset buffer pool config");
1382 gst_object_unref(pool);
1391 ensure_srcpad_buffer_pool(GstVaapiPostproc *postproc, GstCaps *caps)
1394 GstVaapiVideoPool *pool;
1396 gst_video_info_init(&vi);
1397 gst_video_info_from_caps(&vi, caps);
1398 gst_video_info_set_format(&vi, postproc->format,
1399 GST_VIDEO_INFO_WIDTH(&vi), GST_VIDEO_INFO_HEIGHT(&vi));
1401 if (!video_info_changed(&vi, &postproc->filter_pool_info))
1403 postproc->filter_pool_info = vi;
1405 pool = gst_vaapi_surface_pool_new(GST_VAAPI_PLUGIN_BASE_DISPLAY(postproc),
1406 &postproc->filter_pool_info);
1410 gst_vaapi_video_pool_replace(&postproc->filter_pool, pool);
1411 gst_vaapi_video_pool_unref(pool);
1416 gst_vaapipostproc_set_caps(GstBaseTransform *trans, GstCaps *caps,
1419 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
1420 gboolean caps_changed = FALSE;
1422 if (!gst_vaapipostproc_update_sink_caps(postproc, caps, &caps_changed))
1424 if (!gst_vaapipostproc_update_src_caps(postproc, out_caps, &caps_changed))
1428 gst_vaapipostproc_destroy(postproc);
1429 gst_caps_replace(&postproc->sinkpad_caps, caps);
1430 gst_caps_replace(&postproc->srcpad_caps, out_caps);
1431 if (!gst_vaapipostproc_create(postproc))
1435 if (!ensure_sinkpad_buffer_pool(postproc, caps))
1437 if (!ensure_srcpad_buffer_pool(postproc, out_caps))
1443 gst_vaapipostproc_query(GstBaseTransform *trans, GstPadDirection direction,
1446 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
1448 GST_INFO_OBJECT(trans, "query type `%s'", GST_QUERY_TYPE_NAME(query));
1450 if (gst_vaapi_reply_to_query(query, GST_VAAPI_PLUGIN_BASE_DISPLAY(postproc))) {
1451 GST_DEBUG("sharing display %p", GST_VAAPI_PLUGIN_BASE_DISPLAY(postproc));
1455 return GST_BASE_TRANSFORM_CLASS(gst_vaapipostproc_parent_class)->query(
1456 trans, direction, query);
1459 #if GST_CHECK_VERSION(1,0,0)
1461 gst_vaapipostproc_propose_allocation(GstBaseTransform *trans,
1462 GstQuery *decide_query, GstQuery *query)
1464 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(trans);
1465 GstCaps *caps = NULL;
1468 /* Let vaapidecode allocate the video buffers */
1469 if (!postproc->is_raw_yuv)
1472 gst_query_parse_allocation(query, &caps, &need_pool);
1477 if (!ensure_sinkpad_buffer_pool(postproc, caps))
1479 gst_query_add_allocation_pool(query, postproc->sinkpad_buffer_pool,
1480 postproc->sinkpad_buffer_size, 0, 0);
1483 gst_query_add_allocation_meta(query,
1484 GST_VAAPI_VIDEO_META_API_TYPE, NULL);
1485 gst_query_add_allocation_meta(query,
1486 GST_VIDEO_META_API_TYPE, NULL);
1487 gst_query_add_allocation_meta(query,
1488 GST_VIDEO_CROP_META_API_TYPE, NULL);
1489 gst_query_add_allocation_meta(query,
1490 GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, NULL);
1496 GST_ERROR("no caps specified");
1503 gst_vaapipostproc_finalize(GObject *object)
1505 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(object);
1507 gst_vaapipostproc_destroy(postproc);
1509 gst_vaapi_plugin_base_finalize(GST_VAAPI_PLUGIN_BASE(postproc));
1510 G_OBJECT_CLASS(gst_vaapipostproc_parent_class)->finalize(object);
1514 gst_vaapipostproc_set_property(
1517 const GValue *value,
1521 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(object);
1525 postproc->format = g_value_get_enum(value);
1528 postproc->width = g_value_get_uint(value);
1531 postproc->height = g_value_get_uint(value);
1533 case PROP_FORCE_ASPECT_RATIO:
1534 postproc->keep_aspect = g_value_get_boolean(value);
1536 case PROP_DEINTERLACE_MODE:
1537 postproc->deinterlace_mode = g_value_get_enum(value);
1539 case PROP_DEINTERLACE_METHOD:
1540 postproc->deinterlace_method = g_value_get_enum(value);
1543 postproc->denoise_level = g_value_get_float(value);
1544 postproc->flags |= GST_VAAPI_POSTPROC_FLAG_DENOISE;
1547 postproc->sharpen_level = g_value_get_float(value);
1548 postproc->flags |= GST_VAAPI_POSTPROC_FLAG_SHARPEN;
1551 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
1557 gst_vaapipostproc_get_property(
1564 GstVaapiPostproc * const postproc = GST_VAAPIPOSTPROC(object);
1568 g_value_set_enum(value, postproc->format);
1571 g_value_set_uint(value, postproc->width);
1574 g_value_set_uint(value, postproc->height);
1576 case PROP_FORCE_ASPECT_RATIO:
1577 g_value_set_boolean(value, postproc->keep_aspect);
1579 case PROP_DEINTERLACE_MODE:
1580 g_value_set_enum(value, postproc->deinterlace_mode);
1582 case PROP_DEINTERLACE_METHOD:
1583 g_value_set_enum(value, postproc->deinterlace_method);
1586 g_value_set_float(value, postproc->denoise_level);
1589 g_value_set_float(value, postproc->sharpen_level);
1592 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
1598 gst_vaapipostproc_class_init(GstVaapiPostprocClass *klass)
1600 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
1601 GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
1602 GstBaseTransformClass * const trans_class = GST_BASE_TRANSFORM_CLASS(klass);
1603 GstPadTemplate *pad_template;
1604 GPtrArray *filter_ops;
1605 GstVaapiFilterOpInfo *filter_op;
1607 GST_DEBUG_CATEGORY_INIT(gst_debug_vaapipostproc,
1608 GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
1610 gst_vaapi_plugin_base_class_init(GST_VAAPI_PLUGIN_BASE_CLASS(klass));
1612 object_class->finalize = gst_vaapipostproc_finalize;
1613 object_class->set_property = gst_vaapipostproc_set_property;
1614 object_class->get_property = gst_vaapipostproc_get_property;
1615 trans_class->start = gst_vaapipostproc_start;
1616 trans_class->stop = gst_vaapipostproc_stop;
1617 trans_class->transform_caps = gst_vaapipostproc_transform_caps;
1618 trans_class->transform_size = gst_vaapipostproc_transform_size;
1619 trans_class->transform = gst_vaapipostproc_transform;
1620 trans_class->set_caps = gst_vaapipostproc_set_caps;
1621 trans_class->query = gst_vaapipostproc_query;
1623 #if GST_CHECK_VERSION(1,0,0)
1624 trans_class->propose_allocation = gst_vaapipostproc_propose_allocation;
1627 trans_class->prepare_output_buffer =
1628 gst_vaapipostproc_prepare_output_buffer;
1630 #if GST_CHECK_VERSION(1,1,0)
1631 element_class->set_context = gst_vaapipostproc_set_context;
1634 gst_element_class_set_static_metadata(element_class,
1635 "VA-API video postprocessing",
1636 "Filter/Converter/Video",
1638 "Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
1641 pad_template = gst_static_pad_template_get(&gst_vaapipostproc_sink_factory);
1642 gst_element_class_add_pad_template(element_class, pad_template);
1645 pad_template = gst_static_pad_template_get(&gst_vaapipostproc_src_factory);
1646 gst_element_class_add_pad_template(element_class, pad_template);
1649 * GstVaapiPostproc:deinterlace-mode:
1651 * This selects whether the deinterlacing should always be applied or if
1652 * they should only be applied on content that has the "interlaced" flag
1655 g_object_class_install_property
1657 PROP_DEINTERLACE_MODE,
1658 g_param_spec_enum("deinterlace-mode",
1660 "Deinterlace mode to use",
1661 GST_VAAPI_TYPE_DEINTERLACE_MODE,
1662 DEFAULT_DEINTERLACE_MODE,
1663 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1666 * GstVaapiPostproc:deinterlace-method:
1668 * This selects the deinterlacing method to apply.
1670 g_object_class_install_property
1672 PROP_DEINTERLACE_METHOD,
1673 g_param_spec_enum("deinterlace-method",
1674 "Deinterlace method",
1675 "Deinterlace method to use",
1676 GST_VAAPI_TYPE_DEINTERLACE_METHOD,
1677 DEFAULT_DEINTERLACE_METHOD,
1678 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1680 filter_ops = gst_vaapi_filter_get_operations(NULL);
1685 * GstVaapiPostproc:format:
1687 * The forced output pixel format, expressed as a #GstVideoFormat.
1689 filter_op = find_filter_op(filter_ops, GST_VAAPI_FILTER_OP_FORMAT);
1691 g_object_class_install_property(object_class,
1692 PROP_FORMAT, filter_op->pspec);
1695 * GstVaapiPostproc:width:
1697 * The forced output width in pixels. If set to zero, the width is
1698 * calculated from the height if aspect ration is preserved, or
1699 * inherited from the sink caps width
1701 g_object_class_install_property
1704 g_param_spec_uint("width",
1706 "Forced output width",
1708 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1711 * GstVaapiPostproc:height:
1713 * The forced output height in pixels. If set to zero, the height
1714 * is calculated from the width if aspect ration is preserved, or
1715 * inherited from the sink caps height
1717 g_object_class_install_property
1720 g_param_spec_uint("height",
1722 "Forced output height",
1724 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1727 * GstVaapiPostproc:force-aspect-ratio:
1729 * When enabled, scaling respects video aspect ratio; when
1730 * disabled, the video is distorted to fit the width and height
1733 g_object_class_install_property
1735 PROP_FORCE_ASPECT_RATIO,
1736 g_param_spec_boolean("force-aspect-ratio",
1737 "Force aspect ratio",
1738 "When enabled, scaling will respect original aspect ratio",
1740 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1743 * GstVaapiPostproc:denoise:
1745 * The level of noise reduction to apply.
1747 filter_op = find_filter_op(filter_ops, GST_VAAPI_FILTER_OP_DENOISE);
1749 g_object_class_install_property(object_class,
1750 PROP_DENOISE, filter_op->pspec);
1753 * GstVaapiPostproc:sharpen:
1755 * The level of sharpening to apply for positive values, or the
1756 * level of blurring for negative values.
1758 filter_op = find_filter_op(filter_ops, GST_VAAPI_FILTER_OP_SHARPEN);
1760 g_object_class_install_property(object_class,
1761 PROP_SHARPEN, filter_op->pspec);
1763 g_ptr_array_unref(filter_ops);
1767 gst_vaapipostproc_init(GstVaapiPostproc *postproc)
1769 gst_vaapi_plugin_base_init(GST_VAAPI_PLUGIN_BASE(postproc), GST_CAT_DEFAULT);
1771 postproc->format = DEFAULT_FORMAT;
1772 postproc->deinterlace_mode = DEFAULT_DEINTERLACE_MODE;
1773 postproc->deinterlace_method = DEFAULT_DEINTERLACE_METHOD;
1774 postproc->field_duration = GST_CLOCK_TIME_NONE;
1775 postproc->keep_aspect = TRUE;
1777 gst_video_info_init(&postproc->sinkpad_info);
1778 gst_video_info_init(&postproc->srcpad_info);
1779 gst_video_info_init(&postproc->filter_pool_info);