9e5d513dcf985517b0352f85601eccf8b7a27235
[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 converts from raw YUV pixels to VA surfaces suitable
28  * for the vaapisink element, for example.
29  */
30
31 #include "config.h"
32
33 #include <gst/gst.h>
34 #include <gst/video/video.h>
35 #include <gst/video/videocontext.h>
36 #include <gst/vaapi/gstvaapivideosink.h>
37 #include <gst/vaapi/gstvaapivideobuffer.h>
38
39 #if USE_GLX
40 #include <gst/vaapi/gstvaapivideobuffer_glx.h>
41 #define gst_vaapi_video_buffer_new_from_pool(pool) \
42     gst_vaapi_video_buffer_glx_new_from_pool(pool)
43 #define gst_vaapi_video_buffer_new_from_buffer(buffer) \
44     gst_vaapi_video_buffer_glx_new_from_buffer(buffer)
45 #endif
46
47 #include "gstvaapipluginutil.h"
48 #include "gstvaapiupload.h"
49
50 #define GST_PLUGIN_NAME "vaapiupload"
51 #define GST_PLUGIN_DESC "A video to VA flow filter"
52
53 GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapiupload);
54 #define GST_CAT_DEFAULT gst_debug_vaapiupload
55
56 /* ElementFactory information */
57 static const GstElementDetails gst_vaapiupload_details =
58     GST_ELEMENT_DETAILS(
59         "VA-API colorspace converter",
60         "Filter/Converter/Video",
61         GST_PLUGIN_DESC,
62         "Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
63
64 /* Default templates */
65 static const char gst_vaapiupload_yuv_caps_str[] =
66     "video/x-raw-yuv, "
67     "width  = (int) [ 1, MAX ], "
68     "height = (int) [ 1, MAX ]; ";
69
70 static const char gst_vaapiupload_vaapi_caps_str[] =
71     GST_VAAPI_SURFACE_CAPS;
72
73 static GstStaticPadTemplate gst_vaapiupload_sink_factory =
74     GST_STATIC_PAD_TEMPLATE(
75         "sink",
76         GST_PAD_SINK,
77         GST_PAD_ALWAYS,
78         GST_STATIC_CAPS(gst_vaapiupload_yuv_caps_str));
79
80 static GstStaticPadTemplate gst_vaapiupload_src_factory =
81     GST_STATIC_PAD_TEMPLATE(
82         "src",
83         GST_PAD_SRC,
84         GST_PAD_ALWAYS,
85         GST_STATIC_CAPS(gst_vaapiupload_vaapi_caps_str));
86
87 static void
88 gst_vaapiupload_implements_iface_init(GstImplementsInterfaceClass *iface);
89
90 static void
91 gst_video_context_interface_init(GstVideoContextInterface *iface);
92
93 #define GstVideoContextClass GstVideoContextInterface
94 G_DEFINE_TYPE_WITH_CODE(
95     GstVaapiUpload,
96     gst_vaapiupload,
97     GST_TYPE_BASE_TRANSFORM,
98     G_IMPLEMENT_INTERFACE(GST_TYPE_IMPLEMENTS_INTERFACE,
99                           gst_vaapiupload_implements_iface_init);
100     G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_CONTEXT,
101                           gst_video_context_interface_init));
102
103 /*
104  * Direct rendering levels (direct-rendering)
105  * 0: upstream allocated YUV pixels
106  * 1: vaapiupload allocated YUV pixels (mapped from VA image)
107  * 2: vaapiupload allocated YUV pixels (mapped from VA surface)
108  */
109 #define DIRECT_RENDERING_DEFAULT 2
110
111 enum {
112     PROP_0,
113
114     PROP_DIRECT_RENDERING,
115 };
116
117 static gboolean
118 gst_vaapiupload_start(GstBaseTransform *trans);
119
120 static gboolean
121 gst_vaapiupload_stop(GstBaseTransform *trans);
122
123 static GstFlowReturn
124 gst_vaapiupload_transform(
125     GstBaseTransform *trans,
126     GstBuffer        *inbuf,
127     GstBuffer        *outbuf
128 );
129
130 static GstCaps *
131 gst_vaapiupload_transform_caps(
132     GstBaseTransform *trans,
133     GstPadDirection   direction,
134     GstCaps          *caps
135 );
136
137 static gboolean
138 gst_vaapiupload_set_caps(
139     GstBaseTransform *trans,
140     GstCaps          *incaps,
141     GstCaps          *outcaps
142 );
143
144 static gboolean
145 gst_vaapiupload_get_unit_size(
146     GstBaseTransform *trans,
147     GstCaps          *caps,
148     guint            *size
149 );
150
151 static GstFlowReturn
152 gst_vaapiupload_sinkpad_buffer_alloc(
153     GstPad           *pad,
154     guint64           offset,
155     guint             size,
156     GstCaps          *caps,
157     GstBuffer       **pbuf
158 );
159
160 static GstFlowReturn
161 gst_vaapiupload_prepare_output_buffer(
162     GstBaseTransform *trans,
163     GstBuffer        *inbuf,
164     gint              size,
165     GstCaps          *caps,
166     GstBuffer       **poutbuf
167 );
168
169 static gboolean
170 gst_vaapiupload_query(
171     GstPad   *pad,
172     GstQuery *query
173 );
174
175 /* GstImplementsInterface interface */
176
177 static gboolean
178 gst_vaapiupload_implements_interface_supported(
179     GstImplementsInterface *iface,
180     GType                   type
181 )
182 {
183     return (type == GST_TYPE_VIDEO_CONTEXT);
184 }
185
186 static void
187 gst_vaapiupload_implements_iface_init(GstImplementsInterfaceClass *iface)
188 {
189     iface->supported = gst_vaapiupload_implements_interface_supported;
190 }
191
192 /* GstVideoContext interface */
193
194 static void
195 gst_vaapiupload_set_video_context(GstVideoContext *context, const gchar *type,
196     const GValue *value)
197 {
198   GstVaapiUpload *upload = GST_VAAPIUPLOAD (context);
199   gst_vaapi_set_display (type, value, &upload->display);
200 }
201
202 static void
203 gst_video_context_interface_init(GstVideoContextInterface *iface)
204 {
205     iface->set_context = gst_vaapiupload_set_video_context;
206 }
207
208 static void
209 gst_vaapiupload_destroy(GstVaapiUpload *upload)
210 {
211     g_clear_object(&upload->images);
212     g_clear_object(&upload->surfaces);
213     g_clear_object(&upload->display);
214 }
215
216 static void
217 gst_vaapiupload_finalize(GObject *object)
218 {
219     gst_vaapiupload_destroy(GST_VAAPIUPLOAD(object));
220
221     G_OBJECT_CLASS(gst_vaapiupload_parent_class)->finalize(object);
222 }
223
224
225 static void
226 gst_vaapiupload_set_property(
227     GObject      *object,
228     guint         prop_id,
229     const GValue *value,
230     GParamSpec   *pspec
231 )
232 {
233     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(object);
234
235     switch (prop_id) {
236     case PROP_DIRECT_RENDERING:
237         GST_OBJECT_LOCK(upload);
238         upload->direct_rendering = g_value_get_uint(value);
239         GST_OBJECT_UNLOCK(upload);
240         break;
241     default:
242         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
243         break;
244     }
245 }
246
247 static void
248 gst_vaapiupload_get_property(
249     GObject    *object,
250     guint       prop_id,
251     GValue     *value,
252     GParamSpec *pspec
253 )
254 {
255     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(object);
256
257     switch (prop_id) {
258     case PROP_DIRECT_RENDERING:
259         g_value_set_uint(value, upload->direct_rendering);
260         break;
261     default:
262         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
263         break;
264     }
265 }
266
267 static void
268 gst_vaapiupload_class_init(GstVaapiUploadClass *klass)
269 {
270     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
271     GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
272     GstBaseTransformClass * const trans_class = GST_BASE_TRANSFORM_CLASS(klass);
273     GstPadTemplate *pad_template;
274
275     GST_DEBUG_CATEGORY_INIT(gst_debug_vaapiupload,
276                             GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
277
278     object_class->finalize      = gst_vaapiupload_finalize;
279     object_class->set_property  = gst_vaapiupload_set_property;
280     object_class->get_property  = gst_vaapiupload_get_property;
281
282     trans_class->start          = gst_vaapiupload_start;
283     trans_class->stop           = gst_vaapiupload_stop;
284     trans_class->transform      = gst_vaapiupload_transform;
285     trans_class->transform_caps = gst_vaapiupload_transform_caps;
286     trans_class->set_caps       = gst_vaapiupload_set_caps;
287     trans_class->get_unit_size  = gst_vaapiupload_get_unit_size;
288     trans_class->prepare_output_buffer = gst_vaapiupload_prepare_output_buffer;
289
290     gst_element_class_set_details_simple(
291         element_class,
292         gst_vaapiupload_details.longname,
293         gst_vaapiupload_details.klass,
294         gst_vaapiupload_details.description,
295         gst_vaapiupload_details.author
296     );
297
298     /* sink pad */
299     pad_template = gst_static_pad_template_get(&gst_vaapiupload_sink_factory);
300     gst_element_class_add_pad_template(element_class, pad_template);
301     gst_object_unref(pad_template);
302
303     /* src pad */
304     pad_template = gst_static_pad_template_get(&gst_vaapiupload_src_factory);
305     gst_element_class_add_pad_template(element_class, pad_template);
306     gst_object_unref(pad_template);
307
308     /**
309      * GstVaapiUpload:direct-rendering:
310      *
311      * Selects the direct rendering level.
312      * <orderedlist>
313      * <listitem override="0">
314      *   Disables direct rendering.
315      * </listitem>
316      * <listitem>
317      *   Enables direct rendering to the output buffer. i.e. this
318      *   tries to use a single buffer for both sink and src pads.
319      * </listitem>
320      * <listitem>
321      *   Enables direct rendering to the underlying surface. i.e. with
322      *   drivers supporting vaDeriveImage(), the output surface pixels
323      *   will be modified directly.
324      * </listitem>
325      * </orderedlist>
326      */
327     g_object_class_install_property
328         (object_class,
329          PROP_DIRECT_RENDERING,
330          g_param_spec_uint("direct-rendering",
331                            "Direct rendering",
332                            "Direct rendering level",
333                            0, 2,
334                            DIRECT_RENDERING_DEFAULT,
335                            G_PARAM_READWRITE));
336 }
337
338 static void
339 gst_vaapiupload_init(GstVaapiUpload *upload)
340 {
341     GstPad *sinkpad, *srcpad;
342
343     upload->display                     = NULL;
344     upload->images                      = NULL;
345     upload->images_reset                = FALSE;
346     upload->image_width                 = 0;
347     upload->image_height                = 0;
348     upload->surfaces                    = NULL;
349     upload->surfaces_reset              = FALSE;
350     upload->surface_width               = 0;
351     upload->surface_height              = 0;
352     upload->direct_rendering_caps       = 0;
353     upload->direct_rendering            = G_MAXUINT32;
354
355     /* Override buffer allocator on sink pad */
356     sinkpad = gst_element_get_static_pad(GST_ELEMENT(upload), "sink");
357     gst_pad_set_bufferalloc_function(
358         sinkpad,
359         gst_vaapiupload_sinkpad_buffer_alloc
360     );
361     gst_pad_set_query_function(sinkpad, gst_vaapiupload_query);
362     g_object_unref(sinkpad);
363
364     /* Override query on src pad */
365     srcpad = gst_element_get_static_pad(GST_ELEMENT(upload), "src");
366     gst_pad_set_query_function(srcpad, gst_vaapiupload_query);
367     g_object_unref(srcpad);
368 }
369
370 static gboolean
371 gst_vaapiupload_start(GstBaseTransform *trans)
372 {
373     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
374
375     if (!gst_vaapi_ensure_display(upload, &upload->display))
376         return FALSE;
377
378     return TRUE;
379 }
380
381 static gboolean
382 gst_vaapiupload_stop(GstBaseTransform *trans)
383 {
384     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
385
386     g_clear_object(&upload->display);
387
388     return TRUE;
389 }
390
391 static GstFlowReturn
392 gst_vaapiupload_transform(
393     GstBaseTransform *trans,
394     GstBuffer        *inbuf,
395     GstBuffer        *outbuf
396 )
397 {
398     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
399     GstVaapiVideoBuffer *vbuffer;
400     GstVaapiSurface *surface;
401     GstVaapiImage *image;
402     gboolean success;
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_vaapiupload_transform_caps(
452     GstBaseTransform *trans,
453     GstPadDirection   direction,
454     GstCaps          *caps
455 )
456 {
457     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
458     GstCaps *out_caps = NULL;
459     GstStructure *structure;
460
461     g_return_val_if_fail(GST_IS_CAPS(caps), NULL);
462
463     structure = gst_caps_get_structure(caps, 0);
464
465     if (direction == GST_PAD_SINK) {
466         if (!gst_structure_has_name(structure, "video/x-raw-yuv"))
467             return NULL;
468         out_caps = gst_caps_from_string(gst_vaapiupload_vaapi_caps_str);
469
470         structure = gst_caps_get_structure(out_caps, 0);
471         gst_structure_set(
472             structure,
473             "type", G_TYPE_STRING, "vaapi",
474             "opengl", G_TYPE_BOOLEAN, USE_GLX,
475             NULL
476         );
477     }
478     else {
479         if (!gst_structure_has_name(structure, GST_VAAPI_SURFACE_CAPS_NAME))
480             return NULL;
481         out_caps = gst_caps_from_string(gst_vaapiupload_yuv_caps_str);
482         if (upload->display) {
483             GstCaps *allowed_caps, *inter_caps;
484             allowed_caps = gst_vaapi_display_get_image_caps(upload->display);
485             if (!allowed_caps)
486                 return NULL;
487             inter_caps = gst_caps_intersect(out_caps, allowed_caps);
488             gst_caps_unref(allowed_caps);
489             gst_caps_unref(out_caps);
490             out_caps = inter_caps;
491         }
492     }
493
494     if (!gst_vaapi_append_surface_caps(out_caps, caps)) {
495         gst_caps_unref(out_caps);
496         return NULL;
497     }
498     return out_caps;
499 }
500
501 static gboolean
502 gst_vaapiupload_ensure_image_pool(GstVaapiUpload *upload, GstCaps *caps)
503 {
504     GstStructure * const structure = gst_caps_get_structure(caps, 0);
505     gint width, height;
506
507     gst_structure_get_int(structure, "width",  &width);
508     gst_structure_get_int(structure, "height", &height);
509
510     if (width != upload->image_width || height != upload->image_height) {
511         upload->image_width  = width;
512         upload->image_height = height;
513         g_clear_object(&upload->images);
514         upload->images = gst_vaapi_image_pool_new(upload->display, caps);
515         if (!upload->images)
516             return FALSE;
517         upload->images_reset = TRUE;
518     }
519     return TRUE;
520 }
521
522 static gboolean
523 gst_vaapiupload_ensure_surface_pool(GstVaapiUpload *upload, GstCaps *caps)
524 {
525     GstStructure * const structure = gst_caps_get_structure(caps, 0);
526     gint width, height;
527
528     gst_structure_get_int(structure, "width",  &width);
529     gst_structure_get_int(structure, "height", &height);
530
531     if (width != upload->surface_width || height != upload->surface_height) {
532         upload->surface_width  = width;
533         upload->surface_height = height;
534         g_clear_object(&upload->surfaces);
535         upload->surfaces = gst_vaapi_surface_pool_new(upload->display, caps);
536         if (!upload->surfaces)
537             return FALSE;
538         upload->surfaces_reset = TRUE;
539     }
540     return TRUE;
541 }
542
543 static void
544 gst_vaapiupload_ensure_direct_rendering_caps(
545     GstVaapiUpload *upload,
546     GstCaps         *caps
547 )
548 {
549     GstVaapiSurface *surface;
550     GstVaapiImage *image;
551     GstVaapiImageFormat vaformat;
552     GstVideoFormat vformat;
553     GstStructure *structure;
554     gint width, height;
555
556     if (!upload->images_reset && !upload->surfaces_reset)
557         return;
558
559     upload->images_reset          = FALSE;
560     upload->surfaces_reset        = FALSE;
561     upload->direct_rendering_caps = 0;
562
563     structure = gst_caps_get_structure(caps, 0);
564     if (!structure)
565         return;
566     gst_structure_get_int(structure, "width",  &width);
567     gst_structure_get_int(structure, "height", &height);
568
569     /* Translate from Gst video format to VA image format */
570     if (!gst_video_format_parse_caps(caps, &vformat, NULL, NULL))
571         return;
572     if (!gst_video_format_is_yuv(vformat))
573         return;
574     vaformat = gst_vaapi_image_format_from_video(vformat);
575     if (!vaformat)
576         return;
577
578     /* Check if we can alias sink & output buffers (same data_size) */
579     image = gst_vaapi_video_pool_get_object(upload->images);
580     if (image) {
581         if (upload->direct_rendering_caps == 0 &&
582             (gst_vaapi_image_get_format(image) == vaformat &&
583              gst_vaapi_image_is_linear(image) &&
584              (gst_vaapi_image_get_data_size(image) ==
585               gst_video_format_get_size(vformat, width, height))))
586             upload->direct_rendering_caps = 1;
587         gst_vaapi_video_pool_put_object(upload->images, image);
588     }
589
590     /* Check if we can access to the surface pixels directly */
591     surface = gst_vaapi_video_pool_get_object(upload->surfaces);
592     if (surface) {
593         image = gst_vaapi_surface_derive_image(surface);
594         if (image) {
595             if (gst_vaapi_image_map(image)) {
596                 if (upload->direct_rendering_caps == 1 &&
597                     (gst_vaapi_image_get_format(image) == vaformat &&
598                      gst_vaapi_image_is_linear(image) &&
599                      (gst_vaapi_image_get_data_size(image) ==
600                       gst_video_format_get_size(vformat, width, height))))
601                     upload->direct_rendering_caps = 2;
602                 gst_vaapi_image_unmap(image);
603             }
604             g_object_unref(image);
605         }
606         gst_vaapi_video_pool_put_object(upload->surfaces, surface);
607     }
608 }
609
610 static gboolean
611 gst_vaapiupload_negotiate_buffers(
612     GstVaapiUpload  *upload,
613     GstCaps          *incaps,
614     GstCaps          *outcaps
615 )
616 {
617     guint dr;
618
619     if (!gst_vaapiupload_ensure_image_pool(upload, incaps))
620         return FALSE;
621
622     if (!gst_vaapiupload_ensure_surface_pool(upload, outcaps))
623         return FALSE;
624
625     gst_vaapiupload_ensure_direct_rendering_caps(upload, incaps);
626     dr = MIN(upload->direct_rendering, upload->direct_rendering_caps);
627     if (upload->direct_rendering != dr) {
628         upload->direct_rendering = dr;
629         GST_DEBUG("direct-rendering level: %d", dr);
630     }
631     return TRUE;
632 }
633
634 static gboolean
635 gst_vaapiupload_set_caps(
636     GstBaseTransform *trans,
637     GstCaps          *incaps,
638     GstCaps          *outcaps
639 )
640 {
641     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
642
643     if (!gst_vaapiupload_negotiate_buffers(upload, incaps, outcaps))
644         return FALSE;
645
646     return TRUE;
647 }
648
649 static gboolean
650 gst_vaapiupload_get_unit_size(
651     GstBaseTransform *trans,
652     GstCaps          *caps,
653     guint            *size
654 )
655 {
656     GstStructure * const structure = gst_caps_get_structure(caps, 0);
657     GstVideoFormat format;
658     gint width, height;
659
660     if (gst_structure_has_name(structure, GST_VAAPI_SURFACE_CAPS_NAME))
661         *size = 0;
662     else {
663         if (!gst_video_format_parse_caps(caps, &format, &width, &height))
664             return FALSE;
665         *size = gst_video_format_get_size(format, width, height);
666     }
667     return TRUE;
668 }
669
670 static GstFlowReturn
671 gst_vaapiupload_buffer_alloc(
672     GstBaseTransform *trans,
673     guint             size,
674     GstCaps          *caps,
675     GstBuffer       **pbuf
676 )
677 {
678     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
679     GstBuffer *buffer = NULL;
680     GstVaapiImage *image = NULL;
681     GstVaapiSurface *surface = NULL;
682     GstVaapiVideoBuffer *vbuffer;
683
684     /* Check if we can use direct-rendering */
685     if (!gst_vaapiupload_negotiate_buffers(upload, caps, caps))
686         goto error;
687     if (!upload->direct_rendering)
688         return GST_FLOW_OK;
689
690     switch (upload->direct_rendering) {
691     case 2:
692         buffer  = gst_vaapi_video_buffer_new_from_pool(upload->surfaces);
693         if (!buffer)
694             goto error;
695         vbuffer = GST_VAAPI_VIDEO_BUFFER(buffer);
696
697         surface = gst_vaapi_video_buffer_get_surface(vbuffer);
698         image   = gst_vaapi_surface_derive_image(surface);
699         if (image && gst_vaapi_image_get_data_size(image) == size) {
700             gst_vaapi_video_buffer_set_image(vbuffer, image);
701             g_object_unref(image); /* video buffer owns an extra reference */
702             break;
703         }
704
705         /* We can't use the derive-image optimization. Disable it. */
706         upload->direct_rendering = 1;
707         gst_buffer_unref(buffer);
708         buffer = NULL;
709
710     case 1:
711         buffer  = gst_vaapi_video_buffer_new_from_pool(upload->images);
712         if (!buffer)
713             goto error;
714         vbuffer = GST_VAAPI_VIDEO_BUFFER(buffer);
715
716         image   = gst_vaapi_video_buffer_get_image(vbuffer);
717         break;
718     }
719     g_assert(image);
720
721     if (!gst_vaapi_image_map(image))
722         goto error;
723
724     GST_BUFFER_DATA(buffer) = gst_vaapi_image_get_plane(image, 0);
725     GST_BUFFER_SIZE(buffer) = gst_vaapi_image_get_data_size(image);
726
727     gst_buffer_set_caps(buffer, caps);
728     *pbuf = buffer;
729     return GST_FLOW_OK;
730
731 error:
732     /* We can't use the inout-buffers optimization. Disable it. */
733     GST_DEBUG("disable in/out buffer optimization");
734     if (buffer)
735         gst_buffer_unref(buffer);
736     upload->direct_rendering = 0;
737     return GST_FLOW_OK;
738 }
739
740 static GstFlowReturn
741 gst_vaapiupload_sinkpad_buffer_alloc(
742     GstPad           *pad,
743     guint64           offset,
744     guint             size,
745     GstCaps          *caps,
746     GstBuffer       **pbuf
747 )
748 {
749     GstBaseTransform *trans;
750     GstFlowReturn ret;
751
752     trans = GST_BASE_TRANSFORM(gst_pad_get_parent_element(pad));
753     if (!trans)
754         return GST_FLOW_UNEXPECTED;
755
756     ret = gst_vaapiupload_buffer_alloc(trans, size, caps, pbuf);
757     g_object_unref(trans);
758     return ret;
759 }
760
761 static GstFlowReturn
762 gst_vaapiupload_prepare_output_buffer(
763     GstBaseTransform *trans,
764     GstBuffer        *inbuf,
765     gint              size,
766     GstCaps          *caps,
767     GstBuffer       **poutbuf
768 )
769 {
770     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
771     GstBuffer *buffer = NULL;
772
773     if (upload->direct_rendering == 2) {
774         if (GST_VAAPI_IS_VIDEO_BUFFER(inbuf)) {
775             buffer = gst_vaapi_video_buffer_new_from_buffer(inbuf);
776             GST_BUFFER_SIZE(buffer) = size;
777         }
778         else {
779             GST_DEBUG("upstream element destroyed our in/out buffer");
780             upload->direct_rendering = 1;
781         }
782     }
783
784     if (!buffer) {
785         buffer = gst_vaapi_video_buffer_new_from_pool(upload->surfaces);
786         if (!buffer)
787             return GST_FLOW_UNEXPECTED;
788         gst_buffer_set_caps(buffer, caps);
789     }
790
791     *poutbuf = buffer;
792     return GST_FLOW_OK;
793 }
794
795 static gboolean
796 gst_vaapiupload_query(GstPad *pad, GstQuery *query)
797 {
798   GstVaapiUpload *upload = GST_VAAPIUPLOAD (gst_pad_get_parent_element (pad));
799   gboolean res;
800
801   GST_DEBUG ("sharing display %p", upload->display);
802
803   if (gst_vaapi_reply_to_query (query, upload->display))
804     res = TRUE;
805   else
806     res = gst_pad_query_default (pad, query);
807
808   g_object_unref (upload);
809   return res;
810 }