From 5c0d19d705d0a3e52f0805d23366868653dc2b79 Mon Sep 17 00:00:00 2001 From: Wind Yuan Date: Thu, 5 Jan 2012 11:17:33 +0800 Subject: [PATCH] vaapiconvert: change direct-rendering=0 to vaPutImage and support YUY2 colorspace to vaImage --- gst-libs/gst/vaapi/gstvaapiimage.c | 17 +++- gst-libs/gst/vaapi/gstvaapiimage.h | 4 +- gst/vaapi/gstvaapiupload.c | 155 +++++++++++++++++++++++++++++++------ gst/vaapi/gstvaapiupload.h | 1 + 4 files changed, 149 insertions(+), 28 deletions(-) diff --git a/gst-libs/gst/vaapi/gstvaapiimage.c b/gst-libs/gst/vaapi/gstvaapiimage.c index ba727c8..143ef8d 100644 --- a/gst-libs/gst/vaapi/gstvaapiimage.c +++ b/gst-libs/gst/vaapi/gstvaapiimage.c @@ -1568,18 +1568,31 @@ _image_convert_to_yuv411( gboolean gst_vaapi_convert_buffer_to_image( GstVaapiImage *image, - GstBuffer *inbuf, // inbuf : I420 - guint32 in_format) + GstBuffer *inbuf + ) { GstVaapiImagePrivate *priv; guint width, height; GstVaapiImageFormat image_format; gboolean success = TRUE; + GstCaps *buffer_caps; + GstStructure *structure; + guint32 in_format = 0; priv = image->priv; gst_vaapi_image_get_size(image, &width, &height); image_format = gst_vaapi_image_get_format(image); + /* get buffer format */ + buffer_caps = GST_BUFFER_CAPS(inbuf); + if (!buffer_caps) + return FALSE; + structure = gst_caps_get_structure(buffer_caps, 0); + if (!structure) + return FALSE; + if (!gst_structure_get_fourcc(structure, "format", &in_format)) + return FALSE; + /* currently only support YUV convert */ if ( (in_format != GST_MAKE_FOURCC('N','V','1','2') && in_format != GST_MAKE_FOURCC('Y','V','1','2') diff --git a/gst-libs/gst/vaapi/gstvaapiimage.h b/gst-libs/gst/vaapi/gstvaapiimage.h index 3b41f08..8cd1ad7 100644 --- a/gst-libs/gst/vaapi/gstvaapiimage.h +++ b/gst-libs/gst/vaapi/gstvaapiimage.h @@ -207,9 +207,7 @@ gst_vaapi_image_update_from_raw( gboolean gst_vaapi_convert_buffer_to_image( GstVaapiImage *image, - GstBuffer *buffer, - guint32 in_format); - + GstBuffer *buffer); G_END_DECLS diff --git a/gst/vaapi/gstvaapiupload.c b/gst/vaapi/gstvaapiupload.c index 420695e..550d033 100644 --- a/gst/vaapi/gstvaapiupload.c +++ b/gst/vaapi/gstvaapiupload.c @@ -332,17 +332,18 @@ gst_vaapiupload_init(GstVaapiUpload *upload) { GstPad *sinkpad, *srcpad; - upload->display = NULL; - upload->images = NULL; - upload->images_reset = FALSE; - upload->image_width = 0; - upload->image_height = 0; - upload->surfaces = NULL; - upload->surfaces_reset = FALSE; - upload->surface_width = 0; - upload->surface_height = 0; - upload->direct_rendering_caps = 0; - upload->direct_rendering = G_MAXUINT32; + upload->display = NULL; + upload->images = NULL; + upload->images_reset = FALSE; + upload->image_width = 0; + upload->image_height = 0; + upload->surfaces = NULL; + upload->surfaces_reset = FALSE; + upload->surface_width = 0; + upload->surface_height = 0; + upload->direct_rendering_caps = 0; + upload->direct_rendering = G_MAXUINT32; + upload->need_manual_upload = FALSE; /* Override buffer allocator on sink pad */ sinkpad = gst_element_get_static_pad(GST_ELEMENT(upload), "sink"); @@ -397,10 +398,7 @@ gst_vaapiupload_transform( GstVaapiVideoBuffer *vbuffer; GstVaapiSurface *surface; GstVaapiImage *image; - GstCaps *buffer_caps; gboolean success; - GstVaapiImageFormat buffer_format; - gboolean format_changed; vbuffer = GST_VAAPI_VIDEO_BUFFER(outbuf); surface = gst_vaapi_video_buffer_get_surface(vbuffer); @@ -429,16 +427,23 @@ gst_vaapiupload_transform( image = gst_vaapi_video_pool_get_object(upload->images); if (!image) - return GST_FLOW_UNEXPECTED; + goto error_put_image; + + if (!upload->need_manual_upload) { + gst_vaapi_image_update_from_buffer(image, inbuf, NULL); + } else { /* manually copy data to image*/ + success = gst_vaapi_upload_buffer_to_image(image, inbuf); + if (!success) + goto error_put_image; + } - gst_vaapi_image_update_from_buffer(image, inbuf, NULL); success = gst_vaapi_surface_put_image(surface, image); gst_vaapi_video_pool_put_object(upload->images, image); if (!success) goto error_put_image; flow_ok: - FPS_CALCULATION(vaapiconvert); + FPS_CALCULATION(vaapiupload); return GST_FLOW_OK; error_put_image: @@ -623,6 +628,83 @@ gst_vaapiupload_ensure_direct_rendering_caps( } } +typedef enum YUV_TYPE { + YUV_UNKOWN = 0, + YUV_411 = 1, + YUV_422 = 2, + YUV_444 = 4 +} YUV_TYPE; + +static YUV_TYPE +_image_format_to_yuv_type(guint32 fourcc) +{ + switch (fourcc) { + case GST_MAKE_FOURCC('N','V','1','2'): + case GST_MAKE_FOURCC('Y','V','1','2'): + case GST_MAKE_FOURCC('I','4','2','0'): + case GST_MAKE_FOURCC('N','V','2','1'): + return YUV_411; + + case GST_MAKE_FOURCC('Y','U','Y','2'): + case GST_MAKE_FOURCC('Y','V','Y','U'): + return YUV_422; + + case GST_MAKE_FOURCC('A','Y','U','V'): + return YUV_UNKOWN; + + default: + return YUV_UNKOWN; + } +} + +static GstCaps * +_get_nearest_caps(GstCaps *caps_list, GstCaps *src_caps) +{ + GstCaps *ret = NULL; + GstStructure *cur_struct, *tmp_struct; + guint32 cur_format, dest_format, tmp_format; + YUV_TYPE cur_type, tmp_type; + const GValue*tmp_val; + guint n_caps; + guint i; + guint min_diff, tmp_diff; + + cur_struct = gst_caps_get_structure(src_caps, 0); + tmp_val = gst_structure_get_value (cur_struct, "format"); + if (!tmp_val) + return NULL; + + cur_format = gst_value_get_fourcc(tmp_val); + if((cur_type = _image_format_to_yuv_type(cur_format)) == YUV_UNKOWN) + return NULL; + + n_caps = gst_caps_get_size(caps_list); + min_diff = 100; + dest_format = 0; + for (i = 0; i < n_caps; ++i) { + tmp_struct = gst_caps_get_structure(caps_list, i); + tmp_val = gst_structure_get_value (tmp_struct, "format"); + if (!tmp_val) + continue; + tmp_format = gst_value_get_fourcc(tmp_val); + if ((tmp_type = _image_format_to_yuv_type(tmp_format)) == YUV_UNKOWN) + continue; + tmp_diff = abs(tmp_type - cur_type); + if (tmp_diff < min_diff) { + min_diff = tmp_diff; + dest_format = tmp_format; + } + } + + if (dest_format == 0) + return NULL; + + ret = gst_caps_copy(src_caps); + tmp_struct = gst_caps_get_structure(ret, 0); + gst_structure_set(tmp_struct, "format", GST_TYPE_FOURCC, dest_format, NULL); + return ret; +} + static gboolean gst_vaapiupload_negotiate_buffers( GstVaapiUpload *upload, @@ -631,19 +713,42 @@ gst_vaapiupload_negotiate_buffers( ) { guint dr; + gboolean ret = TRUE; + GstCaps *image_allowed_caps = NULL; + GstCaps *image_caps = NULL; + + image_allowed_caps = gst_vaapi_display_get_image_caps(upload->display); + if (gst_caps_can_intersect(incaps, image_allowed_caps)) { + image_caps = gst_caps_ref(incaps); + upload->need_manual_upload = FALSE; + } else { + image_caps = _get_nearest_caps(image_allowed_caps, incaps); + upload->need_manual_upload = TRUE; + } - if (!gst_vaapiupload_ensure_image_pool(upload, incaps)) - return FALSE; + if (!gst_vaapiupload_ensure_image_pool(upload, image_caps)) + goto failed; if (!gst_vaapiupload_ensure_surface_pool(upload, outcaps)) - return FALSE; + goto failed; - if (upload->direct_rendering) - gst_vaapiupload_ensure_direct_rendering_caps(upload, incaps); + if (upload->direct_rendering && !upload->need_manual_upload) + gst_vaapiupload_ensure_direct_rendering_caps(upload, incaps); dr = MIN(upload->direct_rendering, upload->direct_rendering_caps); if (upload->direct_rendering != dr) { upload->direct_rendering = dr; - return TRUE; + GST_DEBUG("direct-rendering level: %d", dr); + } + ret = TRUE; + goto end; + + failed: + ret = FALSE; + + end: + gst_caps_unref(image_caps); + gst_caps_unref(image_allowed_caps); + return ret; } static gboolean @@ -698,6 +803,10 @@ gst_vaapiupload_buffer_alloc( GstVaapiSurface *surface = NULL; GstVaapiVideoBuffer *vbuffer; + /* already checked */ + if (!upload->direct_rendering) + return GST_FLOW_OK; + /* Check if we can use direct-rendering */ if (!gst_vaapiupload_negotiate_buffers(upload, caps, caps)) goto error; diff --git a/gst/vaapi/gstvaapiupload.h b/gst/vaapi/gstvaapiupload.h index 386a62c..c5e37c4 100644 --- a/gst/vaapi/gstvaapiupload.h +++ b/gst/vaapi/gstvaapiupload.h @@ -77,6 +77,7 @@ struct _GstVaapiUpload { guint direct_rendering; unsigned int images_reset : 1; unsigned int surfaces_reset : 1; + unsigned int need_manual_convert : 1; }; struct _GstVaapiUploadClass { -- 2.7.4