2 * gstvaapiupload.c - VA-API video uploader
4 * Copyright (C) 2010-2011 Splitted-Desktop Systems
5 * Copyright (C) 2011-2012 Intel Corporation
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:gstvaapiupload
25 * @short_description: A video to VA flow filter
27 * vaapiupload uploads from raw YUV pixels to VA surfaces suitable
28 * for the vaapisink element, for example.
31 #include "gst/vaapi/sysdeps.h"
33 #include <gst/video/video.h>
34 #include <gst/video/videocontext.h>
35 #include <gst/vaapi/gstvaapivideobuffer.h>
37 #include "gstvaapiupload.h"
38 #include "gstvaapipluginutil.h"
39 #include "gstvaapipluginbuffer.h"
41 #define GST_PLUGIN_NAME "vaapiupload"
42 #define GST_PLUGIN_DESC "A video to VA flow filter"
44 GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapiupload);
45 #define GST_CAT_DEFAULT gst_debug_vaapiupload
47 /* ElementFactory information */
48 static const GstElementDetails gst_vaapiupload_details =
50 "VA-API colorspace uploader",
51 "Filter/Converter/Video",
53 "Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
55 /* Default templates */
56 static const char gst_vaapiupload_yuv_caps_str[] =
58 "width = (int) [ 1, MAX ], "
59 "height = (int) [ 1, MAX ]; ";
61 static const char gst_vaapiupload_vaapi_caps_str[] =
62 GST_VAAPI_SURFACE_CAPS;
64 static GstStaticPadTemplate gst_vaapiupload_sink_factory =
65 GST_STATIC_PAD_TEMPLATE(
69 GST_STATIC_CAPS(gst_vaapiupload_yuv_caps_str));
71 static GstStaticPadTemplate gst_vaapiupload_src_factory =
72 GST_STATIC_PAD_TEMPLATE(
76 GST_STATIC_CAPS(gst_vaapiupload_vaapi_caps_str));
79 gst_vaapiupload_implements_iface_init(GstImplementsInterfaceClass *iface);
82 gst_video_context_interface_init(GstVideoContextInterface *iface);
84 #define GstVideoContextClass GstVideoContextInterface
85 G_DEFINE_TYPE_WITH_CODE(
88 GST_TYPE_BASE_TRANSFORM,
89 G_IMPLEMENT_INTERFACE(GST_TYPE_IMPLEMENTS_INTERFACE,
90 gst_vaapiupload_implements_iface_init);
91 G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_CONTEXT,
92 gst_video_context_interface_init))
95 * Direct rendering levels (direct-rendering)
96 * 0: upstream allocated YUV pixels
97 * 1: vaapiupload allocated YUV pixels (mapped from VA image)
98 * 2: vaapiupload allocated YUV pixels (mapped from VA surface)
100 #define DIRECT_RENDERING_DEFAULT 2
105 PROP_DIRECT_RENDERING,
109 gst_vaapiupload_start(GstBaseTransform *trans);
112 gst_vaapiupload_stop(GstBaseTransform *trans);
115 gst_vaapiupload_transform(
116 GstBaseTransform *trans,
122 gst_vaapiupload_transform_caps(
123 GstBaseTransform *trans,
124 GstPadDirection direction,
129 gst_vaapiupload_set_caps(
130 GstBaseTransform *trans,
136 gst_vaapiupload_get_unit_size(
137 GstBaseTransform *trans,
143 gst_vaapiupload_sinkpad_buffer_alloc(
152 gst_vaapiupload_prepare_output_buffer(
153 GstBaseTransform *trans,
161 gst_vaapiupload_query(
166 /* GstImplementsInterface interface */
169 gst_vaapiupload_implements_interface_supported(
170 GstImplementsInterface *iface,
174 return (type == GST_TYPE_VIDEO_CONTEXT);
178 gst_vaapiupload_implements_iface_init(GstImplementsInterfaceClass *iface)
180 iface->supported = gst_vaapiupload_implements_interface_supported;
183 /* GstVideoContext interface */
186 gst_vaapiupload_set_video_context(GstVideoContext *context, const gchar *type,
189 GstVaapiUpload *upload = GST_VAAPIUPLOAD (context);
190 gst_vaapi_set_display (type, value, &upload->display);
194 gst_video_context_interface_init(GstVideoContextInterface *iface)
196 iface->set_context = gst_vaapiupload_set_video_context;
200 gst_vaapiupload_destroy(GstVaapiUpload *upload)
202 g_clear_object(&upload->images);
203 g_clear_object(&upload->surfaces);
204 g_clear_object(&upload->display);
208 gst_vaapiupload_finalize(GObject *object)
210 gst_vaapiupload_destroy(GST_VAAPIUPLOAD(object));
212 G_OBJECT_CLASS(gst_vaapiupload_parent_class)->finalize(object);
217 gst_vaapiupload_set_property(
224 GstVaapiUpload * const upload = GST_VAAPIUPLOAD(object);
227 case PROP_DIRECT_RENDERING:
228 GST_OBJECT_LOCK(upload);
229 upload->direct_rendering = g_value_get_uint(value);
230 GST_OBJECT_UNLOCK(upload);
233 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
239 gst_vaapiupload_get_property(
246 GstVaapiUpload * const upload = GST_VAAPIUPLOAD(object);
249 case PROP_DIRECT_RENDERING:
250 g_value_set_uint(value, upload->direct_rendering);
253 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
259 gst_vaapiupload_class_init(GstVaapiUploadClass *klass)
261 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
262 GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
263 GstBaseTransformClass * const trans_class = GST_BASE_TRANSFORM_CLASS(klass);
264 GstPadTemplate *pad_template;
266 GST_DEBUG_CATEGORY_INIT(gst_debug_vaapiupload,
267 GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
269 object_class->finalize = gst_vaapiupload_finalize;
270 object_class->set_property = gst_vaapiupload_set_property;
271 object_class->get_property = gst_vaapiupload_get_property;
273 trans_class->start = gst_vaapiupload_start;
274 trans_class->stop = gst_vaapiupload_stop;
275 trans_class->transform = gst_vaapiupload_transform;
276 trans_class->transform_caps = gst_vaapiupload_transform_caps;
277 trans_class->set_caps = gst_vaapiupload_set_caps;
278 trans_class->get_unit_size = gst_vaapiupload_get_unit_size;
279 trans_class->prepare_output_buffer = gst_vaapiupload_prepare_output_buffer;
281 gst_element_class_set_details_simple(
283 gst_vaapiupload_details.longname,
284 gst_vaapiupload_details.klass,
285 gst_vaapiupload_details.description,
286 gst_vaapiupload_details.author
290 pad_template = gst_static_pad_template_get(&gst_vaapiupload_sink_factory);
291 gst_element_class_add_pad_template(element_class, pad_template);
292 gst_object_unref(pad_template);
295 pad_template = gst_static_pad_template_get(&gst_vaapiupload_src_factory);
296 gst_element_class_add_pad_template(element_class, pad_template);
297 gst_object_unref(pad_template);
300 * GstVaapiUpload:direct-rendering:
302 * Selects the direct rendering level.
304 * <listitem override="0">
305 * Disables direct rendering.
308 * Enables direct rendering to the output buffer. i.e. this
309 * tries to use a single buffer for both sink and src pads.
312 * Enables direct rendering to the underlying surface. i.e. with
313 * drivers supporting vaDeriveImage(), the output surface pixels
314 * will be modified directly.
318 g_object_class_install_property
320 PROP_DIRECT_RENDERING,
321 g_param_spec_uint("direct-rendering",
323 "Direct rendering level",
325 DIRECT_RENDERING_DEFAULT,
330 gst_vaapiupload_init(GstVaapiUpload *upload)
332 GstPad *sinkpad, *srcpad;
334 upload->display = NULL;
335 upload->images = NULL;
336 upload->images_reset = FALSE;
337 upload->image_width = 0;
338 upload->image_height = 0;
339 upload->surfaces = NULL;
340 upload->surfaces_reset = FALSE;
341 upload->surface_width = 0;
342 upload->surface_height = 0;
343 upload->direct_rendering_caps = 0;
344 upload->direct_rendering = G_MAXUINT32;
346 /* Override buffer allocator on sink pad */
347 sinkpad = gst_element_get_static_pad(GST_ELEMENT(upload), "sink");
348 gst_pad_set_bufferalloc_function(
350 gst_vaapiupload_sinkpad_buffer_alloc
352 gst_pad_set_query_function(sinkpad, gst_vaapiupload_query);
353 g_object_unref(sinkpad);
355 /* Override query on src pad */
356 srcpad = gst_element_get_static_pad(GST_ELEMENT(upload), "src");
357 gst_pad_set_query_function(srcpad, gst_vaapiupload_query);
358 g_object_unref(srcpad);
361 static inline gboolean
362 gst_vaapiupload_ensure_display(GstVaapiUpload *upload)
364 return gst_vaapi_ensure_display(upload, GST_VAAPI_DISPLAY_TYPE_ANY,
369 gst_vaapiupload_start(GstBaseTransform *trans)
371 GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
373 if (!gst_vaapiupload_ensure_display(upload))
379 gst_vaapiupload_stop(GstBaseTransform *trans)
381 GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
383 g_clear_object(&upload->display);
389 gst_vaapiupload_transform(
390 GstBaseTransform *trans,
395 GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
396 GstVaapiVideoBuffer *vbuffer;
397 GstVaapiSurface *surface;
398 GstVaapiImage *image;
399 GstCaps *buffer_caps;
401 GstVaapiImageFormat buffer_format;
402 gboolean format_changed;
404 vbuffer = GST_VAAPI_VIDEO_BUFFER(outbuf);
405 surface = gst_vaapi_video_buffer_get_surface(vbuffer);
407 return GST_FLOW_UNEXPECTED;
409 if (upload->direct_rendering) {
410 if (!GST_VAAPI_IS_VIDEO_BUFFER(inbuf)) {
411 GST_DEBUG("GstVaapiVideoBuffer was expected");
412 return GST_FLOW_UNEXPECTED;
415 vbuffer = GST_VAAPI_VIDEO_BUFFER(inbuf);
416 image = gst_vaapi_video_buffer_get_image(vbuffer);
418 return GST_FLOW_UNEXPECTED;
419 if (!gst_vaapi_image_unmap(image))
420 return GST_FLOW_UNEXPECTED;
422 if (upload->direct_rendering < 2) {
423 if (!gst_vaapi_surface_put_image(surface, image))
424 goto error_put_image;
429 image = gst_vaapi_video_pool_get_object(upload->images);
431 return GST_FLOW_UNEXPECTED;
433 gst_vaapi_image_update_from_buffer(image, inbuf, NULL);
434 success = gst_vaapi_surface_put_image(surface, image);
435 gst_vaapi_video_pool_put_object(upload->images, image);
437 goto error_put_image;
442 GST_WARNING("failed to upload %" GST_FOURCC_FORMAT " image "
444 GST_FOURCC_ARGS(gst_vaapi_image_get_format(image)),
445 gst_vaapi_surface_get_id(surface));
451 gst_vaapi_get_other_support_caps(GstVaapiConvert *upload)
454 caps = gst_caps_from_string(GST_VIDEO_CAPS_YUV("YUY2"));
459 gst_vaapiupload_transform_caps(
460 GstBaseTransform *trans,
461 GstPadDirection direction,
465 GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
466 GstCaps *out_caps = NULL;
467 GstStructure *structure;
469 g_return_val_if_fail(GST_IS_CAPS(caps), NULL);
471 structure = gst_caps_get_structure(caps, 0);
473 if (direction == GST_PAD_SINK) {
474 if (!gst_structure_has_name(structure, "video/x-raw-yuv"))
476 out_caps = gst_caps_from_string(gst_vaapiupload_vaapi_caps_str);
478 structure = gst_caps_get_structure(out_caps, 0);
481 "type", G_TYPE_STRING, "vaapi",
482 "opengl", G_TYPE_BOOLEAN, USE_GLX,
487 if (!gst_structure_has_name(structure, GST_VAAPI_SURFACE_CAPS_NAME))
489 out_caps = gst_caps_from_string(gst_vaapiupload_yuv_caps_str);
490 if (upload->display) {
491 GstCaps *allowed_caps, *inter_caps, *other_caps;
492 allowed_caps = gst_vaapi_display_get_image_caps(upload->display);
495 /* can direct copy other YUV to va surface */
496 other_caps = gst_vaapi_get_other_support_caps(upload);
497 gst_caps_merge(allowed_caps, other_caps);
499 inter_caps = gst_caps_intersect(out_caps, allowed_caps);
500 gst_caps_unref(allowed_caps);
501 gst_caps_unref(out_caps);
502 out_caps = inter_caps;
506 if (!gst_vaapi_append_surface_caps(out_caps, caps)) {
507 gst_caps_unref(out_caps);
514 gst_vaapiupload_ensure_image_pool(GstVaapiUpload *upload, GstCaps *caps)
516 GstStructure * const structure = gst_caps_get_structure(caps, 0);
519 gst_structure_get_int(structure, "width", &width);
520 gst_structure_get_int(structure, "height", &height);
522 if (width != upload->image_width || height != upload->image_height) {
523 upload->image_width = width;
524 upload->image_height = height;
525 g_clear_object(&upload->images);
526 upload->images = gst_vaapi_image_pool_new(upload->display, caps);
529 upload->images_reset = TRUE;
535 gst_vaapiupload_ensure_surface_pool(GstVaapiUpload *upload, GstCaps *caps)
537 GstStructure * const structure = gst_caps_get_structure(caps, 0);
540 gst_structure_get_int(structure, "width", &width);
541 gst_structure_get_int(structure, "height", &height);
543 if (width != upload->surface_width || height != upload->surface_height) {
544 upload->surface_width = width;
545 upload->surface_height = height;
546 g_clear_object(&upload->surfaces);
547 upload->surfaces = gst_vaapi_surface_pool_new(upload->display, caps);
548 if (!upload->surfaces)
550 upload->surfaces_reset = TRUE;
556 gst_vaapiupload_ensure_direct_rendering_caps(
557 GstVaapiUpload *upload,
561 GstVaapiSurface *surface;
562 GstVaapiImage *image;
563 GstVaapiImageFormat vaformat;
564 GstVideoFormat vformat;
565 GstStructure *structure;
568 if (!upload->images_reset && !upload->surfaces_reset)
571 upload->images_reset = FALSE;
572 upload->surfaces_reset = FALSE;
573 upload->direct_rendering_caps = 0;
575 structure = gst_caps_get_structure(caps, 0);
578 gst_structure_get_int(structure, "width", &width);
579 gst_structure_get_int(structure, "height", &height);
581 /* Translate from Gst video format to VA image format */
582 if (!gst_video_format_parse_caps(caps, &vformat, NULL, NULL))
584 if (!gst_video_format_is_yuv(vformat))
586 vaformat = gst_vaapi_image_format_from_video(vformat);
590 /* Check if we can alias sink & output buffers (same data_size) */
591 image = gst_vaapi_video_pool_get_object(upload->images);
593 if (upload->direct_rendering_caps == 0 &&
594 (gst_vaapi_image_get_format(image) == vaformat &&
595 gst_vaapi_image_is_linear(image) &&
596 (gst_vaapi_image_get_data_size(image) ==
597 gst_video_format_get_size(vformat, width, height))))
598 upload->direct_rendering_caps = 1;
599 gst_vaapi_video_pool_put_object(upload->images, image);
602 /* Check if we can access to the surface pixels directly */
603 surface = gst_vaapi_video_pool_get_object(upload->surfaces);
605 image = gst_vaapi_surface_derive_image(surface);
607 if (gst_vaapi_image_map(image)) {
608 if (upload->direct_rendering_caps == 1 &&
609 (gst_vaapi_image_get_format(image) == vaformat &&
610 gst_vaapi_image_is_linear(image) &&
611 (gst_vaapi_image_get_data_size(image) ==
612 gst_video_format_get_size(vformat, width, height))))
613 upload->direct_rendering_caps = 2;
614 gst_vaapi_image_unmap(image);
616 g_object_unref(image);
618 gst_vaapi_video_pool_put_object(upload->surfaces, surface);
623 gst_vaapiupload_negotiate_buffers(
624 GstVaapiUpload *upload,
631 if (!gst_vaapiupload_ensure_image_pool(upload, incaps))
634 if (!gst_vaapiupload_ensure_surface_pool(upload, outcaps))
637 if (upload->direct_rendering)
638 gst_vaapiupload_ensure_direct_rendering_caps(upload, incaps);
639 dr = MIN(upload->direct_rendering, upload->direct_rendering_caps);
640 if (upload->direct_rendering != dr) {
641 upload->direct_rendering = dr;
646 gst_vaapiupload_set_caps(
647 GstBaseTransform *trans,
652 GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
654 if (!gst_vaapiupload_negotiate_buffers(upload, incaps, outcaps))
657 GST_INFO("set caps\nIN caps:\n%" GST_PTR_FORMAT "\nOUT caps:\n%" GST_PTR_FORMAT,
663 gst_vaapiupload_get_unit_size(
664 GstBaseTransform *trans,
669 GstStructure * const structure = gst_caps_get_structure(caps, 0);
670 GstVideoFormat format;
673 if (gst_structure_has_name(structure, GST_VAAPI_SURFACE_CAPS_NAME))
676 if (!gst_video_format_parse_caps(caps, &format, &width, &height))
678 *size = gst_video_format_get_size(format, width, height);
684 gst_vaapiupload_buffer_alloc(
685 GstBaseTransform *trans,
691 GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
692 GstBuffer *buffer = NULL;
693 GstVaapiImage *image = NULL;
694 GstVaapiSurface *surface = NULL;
695 GstVaapiVideoBuffer *vbuffer;
697 /* Check if we can use direct-rendering */
698 if (!gst_vaapiupload_negotiate_buffers(upload, caps, caps))
700 if (!upload->direct_rendering)
703 switch (upload->direct_rendering) {
705 buffer = gst_vaapi_video_buffer_new_from_pool(upload->surfaces);
708 vbuffer = GST_VAAPI_VIDEO_BUFFER(buffer);
710 surface = gst_vaapi_video_buffer_get_surface(vbuffer);
711 image = gst_vaapi_surface_derive_image(surface);
712 if (image && gst_vaapi_image_get_data_size(image) == size) {
713 gst_vaapi_video_buffer_set_image(vbuffer, image);
714 g_object_unref(image); /* video buffer owns an extra reference */
718 /* We can't use the derive-image optimization. Disable it. */
719 upload->direct_rendering = 1;
720 gst_buffer_unref(buffer);
724 buffer = gst_vaapi_video_buffer_new_from_pool(upload->images);
727 vbuffer = GST_VAAPI_VIDEO_BUFFER(buffer);
729 image = gst_vaapi_video_buffer_get_image(vbuffer);
734 if (!gst_vaapi_image_map(image))
737 GST_BUFFER_DATA(buffer) = gst_vaapi_image_get_plane(image, 0);
738 GST_BUFFER_SIZE(buffer) = gst_vaapi_image_get_data_size(image);
740 gst_buffer_set_caps(buffer, caps);
745 /* We can't use the inout-buffers optimization. Disable it. */
746 GST_DEBUG("disable in/out buffer optimization");
748 gst_buffer_unref(buffer);
749 upload->direct_rendering = 0;
754 gst_vaapiupload_sinkpad_buffer_alloc(
762 GstBaseTransform *trans;
765 trans = GST_BASE_TRANSFORM(gst_pad_get_parent_element(pad));
767 return GST_FLOW_UNEXPECTED;
769 ret = gst_vaapiupload_buffer_alloc(trans, size, caps, pbuf);
770 g_object_unref(trans);
775 gst_vaapiupload_prepare_output_buffer(
776 GstBaseTransform *trans,
783 GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
784 GstBuffer *buffer = NULL;
786 if (upload->direct_rendering == 2) {
787 if (GST_VAAPI_IS_VIDEO_BUFFER(inbuf)) {
788 buffer = gst_vaapi_video_buffer_new_from_buffer(inbuf);
789 GST_BUFFER_SIZE(buffer) = size;
792 GST_DEBUG("upstream element destroyed our in/out buffer");
793 upload->direct_rendering = 1;
798 buffer = gst_vaapi_video_buffer_new_from_pool(upload->surfaces);
800 return GST_FLOW_UNEXPECTED;
801 gst_buffer_set_caps(buffer, caps);
809 gst_vaapiupload_query(GstPad *pad, GstQuery *query)
811 GstVaapiUpload *upload = GST_VAAPIUPLOAD (gst_pad_get_parent_element (pad));
814 GST_DEBUG ("sharing display %p", upload->display);
816 if (gst_vaapi_reply_to_query (query, upload->display))
819 res = gst_pad_query_default (pad, query);
821 g_object_unref (upload);