image.c 10.9 KB
Newer Older
gb's avatar
gb committed
1 2 3
/*
 *  image.c - Image utilities for the tests
 *
4
 *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5
 *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
6 7
 *  Copyright (C) 2013 Intel Corporation
 *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
gb's avatar
gb committed
8
 *
warly's avatar
warly committed
9 10 11 12
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public License
 *  as published by the Free Software Foundation; either version 2.1
 *  of the License, or (at your option) any later version.
gb's avatar
gb committed
13
 *
warly's avatar
warly committed
14
 *  This library is distributed in the hope that it will be useful,
gb's avatar
gb committed
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
warly's avatar
warly committed
16 17
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
gb's avatar
gb committed
18
 *
warly's avatar
warly committed
19 20 21 22
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA 02110-1301 USA
23
 */
gb's avatar
gb committed
24 25 26

#include "image.h"

27
static gboolean
28 29
image_draw_rectangle (GstVaapiImage * image,
    gint x, gint y, guint width, guint height, guint32 color, guint32 flags);
30 31

static gboolean
32 33
image_draw_color_rectangles (GstVaapiImage * image,
    guint width, guint height, const guint32 colors[4], guint32 flags)
34
{
35 36 37 38 39 40 41 42 43 44 45 46
  const guint w = width / 2;
  const guint h = height / 2;

  if (!image_draw_rectangle (image, 0, 0, w, h, colors[0], flags))
    return FALSE;
  if (!image_draw_rectangle (image, w, 0, w, h, colors[1], flags))
    return FALSE;
  if (!image_draw_rectangle (image, 0, h, w, h, colors[2], flags))
    return FALSE;
  if (!image_draw_rectangle (image, w, h, w, h, colors[3], flags))
    return FALSE;
  return TRUE;
47 48
}

gb's avatar
gb committed
49
GstVaapiImage *
50 51
image_generate (GstVaapiDisplay * display,
    GstVideoFormat format, guint width, guint height)
gb's avatar
gb committed
52
{
53
  return image_generate_full (display, format, width, height, 0);
54 55 56
}

GstVaapiImage *
57 58
image_generate_full (GstVaapiDisplay * display,
    GstVideoFormat format, guint width, guint height, guint32 flags)
59
{
60
  GstVaapiImage *image;
gb's avatar
gb committed
61

62 63 64 65 66 67 68 69 70
  static const guint32 rgb_colors[4] =
      { 0xffff0000, 0xff00ff00, 0xff0000ff, 0xff000000 };
  static const guint32 bgr_colors[4] =
      { 0xff000000, 0xff0000ff, 0xff00ff00, 0xffff0000 };
  static const guint32 inv_colors[4] =
      { 0xffdeadc0, 0xffdeadc0, 0xffdeadc0, 0xffdeadc0 };

  image = gst_vaapi_image_new (display, format, width, height);
  if (!image)
gb's avatar
gb committed
71
    return NULL;
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89

  if (flags) {
    if (!image_draw_color_rectangles (image, width, height,
            ((flags & GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD) ?
                rgb_colors : inv_colors),
            GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD))
      goto error;

    if (!image_draw_color_rectangles (image, width, height,
            ((flags & GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD) ?
                bgr_colors : inv_colors),
            GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD))
      goto error;
  } else if (!image_draw_color_rectangles (image, width, height, rgb_colors, 0))
    goto error;
  return image;

error:
90
  gst_vaapi_image_unref (image);
91
  return NULL;
gb's avatar
gb committed
92 93
}

94 95 96 97 98 99
typedef void (*DrawRectFunc) (guchar * pixels[3],
    guint stride[3], gint x, gint y, guint width, guint height, guint32 color);

static void
draw_rect_ARGB (guchar * pixels[3],
    guint stride[3], gint x, gint y, guint width, guint height, guint32 color)
gb's avatar
gb committed
100
{
101
  guint i, j;
gb's avatar
gb committed
102

103
  color = GUINT32_TO_BE (color);
gb's avatar
gb committed
104

105 106 107 108 109
  for (j = 0; j < height; j++) {
    guint32 *p = (guint32 *) (pixels[0] + (y + j) * stride[0] + x * 4);
    for (i = 0; i < width; i++)
      p[i] = color;
  }
gb's avatar
gb committed
110 111
}

112 113 114
static void
draw_rect_BGRA (guchar * pixels[3],
    guint stride[3], gint x, gint y, guint width, guint height, guint32 color)
gb's avatar
gb committed
115
{
116 117
  // Converts ARGB color to BGRA
  color = GUINT32_SWAP_LE_BE (color);
gb's avatar
gb committed
118

119
  draw_rect_ARGB (pixels, stride, x, y, width, height, color);
gb's avatar
gb committed
120 121
}

122 123 124
static void
draw_rect_RGBA (guchar * pixels[3],
    guint stride[3], gint x, gint y, guint width, guint height, guint32 color)
gb's avatar
gb committed
125
{
126 127
  // Converts ARGB color to RGBA
  color = ((color >> 24) & 0xff) | ((color & 0xffffff) << 8);
gb's avatar
gb committed
128

129
  draw_rect_ARGB (pixels, stride, x, y, width, height, color);
gb's avatar
gb committed
130 131
}

132 133 134
static void
draw_rect_ABGR (guchar * pixels[3],
    guint stride[3], gint x, gint y, guint width, guint height, guint32 color)
gb's avatar
gb committed
135
{
136 137 138
  // Converts ARGB color to ABGR
  color = ((color & 0xff00ff00) |
      ((color >> 16) & 0xff) | ((color & 0xff) << 16));
gb's avatar
gb committed
139

140
  draw_rect_ARGB (pixels, stride, x, y, width, height, color);
gb's avatar
gb committed
141 142
}

143 144 145 146
static void
draw_rect_NV12 (                // Y, UV planes
    guchar * pixels[3],
    guint stride[3], gint x, gint y, guint width, guint height, guint32 color)
gb's avatar
gb committed
147
{
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
  const guchar Y = color >> 16;
  const guchar Cb = color >> 8;
  const guchar Cr = color;
  guchar *dst;
  guint i, j;

  dst = pixels[0] + y * stride[0] + x;
  for (j = 0; j < height; j++, dst += stride[0])
    for (i = 0; i < width; i++)
      dst[i] = Y;

  x /= 2;
  y /= 2;
  width /= 2;
  height /= 2;

  dst = pixels[1] + y * stride[1] + x * 2;
  for (j = 0; j < height; j++, dst += stride[1])
    for (i = 0; i < width; i++) {
      dst[2 * i + 0] = Cb;
      dst[2 * i + 1] = Cr;
    }
gb's avatar
gb committed
170 171
}

172 173 174 175
static void
draw_rect_YV12 (                // Y, V, U planes
    guchar * pixels[3],
    guint stride[3], gint x, gint y, guint width, guint height, guint32 color)
gb's avatar
gb committed
176
{
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
  const guchar Y = color >> 16;
  const guchar Cb = color >> 8;
  const guchar Cr = color;
  guchar *pY, *pU, *pV;
  guint i, j;

  pY = pixels[0] + y * stride[0] + x;
  for (j = 0; j < height; j++, pY += stride[0])
    for (i = 0; i < width; i++)
      pY[i] = Y;

  x /= 2;
  y /= 2;
  width /= 2;
  height /= 2;

  pV = pixels[1] + y * stride[1] + x;
  pU = pixels[2] + y * stride[2] + x;
  for (j = 0; j < height; j++, pU += stride[1], pV += stride[2])
    for (i = 0; i < width; i++) {
      pU[i] = Cb;
      pV[i] = Cr;
    }
gb's avatar
gb committed
200 201
}

202 203 204 205
static void
draw_rect_I420 (                // Y, U, V planes
    guchar * pixels[3],
    guint stride[3], gint x, gint y, guint width, guint height, guint32 color)
gb's avatar
gb committed
206
{
207 208
  guchar *new_pixels[3] = { pixels[0], pixels[2], pixels[1] };
  guint new_stride[3] = { stride[0], stride[2], stride[1] };
gb's avatar
gb committed
209

210
  draw_rect_YV12 (new_pixels, new_stride, x, y, width, height, color);
gb's avatar
gb committed
211 212
}

213 214
static void
draw_rect_YUV422 (guchar * pixels[3], guint stride[3],
215 216
    gint x, gint y, guint width, guint height, guint32 color)
{
217 218 219 220 221 222 223 224 225
  guint i, j;

  width /= 2;
  for (j = 0; j < height; j++) {
    guint32 *const p = (guint32 *)
        (pixels[0] + (y + j) * stride[0] + x * 2);
    for (i = 0; i < width; i++)
      p[i] = color;
  }
226 227
}

228 229
static void
draw_rect_YUY2 (guchar * pixels[3], guint stride[3],
230 231
    gint x, gint y, guint width, guint height, guint32 color)
{
232 233 234
  const guchar Y = color >> 16;
  const guchar Cb = color >> 8;
  const guchar Cr = color;
235

236 237
  color = (Y << 24) | (Cb << 16) | (Y << 8) | Cr;
  draw_rect_YUV422 (pixels, stride, x, y, width, height, GUINT32_TO_BE (color));
238 239
}

240 241
static void
draw_rect_UYVY (guchar * pixels[3], guint stride[3],
242 243
    gint x, gint y, guint width, guint height, guint32 color)
{
244 245 246
  const guchar Y = color >> 16;
  const guchar Cb = color >> 8;
  const guchar Cr = color;
247

248 249
  color = (Cb << 24) | (Y << 16) | (Cr << 8) | Y;
  draw_rect_YUV422 (pixels, stride, x, y, width, height, GUINT32_TO_BE (color));
250 251
}

252 253 254
static void
draw_rect_AYUV (guchar * pixels[3],
    guint stride[3], gint x, gint y, guint width, guint height, guint32 color)
gb's avatar
gb committed
255
{
256
  guint i, j;
gb's avatar
gb committed
257

258
  color = color | 0xff000000;
gb's avatar
gb committed
259

260 261 262 263 264
  for (j = 0; j < height; j++) {
    guint32 *p = (guint32 *) (pixels[0] + (y + j) * stride[0] + x * 4);
    for (i = 0; i < width; i++)
      p[i] = color;
  }
gb's avatar
gb committed
265 266
}

267 268
static inline guint32
argb2yuv (guint32 color)
gb's avatar
gb committed
269
{
270 271 272
  const gint32 r = (color >> 16) & 0xff;
  const gint32 g = (color >> 8) & 0xff;
  const gint32 b = (color) & 0xff;
gb's avatar
gb committed
273

274 275 276
  const guint32 y = ((306 * r + 601 * g + 116 * b) >> 10);
  const guint32 u = ((-172 * r - 339 * g + 512 * b) >> 10) + 128;
  const guint32 v = ((512 * r - 428 * g - 83 * b) >> 10) + 128;
gb's avatar
gb committed
277

278
  return (y << 16) | (u << 8) | v;
gb's avatar
gb committed
279 280 281
}

gboolean
282 283
image_draw_rectangle (GstVaapiImage * image,
    gint x, gint y, guint width, guint height, guint32 color, guint32 flags)
gb's avatar
gb committed
284
{
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
  const GstVideoFormat image_format = gst_vaapi_image_get_format (image);
  const guint image_width = gst_vaapi_image_get_width (image);
  const guint image_height = gst_vaapi_image_get_height (image);
  GstVaapiDisplay *display;
  guchar *pixels[3];
  guint stride[3];
  DrawRectFunc draw_rect = NULL;
  guint i;

  static const struct
  {
    GstVideoFormat format;
    DrawRectFunc draw_rect;
  }
  map[] = {
300
#define _(FORMAT) { GST_VIDEO_FORMAT_##FORMAT, draw_rect_##FORMAT }
301
    _(ARGB),
gb's avatar
gb committed
302
        _(BGRA),
303
        _(RGBA), _(ABGR), _(NV12), _(YV12), _(I420), _(YUY2), _(UYVY), _(AYUV),
gb's avatar
gb committed
304
#undef  _
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
    {
    0,}
  };

  for (i = 0; !draw_rect && map[i].format; i++)
    if (map[i].format == image_format)
      draw_rect = map[i].draw_rect;
  if (!draw_rect)
    return FALSE;

  if (x < 0)
    x = 0;
  if (y < 0)
    y = 0;
  if (width > image_width - x)
    width = image_width - x;
  if (height > image_height - y)
    height = image_height - y;

324
  display = gst_vaapi_image_get_display (image);
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
  if (!display)
    return FALSE;

  if (!gst_vaapi_image_map (image))
    return FALSE;

  for (i = 0; i < gst_vaapi_image_get_plane_count (image); i++) {
    pixels[i] = gst_vaapi_image_get_plane (image, i);
    stride[i] = gst_vaapi_image_get_pitch (image, i);
    switch (flags) {
      case GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD:
        pixels[i] += stride[i];
        // fall-through
      case GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD:
        stride[i] *= 2;
        break;
gb's avatar
gb committed
341
    }
342
  }
gb's avatar
gb committed
343

344 345
  if (flags)
    y /= 2, height /= 2;
346

347 348
  if (gst_vaapi_video_format_is_yuv (image_format))
    color = argb2yuv (color);
gb's avatar
gb committed
349

350 351
  draw_rect (pixels, stride, x, y, width, height, color);
  return gst_vaapi_image_unmap (image);
gb's avatar
gb committed
352
}
gb's avatar
gb committed
353 354

gboolean
355
image_upload (GstVaapiImage * image, GstVaapiSurface * surface)
gb's avatar
gb committed
356
{
357 358 359 360 361 362 363 364 365
  GstVaapiDisplay *display;
  GstVideoFormat format;
  GstVaapiImage *surface_image;
  GstVaapiSubpicture *subpicture;
  gboolean success;

  display = gst_vaapi_object_get_display (GST_VAAPI_OBJECT (surface));
  if (!display)
    return FALSE;
366

367 368 369
  format = gst_vaapi_image_get_format (image);
  if (!format)
    return FALSE;
gb's avatar
gb committed
370

371 372
  if (gst_vaapi_surface_put_image (surface, image))
    return TRUE;
gb's avatar
gb committed
373

374 375 376
  surface_image = gst_vaapi_surface_derive_image (surface);
  if (surface_image) {
    success = gst_vaapi_image_copy (surface_image, image);
377
    gst_vaapi_image_unref (surface_image);
378 379 380
    if (success)
      return TRUE;
  }
gb's avatar
gb committed
381

382 383
  g_print ("could not upload %s image to surface\n",
      gst_vaapi_video_format_to_string (format));
gb's avatar
gb committed
384

385 386
  if (!gst_vaapi_display_has_subpicture_format (display, format, NULL))
    return FALSE;
gb's avatar
gb committed
387

388 389 390 391 392 393 394 395 396 397 398 399
  g_print ("trying as a subpicture\n");

  subpicture = gst_vaapi_subpicture_new (image, 0);
  if (!subpicture)
    g_error ("could not create VA subpicture");

  if (!gst_vaapi_surface_associate_subpicture (surface, subpicture, NULL, NULL))
    g_error ("could not associate subpicture to surface");

  /* The surface holds a reference to the subpicture. This is safe */
  gst_vaapi_object_unref (subpicture);
  return TRUE;
gb's avatar
gb committed
400
}