vaapiupload: fix sink caps to report the supported set of YUV caps.
[profile/ivi/gstreamer-vaapi.git] / gst / vaapi / gstvaapiupload.c
1 /*
2  *  gstvaapiupload.c - VA-API video upload element
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 #include <gst/vaapi/gstvaapidebug.h>
37
38 #include "gstvaapiupload.h"
39 #include "gstvaapipluginutil.h"
40 #include "gstvaapipluginbuffer.h"
41
42 #define GST_PLUGIN_NAME "vaapiupload"
43 #define GST_PLUGIN_DESC "A video to VA flow filter"
44
45 GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapiupload);
46 #define GST_CAT_DEFAULT gst_debug_vaapiupload
47
48 /* ElementFactory information */
49 static const GstElementDetails gst_vaapiupload_details =
50     GST_ELEMENT_DETAILS(
51         "VA-API colorspace uploader",
52         "Filter/Converter/Video",
53         GST_PLUGIN_DESC,
54         "Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
55
56 /* Default templates */
57 static const char gst_vaapiupload_yuv_caps_str[] =
58     "video/x-raw-yuv, "
59     "width  = (int) [ 1, MAX ], "
60     "height = (int) [ 1, MAX ]; ";
61
62 static const char gst_vaapiupload_vaapi_caps_str[] =
63     GST_VAAPI_SURFACE_CAPS;
64
65 static GstStaticPadTemplate gst_vaapiupload_sink_factory =
66     GST_STATIC_PAD_TEMPLATE(
67         "sink",
68         GST_PAD_SINK,
69         GST_PAD_ALWAYS,
70         GST_STATIC_CAPS(gst_vaapiupload_yuv_caps_str));
71
72 static GstStaticPadTemplate gst_vaapiupload_src_factory =
73     GST_STATIC_PAD_TEMPLATE(
74         "src",
75         GST_PAD_SRC,
76         GST_PAD_ALWAYS,
77         GST_STATIC_CAPS(gst_vaapiupload_vaapi_caps_str));
78
79 static void
80 gst_vaapiupload_implements_iface_init(GstImplementsInterfaceClass *iface);
81
82 static void
83 gst_video_context_interface_init(GstVideoContextInterface *iface);
84
85 #define GstVideoContextClass GstVideoContextInterface
86 G_DEFINE_TYPE_WITH_CODE(
87     GstVaapiUpload,
88     gst_vaapiupload,
89     GST_TYPE_BASE_TRANSFORM,
90     G_IMPLEMENT_INTERFACE(GST_TYPE_IMPLEMENTS_INTERFACE,
91                           gst_vaapiupload_implements_iface_init);
92     G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_CONTEXT,
93                           gst_video_context_interface_init))
94
95 static gboolean
96 gst_vaapiupload_start(GstBaseTransform *trans);
97
98 static gboolean
99 gst_vaapiupload_stop(GstBaseTransform *trans);
100
101 static GstFlowReturn
102 gst_vaapiupload_transform(
103     GstBaseTransform *trans,
104     GstBuffer        *inbuf,
105     GstBuffer        *outbuf
106 );
107
108 static GstCaps *
109 gst_vaapiupload_transform_caps(
110     GstBaseTransform *trans,
111     GstPadDirection   direction,
112     GstCaps          *caps
113 );
114
115 static gboolean
116 gst_vaapiupload_set_caps(
117     GstBaseTransform *trans,
118     GstCaps          *incaps,
119     GstCaps          *outcaps
120 );
121
122 static gboolean
123 gst_vaapiupload_get_unit_size(
124     GstBaseTransform *trans,
125     GstCaps          *caps,
126     guint            *size
127 );
128
129 static GstFlowReturn
130 gst_vaapiupload_sinkpad_buffer_alloc(
131     GstPad           *pad,
132     guint64           offset,
133     guint             size,
134     GstCaps          *caps,
135     GstBuffer       **pbuf
136 );
137
138 static GstFlowReturn
139 gst_vaapiupload_prepare_output_buffer(
140     GstBaseTransform *trans,
141     GstBuffer        *inbuf,
142     gint              size,
143     GstCaps          *caps,
144     GstBuffer       **poutbuf
145 );
146
147 static gboolean
148 gst_vaapiupload_query(
149     GstPad   *pad,
150     GstQuery *query
151 );
152
153 /* GstImplementsInterface interface */
154
155 static gboolean
156 gst_vaapiupload_implements_interface_supported(
157     GstImplementsInterface *iface,
158     GType                   type
159 )
160 {
161     return (type == GST_TYPE_VIDEO_CONTEXT);
162 }
163
164 static void
165 gst_vaapiupload_implements_iface_init(GstImplementsInterfaceClass *iface)
166 {
167     iface->supported = gst_vaapiupload_implements_interface_supported;
168 }
169
170 /* GstVideoContext interface */
171
172 static void
173 gst_vaapiupload_set_video_context(GstVideoContext *context, const gchar *type,
174     const GValue *value)
175 {
176     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(context);
177
178     gst_vaapi_set_display(type, value, &upload->display);
179
180     if (upload->uploader)
181         gst_vaapi_uploader_ensure_display(upload->uploader, upload->display);
182 }
183
184 static void
185 gst_video_context_interface_init(GstVideoContextInterface *iface)
186 {
187     iface->set_context = gst_vaapiupload_set_video_context;
188 }
189
190 static void
191 gst_vaapiupload_destroy(GstVaapiUpload *upload)
192 {
193     g_clear_object(&upload->uploader);
194     g_clear_object(&upload->display);
195 }
196
197 static void
198 gst_vaapiupload_finalize(GObject *object)
199 {
200     gst_vaapiupload_destroy(GST_VAAPIUPLOAD(object));
201
202     G_OBJECT_CLASS(gst_vaapiupload_parent_class)->finalize(object);
203 }
204
205 static void
206 gst_vaapiupload_class_init(GstVaapiUploadClass *klass)
207 {
208     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
209     GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
210     GstBaseTransformClass * const trans_class = GST_BASE_TRANSFORM_CLASS(klass);
211     GstPadTemplate *pad_template;
212
213     GST_DEBUG_CATEGORY_INIT(gst_debug_vaapiupload,
214                             GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
215
216     object_class->finalize      = gst_vaapiupload_finalize;
217
218     trans_class->start          = gst_vaapiupload_start;
219     trans_class->stop           = gst_vaapiupload_stop;
220     trans_class->transform      = gst_vaapiupload_transform;
221     trans_class->transform_caps = gst_vaapiupload_transform_caps;
222     trans_class->set_caps       = gst_vaapiupload_set_caps;
223     trans_class->get_unit_size  = gst_vaapiupload_get_unit_size;
224     trans_class->prepare_output_buffer = gst_vaapiupload_prepare_output_buffer;
225
226     gst_element_class_set_details_simple(
227         element_class,
228         gst_vaapiupload_details.longname,
229         gst_vaapiupload_details.klass,
230         gst_vaapiupload_details.description,
231         gst_vaapiupload_details.author
232     );
233
234     /* sink pad */
235     pad_template = gst_static_pad_template_get(&gst_vaapiupload_sink_factory);
236     gst_element_class_add_pad_template(element_class, pad_template);
237     gst_object_unref(pad_template);
238
239     /* src pad */
240     pad_template = gst_static_pad_template_get(&gst_vaapiupload_src_factory);
241     gst_element_class_add_pad_template(element_class, pad_template);
242     gst_object_unref(pad_template);
243 }
244
245 static void
246 gst_vaapiupload_init(GstVaapiUpload *upload)
247 {
248     GstPad *sinkpad, *srcpad;
249
250     /* Override buffer allocator on sink pad */
251     sinkpad = gst_element_get_static_pad(GST_ELEMENT(upload), "sink");
252     gst_pad_set_bufferalloc_function(
253         sinkpad,
254         gst_vaapiupload_sinkpad_buffer_alloc
255     );
256     gst_pad_set_query_function(sinkpad, gst_vaapiupload_query);
257     g_object_unref(sinkpad);
258
259     /* Override query on src pad */
260     srcpad = gst_element_get_static_pad(GST_ELEMENT(upload), "src");
261     gst_pad_set_query_function(srcpad, gst_vaapiupload_query);
262     g_object_unref(srcpad);
263 }
264
265 static inline gboolean
266 gst_vaapiupload_ensure_display(GstVaapiUpload *upload)
267 {
268     return gst_vaapi_ensure_display(upload, GST_VAAPI_DISPLAY_TYPE_ANY,
269         &upload->display);
270 }
271
272 static gboolean
273 gst_vaapiupload_ensure_uploader(GstVaapiUpload *upload)
274 {
275     if (!gst_vaapiupload_ensure_display(upload))
276         return FALSE;
277
278     if (!upload->uploader) {
279         upload->uploader = gst_vaapi_uploader_new(upload->display);
280         if (!upload->uploader)
281             return FALSE;
282     }
283     if (!gst_vaapi_uploader_ensure_display(upload->uploader, upload->display))
284         return FALSE;
285     return TRUE;
286 }
287
288 static gboolean
289 gst_vaapiupload_start(GstBaseTransform *trans)
290 {
291     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
292
293     if (!gst_vaapiupload_ensure_uploader(upload))
294         return FALSE;
295     return TRUE;
296 }
297
298 static gboolean
299 gst_vaapiupload_stop(GstBaseTransform *trans)
300 {
301     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
302
303     g_clear_object(&upload->display);
304
305     return TRUE;
306 }
307
308 static GstFlowReturn
309 gst_vaapiupload_transform(
310     GstBaseTransform *trans,
311     GstBuffer        *inbuf,
312     GstBuffer        *outbuf
313 )
314 {
315     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
316     if (!gst_vaapi_uploader_process(upload->uploader, inbuf, outbuf))
317         return GST_FLOW_UNEXPECTED;
318     return GST_FLOW_OK;
319 }
320
321 static GstCaps *
322 gst_vaapi_get_other_support_caps(GstVaapiUpload *upload)
323 {
324   GstCaps *caps;
325   caps = gst_caps_from_string(GST_VIDEO_CAPS_YUV("YUY2"));
326   return caps;
327 }
328
329 static GstCaps *
330 gst_vaapiupload_transform_caps(
331     GstBaseTransform *trans,
332     GstPadDirection   direction,
333     GstCaps          *caps
334 )
335 {
336     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
337     GstCaps *out_caps = NULL;
338     GstStructure *structure;
339
340     g_return_val_if_fail(GST_IS_CAPS(caps), NULL);
341
342     structure = gst_caps_get_structure(caps, 0);
343
344     if (direction == GST_PAD_SINK) {
345         if (!gst_structure_has_name(structure, "video/x-raw-yuv"))
346             return NULL;
347         out_caps = gst_caps_from_string(gst_vaapiupload_vaapi_caps_str);
348
349         structure = gst_caps_get_structure(out_caps, 0);
350         gst_structure_set(
351             structure,
352             "type", G_TYPE_STRING, "vaapi",
353             "opengl", G_TYPE_BOOLEAN, USE_GLX,
354             NULL
355         );
356     }
357     else {
358         if (!gst_structure_has_name(structure, GST_VAAPI_SURFACE_CAPS_NAME))
359             return NULL;
360         out_caps = gst_caps_from_string(gst_vaapiupload_yuv_caps_str);
361         if (gst_vaapiupload_ensure_uploader(upload)) {
362             GstCaps *allowed_caps, *inter_caps, *other_caps;
363             allowed_caps = gst_vaapi_uploader_get_caps(upload->uploader);
364             if (!allowed_caps)
365                 return NULL;
366             /* can direct copy other YUV to va surface */
367             other_caps = gst_vaapi_get_other_support_caps(upload);
368             gst_caps_merge(allowed_caps, other_caps);
369
370             inter_caps = gst_caps_intersect(out_caps, allowed_caps);
371             gst_caps_unref(out_caps);
372             out_caps = inter_caps;
373         }
374     }
375
376     if (!gst_vaapi_append_surface_caps(out_caps, caps)) {
377         gst_caps_unref(out_caps);
378         return NULL;
379     }
380     return out_caps;
381 }
382
383 static gboolean
384 gst_vaapiupload_set_caps(
385     GstBaseTransform *trans,
386     GstCaps          *incaps,
387     GstCaps          *outcaps
388 )
389 {
390     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
391
392     if (!gst_vaapi_uploader_ensure_caps(upload->uploader, incaps, outcaps))
393         return FALSE;
394
395     GST_INFO("set caps\nIN caps:\n%" GST_PTR_FORMAT "\nOUT caps:\n%" GST_PTR_FORMAT,
396              incaps, outcaps);
397     return TRUE;
398 }
399
400 static gboolean
401 gst_vaapiupload_get_unit_size(
402     GstBaseTransform *trans,
403     GstCaps          *caps,
404     guint            *size
405 )
406 {
407     GstStructure * const structure = gst_caps_get_structure(caps, 0);
408     GstVideoFormat format;
409     gint width, height;
410
411     if (gst_structure_has_name(structure, GST_VAAPI_SURFACE_CAPS_NAME))
412         *size = 0;
413     else {
414         if (!gst_video_format_parse_caps(caps, &format, &width, &height))
415             return FALSE;
416         *size = gst_video_format_get_size(format, width, height);
417     }
418     return TRUE;
419 }
420
421 static GstFlowReturn
422 gst_vaapiupload_buffer_alloc(
423     GstBaseTransform *trans,
424     guint             size,
425     GstCaps          *caps,
426     GstBuffer       **pbuf
427 )
428 {
429     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
430     *pbuf = NULL;
431
432     if (!gst_vaapi_uploader_ensure_display(upload->uploader, upload->display))
433         return GST_FLOW_NOT_SUPPORTED;
434     if (!gst_vaapi_uploader_ensure_caps(upload->uploader, caps, NULL))
435         return GST_FLOW_NOT_SUPPORTED;
436
437     /* Allocate a regular GstBuffer if direct rendering is not supported */
438     if (!gst_vaapi_uploader_has_direct_rendering(upload->uploader))
439         return GST_FLOW_OK;
440     *pbuf = gst_vaapi_uploader_get_buffer(upload->uploader);
441     return GST_FLOW_OK;
442 }
443
444 static GstFlowReturn
445 gst_vaapiupload_sinkpad_buffer_alloc(
446     GstPad           *pad,
447     guint64           offset,
448     guint             size,
449     GstCaps          *caps,
450     GstBuffer       **pbuf
451 )
452 {
453     GstBaseTransform *trans;
454     GstFlowReturn ret;
455
456     trans = GST_BASE_TRANSFORM(gst_pad_get_parent_element(pad));
457     if (!trans)
458         return GST_FLOW_UNEXPECTED;
459
460     ret = gst_vaapiupload_buffer_alloc(trans, size, caps, pbuf);
461     g_object_unref(trans);
462     return ret;
463 }
464
465 static GstFlowReturn
466 gst_vaapiupload_prepare_output_buffer(
467     GstBaseTransform *trans,
468     GstBuffer        *inbuf,
469     gint              size,
470     GstCaps          *caps,
471     GstBuffer       **poutbuf
472 )
473 {
474     GstVaapiUpload * const upload = GST_VAAPIUPLOAD(trans);
475     GstBuffer *buffer;
476
477     *poutbuf = NULL;
478
479     if (!gst_vaapi_uploader_has_direct_rendering(upload->uploader))
480         buffer = gst_vaapi_uploader_get_buffer(upload->uploader);
481     else if (GST_VAAPI_IS_VIDEO_BUFFER(inbuf))
482         buffer = gst_vaapi_video_buffer_new_from_buffer(inbuf);
483     else if (GST_VAAPI_IS_VIDEO_BUFFER(inbuf->parent))
484         buffer = gst_vaapi_video_buffer_new_from_buffer(inbuf->parent);
485     else
486         buffer = NULL;
487     if (!buffer)
488         return GST_FLOW_UNEXPECTED;
489
490     gst_buffer_set_caps(buffer, caps);
491     GST_BUFFER_DATA(buffer) = NULL;
492     GST_BUFFER_SIZE(buffer) = 0;
493
494     *poutbuf = buffer;
495     return GST_FLOW_OK;
496 }
497
498 static gboolean
499 gst_vaapiupload_query(GstPad *pad, GstQuery *query)
500 {
501   GstVaapiUpload *upload = GST_VAAPIUPLOAD (gst_pad_get_parent_element (pad));
502   gboolean res;
503
504   GST_DEBUG ("sharing display %p", upload->display);
505
506   if (gst_vaapi_reply_to_query (query, upload->display))
507     res = TRUE;
508   else
509     res = gst_pad_query_default (pad, query);
510
511   g_object_unref (upload);
512   return res;
513 }