2 * gstvaapidownload.c - VA-API video downloader
4 * Copyright (C) 2010-2011 Splitted-Desktop Systems
5 * Copyright (C) 2011-2012 Intel Corporation
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public License
9 * as published by the Free Software Foundation; either version 2.1
10 * of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301 USA
24 * SECTION:gstvaapidownload
25 * @short_description: A VA to video flow filter
27 * vaapidownload converts from VA surfaces to raw YUV pixels.
33 #include <gst/video/video.h>
34 #include <gst/video/videocontext.h>
35 #include <gst/vaapi/gstvaapivideosink.h>
36 #include <gst/vaapi/gstvaapivideobuffer.h>
39 #include <gst/vaapi/gstvaapivideobuffer_glx.h>
40 #define gst_vaapi_video_buffer_new_from_pool(pool) \
41 gst_vaapi_video_buffer_glx_new_from_pool(pool)
42 #define gst_vaapi_video_buffer_new_from_buffer(buffer) \
43 gst_vaapi_video_buffer_glx_new_from_buffer(buffer)
46 #include "gstvaapipluginutil.h"
47 #include "gstvaapidownload.h"
49 #define GST_PLUGIN_NAME "vaapidownload"
50 #define GST_PLUGIN_DESC "A VA to video flow filter"
52 GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapidownload);
53 #define GST_CAT_DEFAULT gst_debug_vaapidownload
55 /* ElementFactory information */
56 static const GstElementDetails gst_vaapidownload_details =
58 "VA-API colorspace converter",
59 "Filter/Converter/Video",
61 "Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
63 /* Default templates */
64 static const char gst_vaapidownload_yuv_caps_str[] =
66 "width = (int) [ 1, MAX ], "
67 "height = (int) [ 1, MAX ]; ";
69 static const char gst_vaapidownload_vaapi_caps_str[] =
70 GST_VAAPI_SURFACE_CAPS;
72 static GstStaticPadTemplate gst_vaapidownload_sink_factory =
73 GST_STATIC_PAD_TEMPLATE(
77 GST_STATIC_CAPS(gst_vaapidownload_vaapi_caps_str));
79 static GstStaticPadTemplate gst_vaapidownload_src_factory =
80 GST_STATIC_PAD_TEMPLATE(
84 GST_STATIC_CAPS(gst_vaapidownload_yuv_caps_str));
86 typedef struct _TransformSizeCache TransformSizeCache;
87 struct _TransformSizeCache {
92 struct _GstVaapiDownload {
94 GstBaseTransform parent_instance;
96 GstVaapiDisplay *display;
97 GstCaps *allowed_caps;
98 TransformSizeCache transform_size_cache[2];
99 GstVaapiVideoPool *images;
100 GstVaapiImageFormat image_format;
103 unsigned int images_reset : 1;
106 struct _GstVaapiDownloadClass {
108 GstBaseTransformClass parent_class;
112 gst_vaapidownload_implements_iface_init(GstImplementsInterfaceClass *iface);
115 gst_video_context_interface_init(GstVideoContextInterface *iface);
117 #define GstVideoContextClass GstVideoContextInterface
118 G_DEFINE_TYPE_WITH_CODE(
121 GST_TYPE_BASE_TRANSFORM,
122 G_IMPLEMENT_INTERFACE(GST_TYPE_IMPLEMENTS_INTERFACE,
123 gst_vaapidownload_implements_iface_init);
124 G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_CONTEXT,
125 gst_video_context_interface_init));
128 gst_vaapidownload_start(GstBaseTransform *trans);
131 gst_vaapidownload_stop(GstBaseTransform *trans);
134 gst_vaapidownload_before_transform(GstBaseTransform *trans, GstBuffer *buffer);
137 gst_vaapidownload_transform(
138 GstBaseTransform *trans,
144 gst_vaapidownload_transform_caps(
145 GstBaseTransform *trans,
146 GstPadDirection direction,
151 gst_vaapidownload_transform_size(
152 GstBaseTransform *trans,
153 GstPadDirection direction,
161 gst_vaapidownload_set_caps(
162 GstBaseTransform *trans,
168 gst_vaapidownload_query(
173 /* GstImplementsInterface interface */
176 gst_vaapidownload_implements_interface_supported(
177 GstImplementsInterface *iface,
181 return (type == GST_TYPE_VIDEO_CONTEXT);
185 gst_vaapidownload_implements_iface_init(GstImplementsInterfaceClass *iface)
187 iface->supported = gst_vaapidownload_implements_interface_supported;
190 /* GstVideoContext interface */
193 gst_vaapidownload_set_video_context(GstVideoContext *context, const gchar *type,
196 GstVaapiDownload *download = GST_VAAPIDOWNLOAD (context);
197 gst_vaapi_set_display (type, value, &download->display);
201 gst_video_context_interface_init(GstVideoContextInterface *iface)
203 iface->set_context = gst_vaapidownload_set_video_context;
207 gst_vaapidownload_destroy(GstVaapiDownload *download)
211 for (i = 0; i < G_N_ELEMENTS(download->transform_size_cache); i++) {
212 TransformSizeCache * const tsc = &download->transform_size_cache[i];
214 gst_caps_unref(tsc->caps);
220 if (download->allowed_caps) {
221 gst_caps_unref(download->allowed_caps);
222 download->allowed_caps = NULL;
225 g_clear_object(&download->images);
226 g_clear_object(&download->display);
230 gst_vaapidownload_finalize(GObject *object)
232 gst_vaapidownload_destroy(GST_VAAPIDOWNLOAD(object));
234 G_OBJECT_CLASS(gst_vaapidownload_parent_class)->finalize(object);
238 gst_vaapidownload_class_init(GstVaapiDownloadClass *klass)
240 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
241 GstBaseTransformClass * const trans_class = GST_BASE_TRANSFORM_CLASS(klass);
242 GstElementClass * const element_class = GST_ELEMENT_CLASS(klass);
243 GstPadTemplate *pad_template;
245 GST_DEBUG_CATEGORY_INIT(gst_debug_vaapidownload,
246 GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
248 object_class->finalize = gst_vaapidownload_finalize;
249 trans_class->start = gst_vaapidownload_start;
250 trans_class->stop = gst_vaapidownload_stop;
251 trans_class->before_transform = gst_vaapidownload_before_transform;
252 trans_class->transform = gst_vaapidownload_transform;
253 trans_class->transform_caps = gst_vaapidownload_transform_caps;
254 trans_class->transform_size = gst_vaapidownload_transform_size;
255 trans_class->set_caps = gst_vaapidownload_set_caps;
257 gst_element_class_set_details_simple(
259 gst_vaapidownload_details.longname,
260 gst_vaapidownload_details.klass,
261 gst_vaapidownload_details.description,
262 gst_vaapidownload_details.author
266 pad_template = gst_static_pad_template_get(&gst_vaapidownload_sink_factory);
267 gst_element_class_add_pad_template(element_class, pad_template);
268 gst_object_unref(pad_template);
271 pad_template = gst_static_pad_template_get(&gst_vaapidownload_src_factory);
272 gst_element_class_add_pad_template(element_class, pad_template);
273 gst_object_unref(pad_template);
277 gst_vaapidownload_init(GstVaapiDownload *download)
279 GstPad *sinkpad, *srcpad;
281 download->display = NULL;
282 download->allowed_caps = NULL;
283 download->images = NULL;
284 download->images_reset = FALSE;
285 download->image_format = (GstVaapiImageFormat)0;
286 download->image_width = 0;
287 download->image_height = 0;
289 /* Override buffer allocator on sink pad */
290 sinkpad = gst_element_get_static_pad(GST_ELEMENT(download), "sink");
291 gst_pad_set_query_function(sinkpad, gst_vaapidownload_query);
292 gst_object_unref(sinkpad);
294 /* Override query on src pad */
295 srcpad = gst_element_get_static_pad(GST_ELEMENT(download), "src");
296 gst_pad_set_query_function(srcpad, gst_vaapidownload_query);
297 gst_object_unref(srcpad);
301 gst_vaapidownload_start(GstBaseTransform *trans)
303 GstVaapiDownload * const download = GST_VAAPIDOWNLOAD(trans);
305 if (!gst_vaapi_ensure_display(download, &download->display))
311 gst_vaapidownload_stop(GstBaseTransform *trans)
313 GstVaapiDownload * const download = GST_VAAPIDOWNLOAD(trans);
315 g_clear_object(&download->display);
320 static GstVaapiImageFormat
321 get_surface_format(GstVaapiSurface *surface)
323 GstVaapiImage *image;
324 GstVaapiImageFormat format = GST_VAAPI_IMAGE_NV12;
326 /* XXX: NV12 is assumed by default */
327 image = gst_vaapi_surface_derive_image(surface);
329 format = gst_vaapi_image_get_format(image);
330 g_object_unref(image);
336 gst_vaapidownload_update_src_caps(GstVaapiDownload *download, GstBuffer *buffer)
338 GstVaapiVideoBuffer *vbuffer;
339 GstVaapiSurface *surface;
340 GstVaapiImageFormat format;
342 GstCaps *in_caps, *out_caps;
344 vbuffer = GST_VAAPI_VIDEO_BUFFER(buffer);
345 surface = gst_vaapi_video_buffer_get_surface(vbuffer);
347 GST_WARNING("failed to retrieve VA surface from buffer");
351 format = get_surface_format(surface);
352 if (format == download->image_format)
355 in_caps = GST_BUFFER_CAPS(buffer);
357 GST_WARNING("failed to retrieve caps from buffer");
361 out_caps = gst_vaapi_image_format_get_caps(format);
363 GST_WARNING("failed to create caps from format %" GST_FOURCC_FORMAT,
364 GST_FOURCC_ARGS(format));
368 if (!gst_vaapi_append_surface_caps(out_caps, in_caps)) {
369 gst_caps_unref(out_caps);
373 /* Try to renegotiate downstream caps */
374 srcpad = gst_element_get_static_pad(GST_ELEMENT(download), "src");
375 gst_pad_set_caps(srcpad, out_caps);
376 gst_object_unref(srcpad);
378 gst_vaapidownload_set_caps(GST_BASE_TRANSFORM(download), in_caps, out_caps);
379 gst_caps_replace(&download->allowed_caps, out_caps);
380 gst_caps_unref(out_caps);
385 gst_vaapidownload_before_transform(GstBaseTransform *trans, GstBuffer *buffer)
387 GstVaapiDownload * const download = GST_VAAPIDOWNLOAD(trans);
389 gst_vaapidownload_update_src_caps(download, buffer);
393 gst_vaapidownload_transform(
394 GstBaseTransform *trans,
399 GstVaapiDownload * const download = GST_VAAPIDOWNLOAD(trans);
400 GstVaapiVideoBuffer *vbuffer;
401 GstVaapiSurface *surface;
402 GstVaapiImage *image = NULL;
405 vbuffer = GST_VAAPI_VIDEO_BUFFER(inbuf);
406 surface = gst_vaapi_video_buffer_get_surface(vbuffer);
408 return GST_FLOW_UNEXPECTED;
410 image = gst_vaapi_video_pool_get_object(download->images);
412 return GST_FLOW_UNEXPECTED;
413 if (!gst_vaapi_surface_get_image(surface, image))
414 goto error_get_image;
416 success = gst_vaapi_image_get_buffer(image, outbuf, NULL);
417 gst_vaapi_video_pool_put_object(download->images, image);
419 goto error_get_buffer;
424 GST_WARNING("failed to download %" GST_FOURCC_FORMAT " image "
425 "from surface 0x%08x",
426 GST_FOURCC_ARGS(gst_vaapi_image_get_format(image)),
427 gst_vaapi_surface_get_id(surface));
428 gst_vaapi_video_pool_put_object(download->images, image);
429 return GST_FLOW_UNEXPECTED;
434 GST_WARNING("failed to transfer image to output video buffer");
435 return GST_FLOW_UNEXPECTED;
440 gst_vaapidownload_transform_caps(
441 GstBaseTransform *trans,
442 GstPadDirection direction,
446 GstVaapiDownload * const download = GST_VAAPIDOWNLOAD(trans);
448 GstCaps *allowed_caps, *inter_caps, *out_caps = NULL;
449 GstStructure *structure;
451 g_return_val_if_fail(GST_IS_CAPS(caps), NULL);
453 structure = gst_caps_get_structure(caps, 0);
455 if (direction == GST_PAD_SINK) {
456 if (!gst_structure_has_name(structure, GST_VAAPI_SURFACE_CAPS_NAME))
458 if (!gst_vaapi_ensure_display(download, &download->display))
460 out_caps = gst_caps_from_string(gst_vaapidownload_yuv_caps_str);
462 /* Build up allowed caps */
463 /* XXX: we don't know the decoded surface format yet so we
464 expose whatever VA images we support */
465 if (download->allowed_caps)
466 allowed_caps = gst_caps_ref(download->allowed_caps);
468 allowed_caps = gst_vaapi_display_get_image_caps(download->display);
472 inter_caps = gst_caps_intersect(out_caps, allowed_caps);
473 gst_caps_unref(allowed_caps);
474 gst_caps_unref(out_caps);
475 out_caps = inter_caps;
477 /* Intersect with allowed caps from the peer, if any */
478 srcpad = gst_element_get_static_pad(GST_ELEMENT(download), "src");
479 allowed_caps = gst_pad_peer_get_caps(srcpad);
481 inter_caps = gst_caps_intersect(out_caps, allowed_caps);
482 gst_caps_unref(allowed_caps);
483 gst_caps_unref(out_caps);
484 out_caps = inter_caps;
488 if (!gst_structure_has_name(structure, "video/x-raw-yuv"))
490 out_caps = gst_caps_from_string(gst_vaapidownload_vaapi_caps_str);
492 structure = gst_caps_get_structure(out_caps, 0);
495 "type", G_TYPE_STRING, "vaapi",
496 "opengl", G_TYPE_BOOLEAN, USE_GLX,
501 if (!gst_vaapi_append_surface_caps(out_caps, caps)) {
502 gst_caps_unref(out_caps);
509 gst_vaapidownload_ensure_image_pool(GstVaapiDownload *download, GstCaps *caps)
511 GstStructure * const structure = gst_caps_get_structure(caps, 0);
512 GstVaapiImageFormat format;
515 format = gst_vaapi_image_format_from_caps(caps);
516 gst_structure_get_int(structure, "width", &width);
517 gst_structure_get_int(structure, "height", &height);
519 if (format != download->image_format ||
520 width != download->image_width ||
521 height != download->image_height) {
522 download->image_format = format;
523 download->image_width = width;
524 download->image_height = height;
525 g_clear_object(&download->images);
526 download->images = gst_vaapi_image_pool_new(download->display, caps);
527 if (!download->images)
529 download->images_reset = TRUE;
534 static inline gboolean
535 gst_vaapidownload_negotiate_buffers(
536 GstVaapiDownload *download,
541 if (!gst_vaapidownload_ensure_image_pool(download, outcaps))
547 gst_vaapidownload_set_caps(
548 GstBaseTransform *trans,
553 GstVaapiDownload * const download = GST_VAAPIDOWNLOAD(trans);
555 if (!gst_vaapidownload_negotiate_buffers(download, incaps, outcaps))
561 gst_vaapidownload_transform_size(
562 GstBaseTransform *trans,
563 GstPadDirection direction,
570 GstVaapiDownload * const download = GST_VAAPIDOWNLOAD(trans);
571 GstStructure * const structure = gst_caps_get_structure(othercaps, 0);
572 GstVideoFormat format;
576 /* Lookup in cache */
577 for (i = 0; i < G_N_ELEMENTS(download->transform_size_cache); i++) {
578 TransformSizeCache * const tsc = &download->transform_size_cache[i];
579 if (tsc->caps && tsc->caps == othercaps) {
580 *othersize = tsc->size;
585 /* Compute requested buffer size */
586 if (gst_structure_has_name(structure, GST_VAAPI_SURFACE_CAPS_NAME))
589 if (!gst_video_format_parse_caps(othercaps, &format, &width, &height))
591 *othersize = gst_video_format_get_size(format, width, height);
595 for (i = 0; i < G_N_ELEMENTS(download->transform_size_cache); i++) {
596 TransformSizeCache * const tsc = &download->transform_size_cache[i];
598 gst_caps_replace(&tsc->caps, othercaps);
599 tsc->size = *othersize;
606 gst_vaapidownload_query(GstPad *pad, GstQuery *query)
608 GstVaapiDownload * const download = GST_VAAPIDOWNLOAD(gst_pad_get_parent_element(pad));
611 GST_DEBUG("sharing display %p", download->display);
613 if (gst_vaapi_reply_to_query(query, download->display))
616 res = gst_pad_query_default(pad, query);
618 g_object_unref(download);