vaapisink: compute and expose the supported set of YUV caps.
authorGwenole Beauchesne <gwenole.beauchesne@intel.com>
Tue, 20 Nov 2012 14:50:56 +0000 (15:50 +0100)
committerZhao Halley <halley.zhao@intel.com>
Wed, 17 Apr 2013 09:09:57 +0000 (17:09 +0800)
Make vaapisink expose only the set of supported caps for raw YUV buffers.

Add gst_vaapi_uploader_get_caps() helper function to determine the set
of supported YUV caps as source (for images). This function actually
tries to zero and upload each image to a 64x64 test surface. Of course,
this relies on VA drivers to not claim success if vaPutImage() is not
correctly supported.

gst/vaapi/gstvaapisink.c
gst/vaapi/gstvaapiuploader.c
gst/vaapi/gstvaapiuploader.h

index e4f4a05..672a221 100755 (executable)
@@ -370,6 +370,20 @@ gst_vaapisink_ensure_display(GstVaapiSink *sink)
 }
 
 static gboolean
+gst_vaapisink_ensure_uploader(GstVaapiSink *sink)
+{
+    if (!gst_vaapisink_ensure_display(sink))
+        return FALSE;
+
+    if (!sink->uploader) {
+        sink->uploader = gst_vaapi_uploader_new(sink->display);
+        if (!sink->uploader)
+            return FALSE;
+    }
+    return TRUE;
+}
+
+static gboolean
 gst_vaapisink_ensure_render_rect(GstVaapiSink *sink, guint width, guint height)
 {
     GstVaapiRectangle * const display_rect = &sink->display_rect;
@@ -668,6 +682,24 @@ gst_vaapisink_stop(GstBaseSink *base_sink)
     return TRUE;
 }
 
+static GstCaps *
+gst_vaapisink_get_caps(GstBaseSink *base_sink)
+{
+    GstVaapiSink * const sink = GST_VAAPISINK(base_sink);
+    GstCaps *out_caps, *yuv_caps;
+
+    out_caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS);
+    if (!out_caps)
+        return NULL;
+
+    if (gst_vaapisink_ensure_uploader(sink)) {
+        yuv_caps = gst_vaapi_uploader_get_caps(sink->uploader);
+        if (yuv_caps)
+            gst_caps_append(out_caps, gst_caps_copy(yuv_caps));
+    }
+    return out_caps;
+}
+
 static gboolean
 gst_vaapisink_set_caps(GstBaseSink *base_sink, GstCaps *caps)
 {
@@ -1131,6 +1163,7 @@ gst_vaapisink_class_init(GstVaapiSinkClass *klass)
 
     basesink_class->start        = gst_vaapisink_start;
     basesink_class->stop         = gst_vaapisink_stop;
+    basesink_class->get_caps     = gst_vaapisink_get_caps;
     basesink_class->set_caps     = gst_vaapisink_set_caps;
     basesink_class->preroll      = gst_vaapisink_show_frame;
     basesink_class->render       = gst_vaapisink_show_frame;
index d7ba1f9..451da71 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 #include "gst/vaapi/sysdeps.h"
+#include <string.h>
 #include <gst/video/video.h>
 #include <gst/vaapi/gstvaapisurface.h>
 #include <gst/vaapi/gstvaapiimagepool.h>
@@ -48,6 +49,7 @@ G_DEFINE_TYPE(GstVaapiUploader, gst_vaapi_uploader, G_TYPE_OBJECT)
 
 struct _GstVaapiUploaderPrivate {
     GstVaapiDisplay    *display;
+    GstCaps            *allowed_caps;
     GstVaapiVideoPool  *images;
     GstCaps            *image_caps;
     guint               image_width;
@@ -70,6 +72,8 @@ gst_vaapi_uploader_destroy(GstVaapiUploader *uploader)
     GstVaapiUploaderPrivate * const priv = uploader->priv;
 
     gst_caps_replace(&priv->image_caps, NULL);
+    gst_caps_replace(&priv->allowed_caps, NULL);
+
     g_clear_object(&priv->images);
     g_clear_object(&priv->surfaces);
     g_clear_object(&priv->display);
@@ -90,6 +94,88 @@ ensure_display(GstVaapiUploader *uploader, GstVaapiDisplay *display)
 }
 
 static gboolean
+ensure_image(GstVaapiImage *image)
+{
+    guint i, num_planes, width, height;
+
+    /* Make the image fully dirty */
+    if (!gst_vaapi_image_map(image))
+        return FALSE;
+
+    gst_vaapi_image_get_size(image, &width, &height);
+
+    num_planes = gst_vaapi_image_get_plane_count(image);
+    for (i = 0; i < num_planes; i++) {
+        guchar * const plane = gst_vaapi_image_get_plane(image, i);
+        if (plane)
+            memset(plane, 0, height * gst_vaapi_image_get_pitch(image, i));
+    }
+
+    if (!gst_vaapi_image_unmap(image))
+        gst_vaapi_image_unmap(image);
+    return TRUE;
+}
+
+static gboolean
+ensure_allowed_caps(GstVaapiUploader *uploader)
+{
+    GstVaapiUploaderPrivate * const priv = uploader->priv;
+    GstVaapiSurface *surface = NULL;
+    GstCaps *out_caps, *image_caps = NULL;
+    guint i, n_structures;
+    gboolean success = FALSE;
+
+    enum { WIDTH = 64, HEIGHT = 64 };
+
+    if (priv->allowed_caps)
+        return TRUE;
+
+    out_caps = gst_caps_new_empty();
+    if (!out_caps)
+        return FALSE;
+
+    image_caps = gst_vaapi_display_get_image_caps(priv->display);
+    if (!image_caps)
+        goto end;
+
+    surface = gst_vaapi_surface_new(priv->display,
+        GST_VAAPI_CHROMA_TYPE_YUV420, WIDTH, HEIGHT);
+    if (!surface)
+        goto end;
+
+    n_structures = gst_caps_get_size(image_caps);
+    for (i = 0; i < n_structures; i++) {
+        GstStructure * const structure = gst_caps_get_structure(image_caps, i);
+        GstVaapiImage *image;
+        GstVaapiImageFormat format;
+        guint32 fourcc;
+
+        if (!gst_structure_get_fourcc(structure, "format", &fourcc))
+            continue;
+        format = gst_vaapi_image_format_from_fourcc(fourcc);
+        if (!format)
+            continue;
+        image = gst_vaapi_image_new(priv->display, format, WIDTH, HEIGHT);
+        if (!image)
+            continue;
+        if (ensure_image(image) && gst_vaapi_surface_put_image(surface, image))
+            gst_caps_append_structure(out_caps, gst_structure_copy(structure));
+        gst_object_unref(image);
+    }
+
+    gst_caps_replace(&priv->allowed_caps, out_caps);
+    success = TRUE;
+
+end:
+    gst_caps_unref(out_caps);
+    if (image_caps)
+        gst_caps_unref(image_caps);
+    if (surface)
+        gst_object_unref(surface);
+    return success;
+}
+
+static gboolean
 ensure_image_pool(GstVaapiUploader *uploader, GstCaps *caps)
 {
     GstVaapiUploaderPrivate * const priv = uploader->priv;
@@ -340,6 +426,16 @@ gst_vaapi_uploader_process(
     return TRUE;
 }
 
+GstCaps *
+gst_vaapi_uploader_get_caps(GstVaapiUploader *uploader)
+{
+    g_return_val_if_fail(GST_VAAPI_IS_UPLOADER(uploader), NULL);
+
+    if (!ensure_allowed_caps(uploader))
+        return NULL;
+    return uploader->priv->allowed_caps;
+}
+
 GstBuffer *
 gst_vaapi_uploader_get_buffer(GstVaapiUploader *uploader)
 {
index 06f62d3..db2dcdb 100644 (file)
@@ -99,6 +99,10 @@ gst_vaapi_uploader_process(
 );
 
 G_GNUC_INTERNAL
+GstCaps *
+gst_vaapi_uploader_get_caps(GstVaapiUploader *uploader);
+
+G_GNUC_INTERNAL
 GstBuffer *
 gst_vaapi_uploader_get_buffer(GstVaapiUploader *uploader);