support YUY2 convert to surface
[profile/ivi/gstreamer-vaapi.git] / gst / vaapi / gstvaapiupload.c
1 /*
2  *  gstvaapiupload.c - VA-API video uploader
3  *
4  *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5  *  Copyright (C) 2011-2012 Intel Corporation
6  *
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.
11  *
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.
16  *
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
21  */
22
23 /**
24  * SECTION:gstvaapiupload
25  * @short_description: A video to VA flow filter
26  *
27  * vaapiupload uploads from raw YUV pixels to VA surfaces suitable
28  * for the vaapisink element, for example.
29  */
30
31 #include "gst/vaapi/sysdeps.h"
32 #include <gst/gst.h>
33 #include <gst/video/video.h>
34 #include <gst/video/videocontext.h>
35 #include <gst/vaapi/gstvaapivideobuffer.h>
36
37 #include "gstvaapiupload.h"
38 #include "gstvaapipluginutil.h"
39 #include "gstvaapipluginbuffer.h"
40
41 #define GST_PLUGIN_NAME "vaapiupload"
42 #define GST_PLUGIN_DESC "A video to VA flow filter"
43
44 GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapiupload);
45 #define GST_CAT_DEFAULT gst_debug_vaapiupload
46
47 /* ElementFactory information */
48 static const GstElementDetails gst_vaapiupload_details =
49     GST_ELEMENT_DETAILS(
50         "VA-API colorspace uploader",
51         "Filter/Converter/Video",
52         GST_PLUGIN_DESC,
53         "Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
54
55 /* Default templates */
56 static const char gst_vaapiupload_yuv_caps_str[] =
57     "video/x-raw-yuv, "
58     "width  = (int) [ 1, MAX ], "
59     "height = (int) [ 1, MAX ]; ";
60
61 static const char gst_vaapiupload_vaapi_caps_str[] =
62     GST_VAAPI_SURFACE_CAPS;
63
64 static GstStaticPadTemplate gst_vaapiupload_sink_factory =
65     GST_STATIC_PAD_TEMPLATE(
66         "sink",
67         GST_PAD_SINK,
68         GST_PAD_ALWAYS,
69         GST_STATIC_CAPS(gst_vaapiupload_yuv_caps_str));
70
71 static GstStaticPadTemplate gst_vaapiupload_src_factory =
72     GST_STATIC_PAD_TEMPLATE(
73         "src",
74         GST_PAD_SRC,
75         GST_PAD_ALWAYS,
76         GST_STATIC_CAPS(gst_vaapiupload_vaapi_caps_str));
77
78 static void
79 gst_vaapiupload_implements_iface_init(GstImplementsInterfaceClass *iface);
80
81 static void
82 gst_video_context_interface_init(GstVideoContextInterface *iface);
83
84 #define GstVideoContextClass GstVideoContextInterface
85 G_DEFINE_TYPE_WITH_CODE(
86     GstVaapiUpload,
87     gst_vaapiupload,
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))
93
94 /*
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)
99  */
100 #define DIRECT_RENDERING_DEFAULT 2
101
102 enum {
103     PROP_0,
104
105     PROP_DIRECT_RENDERING,
106 };
107
108 static gboolean
109 gst_vaapiupload_start(GstBaseTransform *trans);
110
111 static gboolean
112 gst_vaapiupload_stop(GstBaseTransform *trans);
113
114 static GstFlowReturn
115 gst_vaapiupload_transform(
116     GstBaseTransform *trans,
117     GstBuffer        *inbuf,
118     GstBuffer        *outbuf
119 );
120
121 static GstCaps *
122 gst_vaapiupload_transform_caps(
123     GstBaseTransform *trans,
124     GstPadDirection   direction,
125     GstCaps          *caps
126 );
127
128 static gboolean
129 gst_vaapiupload_set_caps(
130     GstBaseTransform *trans,
131     GstCaps          *incaps,
132     GstCaps          *outcaps
133 );
134
135 static gboolean
136 gst_vaapiupload_get_unit_size(
137     GstBaseTransform *trans,
138     GstCaps          *caps,
139     guint            *size
140 );
141
142 static GstFlowReturn
143 gst_vaapiupload_sinkpad_buffer_alloc(
144     GstPad           *pad,
145     guint64           offset,
146     guint             size,
147     GstCaps          *caps,
148     GstBuffer       **pbuf
149 );
150
151 static GstFlowReturn
152 gst_vaapiupload_prepare_output_buffer(
153     GstBaseTransform *trans,
154     GstBuffer        *inbuf,
155     gint              size,
156     GstCaps          *caps,
157     GstBuffer       **poutbuf
158 );
159
160 static gboolean
161 gst_vaapiupload_query(
162     GstPad   *pad,
163     GstQuery *query
164 );
165
166 /* GstImplementsInterface interface */
167
168 static gboolean
169 gst_vaapiupload_implements_interface_supported(
170     GstImplementsInterface *iface,
171     GType                   type
172 )
173 {
174     return (type == GST_TYPE_VIDEO_CONTEXT);
175 }
176
177 static void
178 gst_vaapiupload_implements_iface_init(GstImplementsInterfaceClass *iface)
179 {
180     iface->supported = gst_vaapiupload_implements_interface_supported;
181 }
182
183 /* GstVideoContext interface */
184
185 static void
186 gst_vaapiupload_set_video_context(GstVideoContext *context, const gchar *type,
187     const GValue *value)
188 {
189   GstVaapiUpload *upload = GST_VAAPIUPLOAD (context);
190   gst_vaapi_set_display (type, value, &upload->display);
191 }
192
193 static void
194 gst_video_context_interface_init(GstVideoContextInterface *iface)
195 {
196     iface->set_context = gst_vaapiupload_set_video_context;
197 }
198
199 static void
200 gst_vaapiupload_destroy(GstVaapiUpload *upload)
201 {
202     g_clear_object(&upload->images);
203     g_clear_object(&upload->surfaces);
204     g_clear_object(&upload->display);
205 }
206
207 static void
208 gst_vaapiupload_finalize(GObject *object)
209 {
210     gst_vaapiupload_destroy(GST_VAAPIUPLOAD(object));
211
212     G_OBJECT_CLASS(gst_vaapiupload_parent_class)->finalize(object);
213 }
214
215
216 static void
217 gst_vaapiupload_set_property(
218     GObject      *object,
219     guint         prop_id,
220     const GValue *value,
221     GParamSpec   *pspec
222 )
223 {
224     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(object);
225
226     switch (prop_id) {
227     case PROP_DIRECT_RENDERING:
228         GST_OBJECT_LOCK(upload);
229         upload->direct_rendering = g_value_get_uint(value);
230         GST_OBJECT_UNLOCK(upload);
231         break;
232     default:
233         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
234         break;
235     }
236 }
237
238 static void
239 gst_vaapiupload_get_property(
240     GObject    *object,
241     guint       prop_id,
242     GValue     *value,
243     GParamSpec *pspec
244 )
245 {
246     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(object);
247
248     switch (prop_id) {
249     case PROP_DIRECT_RENDERING:
250         g_value_set_uint(value, upload->direct_rendering);
251         break;
252     default:
253         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
254         break;
255     }
256 }
257
258 static void
259 gst_vaapiupload_class_init(GstVaapiUploadClass *klass)
260 {
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;
265
266     GST_DEBUG_CATEGORY_INIT(gst_debug_vaapiupload,
267                             GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
268
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;
272
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;
280
281     gst_element_class_set_details_simple(
282         element_class,
283         gst_vaapiupload_details.longname,
284         gst_vaapiupload_details.klass,
285         gst_vaapiupload_details.description,
286         gst_vaapiupload_details.author
287     );
288
289     /* sink pad */
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);
293
294     /* src pad */
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);
298
299     /**
300      * GstVaapiUpload:direct-rendering:
301      *
302      * Selects the direct rendering level.
303      * <orderedlist>
304      * <listitem override="0">
305      *   Disables direct rendering.
306      * </listitem>
307      * <listitem>
308      *   Enables direct rendering to the output buffer. i.e. this
309      *   tries to use a single buffer for both sink and src pads.
310      * </listitem>
311      * <listitem>
312      *   Enables direct rendering to the underlying surface. i.e. with
313      *   drivers supporting vaDeriveImage(), the output surface pixels
314      *   will be modified directly.
315      * </listitem>
316      * </orderedlist>
317      */
318     g_object_class_install_property
319         (object_class,
320          PROP_DIRECT_RENDERING,
321          g_param_spec_uint("direct-rendering",
322                            "Direct rendering",
323                            "Direct rendering level",
324                            0, 2,
325                            DIRECT_RENDERING_DEFAULT,
326                            G_PARAM_READWRITE));
327 }
328
329 static void
330 gst_vaapiupload_init(GstVaapiUpload *upload)
331 {
332     GstPad *sinkpad, *srcpad;
333
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;
345
346     /* Override buffer allocator on sink pad */
347     sinkpad = gst_element_get_static_pad(GST_ELEMENT(upload), "sink");
348     gst_pad_set_bufferalloc_function(
349         sinkpad,
350         gst_vaapiupload_sinkpad_buffer_alloc
351     );
352     gst_pad_set_query_function(sinkpad, gst_vaapiupload_query);
353     g_object_unref(sinkpad);
354
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);
359 }
360
361 static inline gboolean
362 gst_vaapiupload_ensure_display(GstVaapiUpload *upload)
363 {
364     return gst_vaapi_ensure_display(upload, GST_VAAPI_DISPLAY_TYPE_ANY,
365         &upload->display);
366 }
367
368 static gboolean
369 gst_vaapiupload_start(GstBaseTransform *trans)
370 {
371     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
372
373     if (!gst_vaapiupload_ensure_display(upload))
374         return FALSE;
375     return TRUE;
376 }
377
378 static gboolean
379 gst_vaapiupload_stop(GstBaseTransform *trans)
380 {
381     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
382
383     g_clear_object(&upload->display);
384
385     return TRUE;
386 }
387
388 static GstFlowReturn
389 gst_vaapiupload_transform(
390     GstBaseTransform *trans,
391     GstBuffer        *inbuf,
392     GstBuffer        *outbuf
393 )
394 {
395     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
396     GstVaapiVideoBuffer *vbuffer;
397     GstVaapiSurface *surface;
398     GstVaapiImage *image;
399     GstCaps *buffer_caps;
400     gboolean success;
401     GstVaapiImageFormat buffer_format;
402     gboolean format_changed;
403
404     vbuffer = GST_VAAPI_VIDEO_BUFFER(outbuf);
405     surface = gst_vaapi_video_buffer_get_surface(vbuffer);
406     if (!surface)
407         return GST_FLOW_UNEXPECTED;
408
409     if (upload->direct_rendering) {
410         if (!GST_VAAPI_IS_VIDEO_BUFFER(inbuf)) {
411             GST_DEBUG("GstVaapiVideoBuffer was expected");
412             return GST_FLOW_UNEXPECTED;
413         }
414
415         vbuffer = GST_VAAPI_VIDEO_BUFFER(inbuf);
416         image   = gst_vaapi_video_buffer_get_image(vbuffer);
417         if (!image)
418             return GST_FLOW_UNEXPECTED;
419         if (!gst_vaapi_image_unmap(image))
420             return GST_FLOW_UNEXPECTED;
421
422         if (upload->direct_rendering < 2) {
423             if (!gst_vaapi_surface_put_image(surface, image))
424                 goto error_put_image;
425         }
426         return GST_FLOW_OK;
427     }
428
429     image = gst_vaapi_video_pool_get_object(upload->images);
430     if (!image)
431         return GST_FLOW_UNEXPECTED;
432
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);
436     if (!success)
437         goto error_put_image;
438     return GST_FLOW_OK;
439
440 error_put_image:
441     {
442         GST_WARNING("failed to upload %" GST_FOURCC_FORMAT " image "
443                     "to surface 0x%08x",
444                     GST_FOURCC_ARGS(gst_vaapi_image_get_format(image)),
445                     gst_vaapi_surface_get_id(surface));
446         return GST_FLOW_OK;
447     }
448 }
449
450 static GstCaps *
451 gst_vaapi_get_other_support_caps(GstVaapiConvert *upload)
452 {
453   GstCaps *caps;
454   caps = gst_caps_from_string(GST_VIDEO_CAPS_YUV("YUY2"));
455   return caps;
456 }
457
458 static GstCaps *
459 gst_vaapiupload_transform_caps(
460     GstBaseTransform *trans,
461     GstPadDirection   direction,
462     GstCaps          *caps
463 )
464 {
465     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
466     GstCaps *out_caps = NULL;
467     GstStructure *structure;
468
469     g_return_val_if_fail(GST_IS_CAPS(caps), NULL);
470
471     structure = gst_caps_get_structure(caps, 0);
472
473     if (direction == GST_PAD_SINK) {
474         if (!gst_structure_has_name(structure, "video/x-raw-yuv"))
475             return NULL;
476         out_caps = gst_caps_from_string(gst_vaapiupload_vaapi_caps_str);
477
478         structure = gst_caps_get_structure(out_caps, 0);
479         gst_structure_set(
480             structure,
481             "type", G_TYPE_STRING, "vaapi",
482             "opengl", G_TYPE_BOOLEAN, USE_GLX,
483             NULL
484         );
485     }
486     else {
487         if (!gst_structure_has_name(structure, GST_VAAPI_SURFACE_CAPS_NAME))
488             return NULL;
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);
493             if (!allowed_caps)
494                 return NULL;
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);
498
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;
503         }
504     }
505
506     if (!gst_vaapi_append_surface_caps(out_caps, caps)) {
507         gst_caps_unref(out_caps);
508         return NULL;
509     }
510     return out_caps;
511 }
512
513 static gboolean
514 gst_vaapiupload_ensure_image_pool(GstVaapiUpload *upload, GstCaps *caps)
515 {
516     GstStructure * const structure = gst_caps_get_structure(caps, 0);
517     gint width, height;
518
519     gst_structure_get_int(structure, "width",  &width);
520     gst_structure_get_int(structure, "height", &height);
521
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);
527         if (!upload->images)
528             return FALSE;
529         upload->images_reset = TRUE;
530     }
531     return TRUE;
532 }
533
534 static gboolean
535 gst_vaapiupload_ensure_surface_pool(GstVaapiUpload *upload, GstCaps *caps)
536 {
537     GstStructure * const structure = gst_caps_get_structure(caps, 0);
538     gint width, height;
539
540     gst_structure_get_int(structure, "width",  &width);
541     gst_structure_get_int(structure, "height", &height);
542
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)
549             return FALSE;
550         upload->surfaces_reset = TRUE;
551     }
552     return TRUE;
553 }
554
555 static void
556 gst_vaapiupload_ensure_direct_rendering_caps(
557     GstVaapiUpload *upload,
558     GstCaps         *caps
559 )
560 {
561     GstVaapiSurface *surface;
562     GstVaapiImage *image;
563     GstVaapiImageFormat vaformat;
564     GstVideoFormat vformat;
565     GstStructure *structure;
566     gint width, height;
567
568     if (!upload->images_reset && !upload->surfaces_reset)
569         return;
570
571     upload->images_reset          = FALSE;
572     upload->surfaces_reset        = FALSE;
573     upload->direct_rendering_caps = 0;
574
575     structure = gst_caps_get_structure(caps, 0);
576     if (!structure)
577         return;
578     gst_structure_get_int(structure, "width",  &width);
579     gst_structure_get_int(structure, "height", &height);
580
581     /* Translate from Gst video format to VA image format */
582     if (!gst_video_format_parse_caps(caps, &vformat, NULL, NULL))
583         return;
584     if (!gst_video_format_is_yuv(vformat))
585         return;
586     vaformat = gst_vaapi_image_format_from_video(vformat);
587     if (!vaformat)
588         return;
589
590     /* Check if we can alias sink & output buffers (same data_size) */
591     image = gst_vaapi_video_pool_get_object(upload->images);
592     if (image) {
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);
600     }
601
602     /* Check if we can access to the surface pixels directly */
603     surface = gst_vaapi_video_pool_get_object(upload->surfaces);
604     if (surface) {
605         image = gst_vaapi_surface_derive_image(surface);
606         if (image) {
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);
615             }
616             g_object_unref(image);
617         }
618         gst_vaapi_video_pool_put_object(upload->surfaces, surface);
619     }
620 }
621
622 static gboolean
623 gst_vaapiupload_negotiate_buffers(
624     GstVaapiUpload  *upload,
625     GstCaps          *incaps,
626     GstCaps          *outcaps
627 )
628 {
629     guint dr;
630
631     if (!gst_vaapiupload_ensure_image_pool(upload, incaps))
632         return FALSE;
633
634     if (!gst_vaapiupload_ensure_surface_pool(upload, outcaps))
635         return FALSE;
636
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;
642     return TRUE;
643 }
644
645 static gboolean
646 gst_vaapiupload_set_caps(
647     GstBaseTransform *trans,
648     GstCaps          *incaps,
649     GstCaps          *outcaps
650 )
651 {
652     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
653
654     if (!gst_vaapiupload_negotiate_buffers(upload, incaps, outcaps))
655         return FALSE;
656
657     GST_INFO("set caps\nIN caps:\n%" GST_PTR_FORMAT "\nOUT caps:\n%" GST_PTR_FORMAT,
658              incaps, outcaps);
659     return TRUE;
660 }
661
662 static gboolean
663 gst_vaapiupload_get_unit_size(
664     GstBaseTransform *trans,
665     GstCaps          *caps,
666     guint            *size
667 )
668 {
669     GstStructure * const structure = gst_caps_get_structure(caps, 0);
670     GstVideoFormat format;
671     gint width, height;
672
673     if (gst_structure_has_name(structure, GST_VAAPI_SURFACE_CAPS_NAME))
674         *size = 0;
675     else {
676         if (!gst_video_format_parse_caps(caps, &format, &width, &height))
677             return FALSE;
678         *size = gst_video_format_get_size(format, width, height);
679     }
680     return TRUE;
681 }
682
683 static GstFlowReturn
684 gst_vaapiupload_buffer_alloc(
685     GstBaseTransform *trans,
686     guint             size,
687     GstCaps          *caps,
688     GstBuffer       **pbuf
689 )
690 {
691     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
692     GstBuffer *buffer = NULL;
693     GstVaapiImage *image = NULL;
694     GstVaapiSurface *surface = NULL;
695     GstVaapiVideoBuffer *vbuffer;
696
697     /* Check if we can use direct-rendering */
698     if (!gst_vaapiupload_negotiate_buffers(upload, caps, caps))
699         goto error;
700     if (!upload->direct_rendering)
701         return GST_FLOW_OK;
702
703     switch (upload->direct_rendering) {
704     case 2:
705         buffer  = gst_vaapi_video_buffer_new_from_pool(upload->surfaces);
706         if (!buffer)
707             goto error;
708         vbuffer = GST_VAAPI_VIDEO_BUFFER(buffer);
709
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 */
715             break;
716         }
717
718         /* We can't use the derive-image optimization. Disable it. */
719         upload->direct_rendering = 1;
720         gst_buffer_unref(buffer);
721         buffer = NULL;
722
723     case 1:
724         buffer  = gst_vaapi_video_buffer_new_from_pool(upload->images);
725         if (!buffer)
726             goto error;
727         vbuffer = GST_VAAPI_VIDEO_BUFFER(buffer);
728
729         image   = gst_vaapi_video_buffer_get_image(vbuffer);
730         break;
731     }
732     g_assert(image);
733
734     if (!gst_vaapi_image_map(image))
735         goto error;
736
737     GST_BUFFER_DATA(buffer) = gst_vaapi_image_get_plane(image, 0);
738     GST_BUFFER_SIZE(buffer) = gst_vaapi_image_get_data_size(image);
739
740     gst_buffer_set_caps(buffer, caps);
741     *pbuf = buffer;
742     return GST_FLOW_OK;
743
744 error:
745     /* We can't use the inout-buffers optimization. Disable it. */
746     GST_DEBUG("disable in/out buffer optimization");
747     if (buffer)
748         gst_buffer_unref(buffer);
749     upload->direct_rendering = 0;
750     return GST_FLOW_OK;
751 }
752
753 static GstFlowReturn
754 gst_vaapiupload_sinkpad_buffer_alloc(
755     GstPad           *pad,
756     guint64           offset,
757     guint             size,
758     GstCaps          *caps,
759     GstBuffer       **pbuf
760 )
761 {
762     GstBaseTransform *trans;
763     GstFlowReturn ret;
764
765     trans = GST_BASE_TRANSFORM(gst_pad_get_parent_element(pad));
766     if (!trans)
767         return GST_FLOW_UNEXPECTED;
768
769     ret = gst_vaapiupload_buffer_alloc(trans, size, caps, pbuf);
770     g_object_unref(trans);
771     return ret;
772 }
773
774 static GstFlowReturn
775 gst_vaapiupload_prepare_output_buffer(
776     GstBaseTransform *trans,
777     GstBuffer        *inbuf,
778     gint              size,
779     GstCaps          *caps,
780     GstBuffer       **poutbuf
781 )
782 {
783     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
784     GstBuffer *buffer = NULL;
785
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;
790         }
791         else {
792             GST_DEBUG("upstream element destroyed our in/out buffer");
793             upload->direct_rendering = 1;
794         }
795     }
796
797     if (!buffer) {
798         buffer = gst_vaapi_video_buffer_new_from_pool(upload->surfaces);
799         if (!buffer)
800             return GST_FLOW_UNEXPECTED;
801         gst_buffer_set_caps(buffer, caps);
802     }
803
804     *poutbuf = buffer;
805     return GST_FLOW_OK;
806 }
807
808 static gboolean
809 gst_vaapiupload_query(GstPad *pad, GstQuery *query)
810 {
811   GstVaapiUpload *upload = GST_VAAPIUPLOAD (gst_pad_get_parent_element (pad));
812   gboolean res;
813
814   GST_DEBUG ("sharing display %p", upload->display);
815
816   if (gst_vaapi_reply_to_query (query, upload->display))
817     res = TRUE;
818   else
819     res = gst_pad_query_default (pad, query);
820
821   g_object_unref (upload);
822   return res;
823 }