packaging: add packaging folder and update submodule pkgs
[platform/upstream/gstreamer-vaapi.git] / tests / image.c
1 /*
2  *  image.c - Image utilities for the tests
3  *
4  *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5  *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
6  *  Copyright (C) 2013 Intel Corporation
7  *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
8  *
9  *  This library is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU Lesser General Public License
11  *  as published by the Free Software Foundation; either version 2.1
12  *  of the License, or (at your option) any later version.
13  *
14  *  This library is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  Lesser General Public License for more details.
18  *
19  *  You should have received a copy of the GNU Lesser General Public
20  *  License along with this library; if not, write to the Free
21  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  *  Boston, MA 02110-1301 USA
23  */
24
25 #include "image.h"
26
27 static gboolean
28 image_draw_rectangle(
29     GstVaapiImage *image,
30     gint           x,
31     gint           y,
32     guint          width,
33     guint          height,
34     guint32        color,
35     guint32        flags
36 );
37
38 static gboolean
39 image_draw_color_rectangles(
40     GstVaapiImage      *image,
41     guint               width,
42     guint               height,
43     const guint32       colors[4],
44     guint32             flags
45     )
46 {
47     const guint w = width / 2;
48     const guint h = height / 2;
49
50     if (!image_draw_rectangle(image, 0, 0, w, h, colors[0], flags))
51         return FALSE;
52     if (!image_draw_rectangle(image, w, 0, w, h, colors[1], flags))
53         return FALSE;
54     if (!image_draw_rectangle(image, 0, h, w, h, colors[2], flags))
55         return FALSE;
56     if (!image_draw_rectangle(image, w, h, w, h, colors[3], flags))
57         return FALSE;
58     return TRUE;
59 }
60
61 GstVaapiImage *
62 image_generate(
63     GstVaapiDisplay    *display,
64     GstVideoFormat      format,
65     guint               width,
66     guint               height
67 )
68 {
69     return image_generate_full(display, format, width, height, 0);
70 }
71
72 GstVaapiImage *
73 image_generate_full(
74     GstVaapiDisplay    *display,
75     GstVideoFormat      format,
76     guint               width,
77     guint               height,
78     guint32             flags
79 )
80 {
81     GstVaapiImage *image;
82
83     static const guint32 rgb_colors[4] =
84         { 0xffff0000, 0xff00ff00, 0xff0000ff, 0xff000000 };
85     static const guint32 bgr_colors[4] =
86         { 0xff000000, 0xff0000ff, 0xff00ff00, 0xffff0000 };
87     static const guint32 inv_colors[4] =
88         { 0xffdeadc0, 0xffdeadc0, 0xffdeadc0, 0xffdeadc0 };
89
90     image = gst_vaapi_image_new(display, format, width, height);
91     if (!image)
92         return NULL;
93
94     if (flags) {
95         if (!image_draw_color_rectangles(image, width, height,
96                 ((flags & GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD) ?
97                  rgb_colors : inv_colors),
98                 GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD))
99             goto error;
100
101         if (!image_draw_color_rectangles(image, width, height,
102                 ((flags & GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD) ?
103                  bgr_colors : inv_colors),
104                 GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD))
105             goto error;
106     }
107     else if (!image_draw_color_rectangles(image, width, height, rgb_colors, 0))
108         goto error;
109     return image;
110
111 error:
112     gst_vaapi_object_unref(image);
113     return NULL;
114 }
115
116 typedef void (*DrawRectFunc)(
117     guchar *pixels[3],
118     guint   stride[3],
119     gint    x,
120     gint    y,
121     guint   width,
122     guint   height,
123     guint32 color
124 );
125
126 static void draw_rect_ARGB(
127     guchar *pixels[3],
128     guint   stride[3],
129     gint    x,
130     gint    y,
131     guint   width,
132     guint   height,
133     guint32 color
134 )
135 {
136     guint i, j;
137
138     color = GUINT32_TO_BE(color);
139
140     for (j = 0; j < height; j++) {
141         guint32 *p = (guint32 *)(pixels[0] + (y + j) * stride[0] + x * 4);
142         for (i = 0; i < width; i++)
143             p[i] = color;
144     }
145 }
146
147 static void draw_rect_BGRA(
148     guchar *pixels[3],
149     guint   stride[3],
150     gint    x,
151     gint    y,
152     guint   width,
153     guint   height,
154     guint32 color
155 )
156 {
157     // Converts ARGB color to BGRA
158     color = GUINT32_SWAP_LE_BE(color);
159
160     draw_rect_ARGB(pixels, stride, x, y, width, height, color);
161 }
162
163 static void draw_rect_RGBA(
164     guchar *pixels[3],
165     guint   stride[3],
166     gint    x,
167     gint    y,
168     guint   width,
169     guint   height,
170     guint32 color
171 )
172 {
173     // Converts ARGB color to RGBA
174     color = ((color >> 24) & 0xff) | ((color & 0xffffff) << 8);
175
176     draw_rect_ARGB(pixels, stride, x, y, width, height, color);
177 }
178
179 static void draw_rect_ABGR(
180     guchar *pixels[3],
181     guint   stride[3],
182     gint    x,
183     gint    y,
184     guint   width,
185     guint   height,
186     guint32 color
187 )
188 {
189     // Converts ARGB color to ABGR
190     color = ((color & 0xff00ff00)   |
191              ((color >> 16) & 0xff) |
192              ((color & 0xff) << 16));
193
194     draw_rect_ARGB(pixels, stride, x, y, width, height, color);
195 }
196
197 static void draw_rect_NV12( // Y, UV planes
198     guchar *pixels[3],
199     guint   stride[3],
200     gint    x,
201     gint    y,
202     guint   width,
203     guint   height,
204     guint32 color
205 )
206 {
207     const guchar Y  = color >> 16;
208     const guchar Cb = color >> 8;
209     const guchar Cr = color;
210     guchar *dst;
211     guint i, j;
212
213     dst = pixels[0] + y * stride[0] + x;
214     for (j = 0; j < height; j++, dst += stride[0])
215         for (i = 0; i < width; i++)
216             dst[i] = Y;
217
218     x      /= 2;
219     y      /= 2;
220     width  /= 2;
221     height /= 2;
222
223     dst = pixels[1] + y * stride[1] + x * 2;
224     for (j = 0; j < height; j++, dst += stride[1])
225         for (i = 0; i < width; i++) {
226             dst[2*i + 0] = Cb;
227             dst[2*i + 1] = Cr;
228         }
229 }
230
231 static void draw_rect_YV12( // Y, V, U planes
232     guchar *pixels[3],
233     guint   stride[3],
234     gint    x,
235     gint    y,
236     guint   width,
237     guint   height,
238     guint32 color
239 )
240 {
241     const guchar Y  = color >> 16;
242     const guchar Cb = color >> 8;
243     const guchar Cr = color;
244     guchar *pY, *pU, *pV;
245     guint i, j;
246
247     pY = pixels[0] + y * stride[0] + x;
248     for (j = 0; j < height; j++, pY += stride[0])
249         for (i = 0; i < width; i++)
250             pY[i] = Y;
251
252     x      /= 2;
253     y      /= 2;
254     width  /= 2;
255     height /= 2;
256
257     pV = pixels[1] + y * stride[1] + x;
258     pU = pixels[2] + y * stride[2] + x;
259     for (j = 0; j < height; j++, pU += stride[1], pV += stride[2])
260         for (i = 0; i < width; i++) {
261             pU[i] = Cb;
262             pV[i] = Cr;
263         }
264 }
265
266 static void draw_rect_I420( // Y, U, V planes
267     guchar *pixels[3],
268     guint   stride[3],
269     gint    x,
270     gint    y,
271     guint   width,
272     guint   height,
273     guint32 color
274 )
275 {
276     guchar *new_pixels[3] = { pixels[0], pixels[2], pixels[1] };
277     guint   new_stride[3] = { stride[0], stride[2], stride[1] };
278
279     draw_rect_YV12(new_pixels, new_stride, x, y, width, height, color);
280 }
281
282 static void draw_rect_YUV422(guchar *pixels[3], guint stride[3],
283     gint x, gint y, guint width, guint height, guint32 color)
284 {
285     guint i, j;
286
287     width /= 2;
288     for (j = 0; j < height; j++) {
289         guint32 * const p = (guint32 *)
290             (pixels[0] + (y + j) * stride[0] + x * 2);
291         for (i = 0; i < width; i++)
292             p[i] = color;
293     }
294 }
295
296 static void draw_rect_YUY2(guchar *pixels[3], guint stride[3],
297     gint x, gint y, guint width, guint height, guint32 color)
298 {
299     const guchar Y  = color >> 16;
300     const guchar Cb = color >> 8;
301     const guchar Cr = color;
302
303     color = (Y << 24) | (Cb << 16) | (Y << 8) | Cr;
304     draw_rect_YUV422(pixels, stride, x, y, width, height, GUINT32_TO_BE(color));
305 }
306
307 static void draw_rect_UYVY(guchar *pixels[3], guint stride[3],
308     gint x, gint y, guint width, guint height, guint32 color)
309 {
310     const guchar Y  = color >> 16;
311     const guchar Cb = color >> 8;
312     const guchar Cr = color;
313
314     color = (Cb << 24) | (Y << 16) | (Cr << 8) | Y;
315     draw_rect_YUV422(pixels, stride, x, y, width, height, GUINT32_TO_BE(color));
316 }
317
318 static void draw_rect_AYUV(
319     guchar *pixels[3],
320     guint   stride[3],
321     gint    x,
322     gint    y,
323     guint   width,
324     guint   height,
325     guint32 color
326 )
327 {
328     guint i, j;
329
330     color = color | 0xff000000;
331
332     for (j = 0; j < height; j++) {
333         guint32 *p = (guint32 *)(pixels[0] + (y + j) * stride[0] + x * 4);
334         for (i = 0; i < width; i++)
335             p[i] = color;
336     }
337 }
338
339 static inline guint32 argb2yuv(guint32 color)
340 {
341     const gint32 r = (color >> 16) & 0xff;
342     const gint32 g = (color >>  8) & 0xff;
343     const gint32 b = (color      ) & 0xff;
344
345     const guint32 y = (( 306 * r + 601 * g + 116 * b) >> 10);
346     const guint32 u = ((-172 * r - 339 * g + 512 * b) >> 10) + 128;
347     const guint32 v = (( 512 * r - 428 * g -  83 * b) >> 10) + 128;
348
349     return (y << 16) | (u << 8) | v;
350 }
351
352 gboolean
353 image_draw_rectangle(
354     GstVaapiImage *image,
355     gint           x,
356     gint           y,
357     guint          width,
358     guint          height,
359     guint32        color,
360     guint32        flags
361 )
362 {
363     const GstVideoFormat      image_format = gst_vaapi_image_get_format(image);
364     const guint               image_width  = gst_vaapi_image_get_width(image);
365     const guint               image_height = gst_vaapi_image_get_height(image);
366     GstVaapiDisplay          *display;
367     guchar                   *pixels[3];
368     guint                     stride[3];
369     DrawRectFunc              draw_rect = NULL;
370     guint                     i;
371
372     static const struct {
373         GstVideoFormat        format;
374         DrawRectFunc          draw_rect;
375     }
376     map[] = {
377 #define _(FORMAT) { GST_VIDEO_FORMAT_##FORMAT, draw_rect_##FORMAT }
378         _(ARGB),
379         _(BGRA),
380         _(RGBA),
381         _(ABGR),
382         _(NV12),
383         _(YV12),
384         _(I420),
385         _(YUY2),
386         _(UYVY),
387         _(AYUV),
388 #undef  _
389         { 0, }
390     };
391
392     for (i = 0; !draw_rect && map[i].format; i++)
393         if (map[i].format == image_format)
394             draw_rect = map[i].draw_rect;
395     if (!draw_rect)
396         return FALSE;
397
398     if (x < 0)
399         x = 0;
400     if (y < 0)
401         y = 0;
402     if (width > image_width - x)
403         width = image_width - x;
404     if (height > image_height - y)
405         height = image_height - y;
406
407     display = gst_vaapi_object_get_display(GST_VAAPI_OBJECT(image));
408     if (!display)
409         return FALSE;
410
411     if (!gst_vaapi_image_map(image))
412         return FALSE;
413
414     for (i = 0; i < gst_vaapi_image_get_plane_count(image); i++) {
415         pixels[i] = gst_vaapi_image_get_plane(image, i);
416         stride[i] = gst_vaapi_image_get_pitch(image, i);
417         switch (flags) {
418         case GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD:
419             pixels[i] += stride[i];
420             // fall-through
421         case GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD:
422             stride[i] *= 2;
423             break;
424         }
425     }
426
427     if (flags)
428         y /= 2, height /= 2;
429
430     if (gst_vaapi_video_format_is_yuv(image_format))
431         color = argb2yuv(color);
432
433     draw_rect(pixels, stride, x, y, width, height, color);
434     return gst_vaapi_image_unmap(image);
435 }
436
437 gboolean
438 image_upload(GstVaapiImage *image, GstVaapiSurface *surface)
439 {
440     GstVaapiDisplay    *display;
441     GstVideoFormat      format;
442     GstVaapiImage      *surface_image;
443     GstVaapiSubpicture *subpicture;
444     gboolean            success;
445
446     display = gst_vaapi_object_get_display(GST_VAAPI_OBJECT(surface));
447     if (!display)
448         return FALSE;
449
450     format = gst_vaapi_image_get_format(image);
451     if (!format)
452         return FALSE;
453
454     if (gst_vaapi_surface_put_image(surface, image))
455         return TRUE;
456
457     surface_image = gst_vaapi_surface_derive_image(surface);
458     if (surface_image) {
459         success = gst_vaapi_image_copy(surface_image, image);
460         gst_vaapi_object_unref(surface_image);
461         if (success)
462             return TRUE;
463     }
464
465     g_print("could not upload %s image to surface\n",
466             gst_vaapi_video_format_to_string(format));
467
468     if (!gst_vaapi_display_has_subpicture_format(display, format, NULL))
469         return FALSE;
470
471     g_print("trying as a subpicture\n");
472
473     subpicture = gst_vaapi_subpicture_new(image, 0);
474     if (!subpicture)
475         g_error("could not create VA subpicture");
476
477     if (!gst_vaapi_surface_associate_subpicture(surface, subpicture,
478                                                 NULL, NULL))
479         g_error("could not associate subpicture to surface");
480
481     /* The surface holds a reference to the subpicture. This is safe */
482     gst_vaapi_object_unref(subpicture);
483     return TRUE;
484 }