Optimize gst_vaapi_image_is_linear() and simplify gst_vaapi_image_update_from_buffer().

This commit is contained in:
gb 2010-03-17 10:43:02 +00:00
parent bcb5d3f138
commit cf432f9ec8

View file

@ -36,13 +36,15 @@ G_DEFINE_TYPE(GstVaapiImage, gst_vaapi_image, G_TYPE_OBJECT);
struct _GstVaapiImagePrivate { struct _GstVaapiImagePrivate {
GstVaapiDisplay *display; GstVaapiDisplay *display;
gboolean is_constructed; VAImage internal_image;
VAImage image; VAImage image;
guchar *image_data; guchar *image_data;
GstVaapiImageFormat internal_format; GstVaapiImageFormat internal_format;
GstVaapiImageFormat format; GstVaapiImageFormat format;
guint width; guint width;
guint height; guint height;
guint is_constructed : 1;
guint is_linear : 1;
}; };
enum { enum {
@ -69,16 +71,17 @@ gst_vaapi_image_destroy(GstVaapiImage *image)
gst_vaapi_image_unmap(image); gst_vaapi_image_unmap(image);
if (priv->image.image_id != VA_INVALID_ID) { if (priv->internal_image.image_id != VA_INVALID_ID) {
GST_VAAPI_DISPLAY_LOCK(priv->display); GST_VAAPI_DISPLAY_LOCK(priv->display);
status = vaDestroyImage( status = vaDestroyImage(
GST_VAAPI_DISPLAY_VADISPLAY(priv->display), GST_VAAPI_DISPLAY_VADISPLAY(priv->display),
priv->image.image_id priv->internal_image.image_id
); );
GST_VAAPI_DISPLAY_UNLOCK(priv->display); GST_VAAPI_DISPLAY_UNLOCK(priv->display);
if (!vaapi_check_status(status, "vaDestroyImage()")) if (!vaapi_check_status(status, "vaDestroyImage()"))
g_warning("failed to destroy image 0x%08x\n", priv->image.image_id); g_warning("failed to destroy image 0x%08x\n",
priv->image.image_id = VA_INVALID_ID; priv->internal_image.image_id);
priv->internal_image.image_id = VA_INVALID_ID;
} }
if (priv->display) { if (priv->display) {
@ -107,40 +110,93 @@ _gst_vaapi_image_create(GstVaapiImage *image, GstVaapiImageFormat format)
(VAImageFormat *)va_format, (VAImageFormat *)va_format,
priv->width, priv->width,
priv->height, priv->height,
&priv->image &priv->internal_image
); );
GST_VAAPI_DISPLAY_UNLOCK(priv->display); GST_VAAPI_DISPLAY_UNLOCK(priv->display);
return (status == VA_STATUS_SUCCESS && if (status != VA_STATUS_SUCCESS ||
priv->image.format.fourcc == va_format->fourcc); priv->internal_image.format.fourcc != va_format->fourcc)
return FALSE;
priv->internal_format = format;
return TRUE;
}
static gboolean
_gst_vaapi_image_is_linear(GstVaapiImage *image)
{
GstVaapiImagePrivate * const priv = image->priv;
guint i, width, height, width2, height2, data_size;
for (i = 1; i < priv->image.num_planes; i++)
if (priv->image.offsets[i] < priv->image.offsets[i - 1])
return FALSE;
width = priv->width;
height = priv->height;
width2 = (width + 1) / 2;
height2 = (height + 1) / 2;
switch (priv->internal_format) {
case GST_VAAPI_IMAGE_NV12:
case GST_VAAPI_IMAGE_YV12:
case GST_VAAPI_IMAGE_I420:
data_size = width * height + 2 * width2 * height2;
break;
case GST_VAAPI_IMAGE_ARGB:
case GST_VAAPI_IMAGE_RGBA:
case GST_VAAPI_IMAGE_ABGR:
case GST_VAAPI_IMAGE_BGRA:
data_size = 4 * width * height;
break;
default:
g_error("FIXME: incomplete formats");
break;
}
return priv->image.data_size == data_size;
} }
static gboolean static gboolean
gst_vaapi_image_create(GstVaapiImage *image) gst_vaapi_image_create(GstVaapiImage *image)
{ {
GstVaapiImagePrivate * const priv = image->priv; GstVaapiImagePrivate * const priv = image->priv;
GstVaapiImageFormat format = priv->format;
const VAImageFormat *va_format;
if (_gst_vaapi_image_create(image, priv->format)) { if (!_gst_vaapi_image_create(image, format)) {
priv->internal_format = priv->format; switch (format) {
return TRUE; case GST_VAAPI_IMAGE_I420:
format = GST_VAAPI_IMAGE_YV12;
break;
case GST_VAAPI_IMAGE_YV12:
format = GST_VAAPI_IMAGE_I420;
break;
default:
format = 0;
break;
}
if (!format || !_gst_vaapi_image_create(image, format))
return FALSE;
} }
priv->image = priv->internal_image;
switch (priv->format) { if (priv->format != priv->internal_format) {
case GST_VAAPI_IMAGE_I420: switch (priv->format) {
priv->internal_format = GST_VAAPI_IMAGE_YV12; case GST_VAAPI_IMAGE_YV12:
break; case GST_VAAPI_IMAGE_I420:
case GST_VAAPI_IMAGE_YV12: va_format = gst_vaapi_image_format_get_va_format(priv->format);
priv->internal_format = GST_VAAPI_IMAGE_I420; if (!va_format)
break; return FALSE;
default: priv->image.format = *va_format;
priv->internal_format = 0; SWAP_UINT(priv->image.offsets[1], priv->image.offsets[2]);
break; SWAP_UINT(priv->image.pitches[1], priv->image.pitches[2]);
break;
default:
break;
}
} }
if (!priv->internal_format)
return FALSE;
if (!_gst_vaapi_image_create(image, priv->internal_format))
return FALSE;
GST_DEBUG("image 0x%08x", priv->image.image_id); GST_DEBUG("image 0x%08x", priv->image.image_id);
priv->is_linear = _gst_vaapi_image_is_linear(image);
return TRUE; return TRUE;
} }
@ -290,16 +346,23 @@ gst_vaapi_image_init(GstVaapiImage *image)
{ {
GstVaapiImagePrivate *priv = GST_VAAPI_IMAGE_GET_PRIVATE(image); GstVaapiImagePrivate *priv = GST_VAAPI_IMAGE_GET_PRIVATE(image);
image->priv = priv; image->priv = priv;
priv->display = NULL; priv->display = NULL;
priv->image_data = NULL; priv->image_data = NULL;
priv->width = 0; priv->width = 0;
priv->height = 0; priv->height = 0;
priv->format = 0; priv->internal_format = 0;
priv->format = 0;
priv->is_constructed = FALSE;
priv->is_linear = FALSE;
memset(&priv->internal_image, 0, sizeof(priv->internal_image));
priv->internal_image.image_id = VA_INVALID_ID;
priv->internal_image.buf = VA_INVALID_ID;
memset(&priv->image, 0, sizeof(priv->image)); memset(&priv->image, 0, sizeof(priv->image));
priv->image.image_id = VA_INVALID_ID; priv->image.image_id = VA_INVALID_ID;
priv->image.buf = VA_INVALID_ID; priv->image.buf = VA_INVALID_ID;
} }
GstVaapiImage * GstVaapiImage *
@ -340,20 +403,9 @@ gst_vaapi_image_get_image(GstVaapiImage *image, VAImage *va_image)
g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE); g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
g_return_val_if_fail(image->priv->is_constructed, FALSE); g_return_val_if_fail(image->priv->is_constructed, FALSE);
if (!va_image) if (va_image)
return TRUE; *va_image = image->priv->image;
*va_image = image->priv->image;
if (image->priv->format != image->priv->internal_format) {
if (!(image->priv->format == GST_VAAPI_IMAGE_I420 &&
image->priv->internal_format == GST_VAAPI_IMAGE_YV12) &&
!(image->priv->format == GST_VAAPI_IMAGE_YV12 &&
image->priv->internal_format == GST_VAAPI_IMAGE_I420))
return FALSE;
SWAP_UINT(va_image->offsets[1], va_image->offsets[2]);
SWAP_UINT(va_image->pitches[1], va_image->pitches[2]);
}
return TRUE; return TRUE;
} }
@ -409,41 +461,10 @@ gst_vaapi_image_get_size(GstVaapiImage *image, guint *pwidth, guint *pheight)
gboolean gboolean
gst_vaapi_image_is_linear(GstVaapiImage *image) gst_vaapi_image_is_linear(GstVaapiImage *image)
{ {
VAImage va_image;
guint i, width, height, width2, height2, data_size;
g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE); g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
g_return_val_if_fail(image->priv->is_constructed, FALSE); g_return_val_if_fail(image->priv->is_constructed, FALSE);
if (!gst_vaapi_image_get_image(image, &va_image)) return image->priv->is_linear;
return FALSE;
for (i = 1; i < va_image.num_planes; i++)
if (va_image.offsets[i] < va_image.offsets[i - 1])
return FALSE;
width = image->priv->width;
height = image->priv->height;
width2 = (width + 1) / 2;
height2 = (height + 1) / 2;
switch (image->priv->internal_format) {
case GST_VAAPI_IMAGE_NV12:
case GST_VAAPI_IMAGE_YV12:
case GST_VAAPI_IMAGE_I420:
data_size = width * height + 2 * width2 * height2;
break;
case GST_VAAPI_IMAGE_ARGB:
case GST_VAAPI_IMAGE_RGBA:
case GST_VAAPI_IMAGE_ABGR:
case GST_VAAPI_IMAGE_BGRA:
data_size = 4 * width * height;
break;
default:
g_error("FIXME: incomplete formats");
break;
}
return va_image.data_size == data_size;
} }
static inline gboolean static inline gboolean
@ -564,7 +585,6 @@ gst_vaapi_image_update_from_buffer(GstVaapiImage *image, GstBuffer *buffer)
guint i, j; guint i, j;
guchar *data; guchar *data;
guint32 data_size; guint32 data_size;
gboolean swap_YUV;
g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE); g_return_val_if_fail(GST_VAAPI_IS_IMAGE(image), FALSE);
g_return_val_if_fail(image->priv->is_constructed, FALSE); g_return_val_if_fail(image->priv->is_constructed, FALSE);
@ -582,12 +602,6 @@ gst_vaapi_image_update_from_buffer(GstVaapiImage *image, GstBuffer *buffer)
if (format != priv->format) if (format != priv->format)
return FALSE; return FALSE;
swap_YUV = (priv->format != priv->internal_format &&
((priv->format == GST_VAAPI_IMAGE_I420 &&
priv->internal_format == GST_VAAPI_IMAGE_YV12) ||
(priv->format == GST_VAAPI_IMAGE_YV12 &&
priv->internal_format == GST_VAAPI_IMAGE_I420)));
structure = gst_caps_get_structure(caps, 0); structure = gst_caps_get_structure(caps, 0);
gst_structure_get_int(structure, "width", &width); gst_structure_get_int(structure, "width", &width);
gst_structure_get_int(structure, "height", &height); gst_structure_get_int(structure, "height", &height);
@ -597,7 +611,7 @@ gst_vaapi_image_update_from_buffer(GstVaapiImage *image, GstBuffer *buffer)
if (!gst_vaapi_image_map(image)) if (!gst_vaapi_image_map(image))
return FALSE; return FALSE;
if (format == priv->internal_format && data_size == priv->image.data_size) if (priv->is_linear && data_size == priv->image.data_size)
memcpy(priv->image_data, data, data_size); memcpy(priv->image_data, data, data_size);
else { else {
/* XXX: copied from gst_video_format_get_row_stride() -- no NV12? */ /* XXX: copied from gst_video_format_get_row_stride() -- no NV12? */
@ -649,20 +663,6 @@ gst_vaapi_image_update_from_buffer(GstVaapiImage *image, GstBuffer *buffer)
} }
if (size2 != data_size) if (size2 != data_size)
g_error("data_size mismatch %d / %u", size2, data_size); g_error("data_size mismatch %d / %u", size2, data_size);
if (swap_YUV) {
guint offset = offsets[1];
guint stride = pitches[1];
guint width = widths [1];
guint height = heights[1];
offsets[1] = offsets[2];
pitches[1] = pitches[2];
widths [1] = widths [2];
heights[1] = heights[2];
offsets[2] = offset;
pitches[2] = stride;
widths [2] = width;
heights[2] = height;
}
for (i = 0; i < priv->image.num_planes; i++) { for (i = 0; i < priv->image.num_planes; i++) {
guchar *src = data + offsets[i]; guchar *src = data + offsets[i];
guchar *dst = priv->image_data + priv->image.offsets[i]; guchar *dst = priv->image_data + priv->image.offsets[i];