3116449a1b98ce439b3e13bbe37edc12af96ba67
[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 "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 converter",
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_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     if (convert->direct_rendering)
626         gst_vaapiupload_ensure_direct_rendering_caps(upload, incaps);
627     dr = MIN(upload->direct_rendering, upload->direct_rendering_caps);
628     if (upload->direct_rendering != dr) {
629         upload->direct_rendering = dr;
630     return TRUE;
631 }
632
633 static gboolean
634 gst_vaapiupload_set_caps(
635     GstBaseTransform *trans,
636     GstCaps          *incaps,
637     GstCaps          *outcaps
638 )
639 {
640     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
641
642     if (!gst_vaapiupload_negotiate_buffers(upload, incaps, outcaps))
643         return FALSE;
644
645     return TRUE;
646 }
647
648 static gboolean
649 gst_vaapiupload_get_unit_size(
650     GstBaseTransform *trans,
651     GstCaps          *caps,
652     guint            *size
653 )
654 {
655     GstStructure * const structure = gst_caps_get_structure(caps, 0);
656     GstVideoFormat format;
657     gint width, height;
658
659     if (gst_structure_has_name(structure, GST_VAAPI_SURFACE_CAPS_NAME))
660         *size = 0;
661     else {
662         if (!gst_video_format_parse_caps(caps, &format, &width, &height))
663             return FALSE;
664         *size = gst_video_format_get_size(format, width, height);
665     }
666     return TRUE;
667 }
668
669 static GstFlowReturn
670 gst_vaapiupload_buffer_alloc(
671     GstBaseTransform *trans,
672     guint             size,
673     GstCaps          *caps,
674     GstBuffer       **pbuf
675 )
676 {
677     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
678     GstBuffer *buffer = NULL;
679     GstVaapiImage *image = NULL;
680     GstVaapiSurface *surface = NULL;
681     GstVaapiVideoBuffer *vbuffer;
682
683     /* Check if we can use direct-rendering */
684     if (!gst_vaapiupload_negotiate_buffers(upload, caps, caps))
685         goto error;
686     if (!upload->direct_rendering)
687         return GST_FLOW_OK;
688
689     switch (upload->direct_rendering) {
690     case 2:
691         buffer  = gst_vaapi_video_buffer_new_from_pool(upload->surfaces);
692         if (!buffer)
693             goto error;
694         vbuffer = GST_VAAPI_VIDEO_BUFFER(buffer);
695
696         surface = gst_vaapi_video_buffer_get_surface(vbuffer);
697         image   = gst_vaapi_surface_derive_image(surface);
698         if (image && gst_vaapi_image_get_data_size(image) == size) {
699             gst_vaapi_video_buffer_set_image(vbuffer, image);
700             g_object_unref(image); /* video buffer owns an extra reference */
701             break;
702         }
703
704         /* We can't use the derive-image optimization. Disable it. */
705         upload->direct_rendering = 1;
706         gst_buffer_unref(buffer);
707         buffer = NULL;
708
709     case 1:
710         buffer  = gst_vaapi_video_buffer_new_from_pool(upload->images);
711         if (!buffer)
712             goto error;
713         vbuffer = GST_VAAPI_VIDEO_BUFFER(buffer);
714
715         image   = gst_vaapi_video_buffer_get_image(vbuffer);
716         break;
717     }
718     g_assert(image);
719
720     if (!gst_vaapi_image_map(image))
721         goto error;
722
723     GST_BUFFER_DATA(buffer) = gst_vaapi_image_get_plane(image, 0);
724     GST_BUFFER_SIZE(buffer) = gst_vaapi_image_get_data_size(image);
725
726     gst_buffer_set_caps(buffer, caps);
727     *pbuf = buffer;
728     return GST_FLOW_OK;
729
730 error:
731     /* We can't use the inout-buffers optimization. Disable it. */
732     GST_DEBUG("disable in/out buffer optimization");
733     if (buffer)
734         gst_buffer_unref(buffer);
735     upload->direct_rendering = 0;
736     return GST_FLOW_OK;
737 }
738
739 static GstFlowReturn
740 gst_vaapiupload_sinkpad_buffer_alloc(
741     GstPad           *pad,
742     guint64           offset,
743     guint             size,
744     GstCaps          *caps,
745     GstBuffer       **pbuf
746 )
747 {
748     GstBaseTransform *trans;
749     GstFlowReturn ret;
750
751     trans = GST_BASE_TRANSFORM(gst_pad_get_parent_element(pad));
752     if (!trans)
753         return GST_FLOW_UNEXPECTED;
754
755     ret = gst_vaapiupload_buffer_alloc(trans, size, caps, pbuf);
756     g_object_unref(trans);
757     return ret;
758 }
759
760 static GstFlowReturn
761 gst_vaapiupload_prepare_output_buffer(
762     GstBaseTransform *trans,
763     GstBuffer        *inbuf,
764     gint              size,
765     GstCaps          *caps,
766     GstBuffer       **poutbuf
767 )
768 {
769     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
770     GstBuffer *buffer = NULL;
771
772     if (upload->direct_rendering == 2) {
773         if (GST_VAAPI_IS_VIDEO_BUFFER(inbuf)) {
774             buffer = gst_vaapi_video_buffer_new_from_buffer(inbuf);
775             GST_BUFFER_SIZE(buffer) = size;
776         }
777         else {
778             GST_DEBUG("upstream element destroyed our in/out buffer");
779             upload->direct_rendering = 1;
780         }
781     }
782
783     if (!buffer) {
784         buffer = gst_vaapi_video_buffer_new_from_pool(upload->surfaces);
785         if (!buffer)
786             return GST_FLOW_UNEXPECTED;
787         gst_buffer_set_caps(buffer, caps);
788     }
789
790     *poutbuf = buffer;
791     return GST_FLOW_OK;
792 }
793
794 static gboolean
795 gst_vaapiupload_query(GstPad *pad, GstQuery *query)
796 {
797   GstVaapiUpload *upload = GST_VAAPIUPLOAD (gst_pad_get_parent_element (pad));
798   gboolean res;
799
800   GST_DEBUG ("sharing display %p", upload->display);
801
802   if (gst_vaapi_reply_to_query (query, upload->display))
803     res = TRUE;
804   else
805     res = gst_pad_query_default (pad, query);
806
807   g_object_unref (upload);
808   return res;
809 }