tests: image: fix generation of I420/YV12 images.
[vaapi: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  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public License
8  *  as published by the Free Software Foundation; either version 2.1
9  *  of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free
18  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  *  Boston, MA 02110-1301 USA
20  */
21
22 #include "image.h"
23
24 GstVaapiImage *
25 image_generate(
26     GstVaapiDisplay    *display,
27     GstVideoFormat      format,
28     guint               width,
29     guint               height
30 )
31 {
32     const guint w = width;
33     const guint h = height;
34     GstVaapiImage *image;
35
36     image = gst_vaapi_image_new(display, format, w, h);
37     if (!image)
38         return NULL;
39
40     if (image_draw_rectangle(image, 0,   0,   w/2, h/2, 0xffff0000) &&
41         image_draw_rectangle(image, w/2, 0,   w/2, h/2, 0xff00ff00) &&
42         image_draw_rectangle(image, 0,   h/2, w/2, h/2, 0xff0000ff) &&
43         image_draw_rectangle(image, w/2, h/2, w/2, h/2, 0xff000000))
44         return image;
45
46     gst_vaapi_object_unref(image);
47     return NULL;
48 }
49
50 typedef void (*DrawRectFunc)(
51     guchar *pixels[3],
52     guint   stride[3],
53     gint    x,
54     gint    y,
55     guint   width,
56     guint   height,
57     guint32 color
58 );
59
60 static void draw_rect_ARGB(
61     guchar *pixels[3],
62     guint   stride[3],
63     gint    x,
64     gint    y,
65     guint   width,
66     guint   height,
67     guint32 color
68 )
69 {
70     guint i, j;
71
72     color = GUINT32_TO_BE(color);
73
74     for (j = 0; j < height; j++) {
75         guint32 *p = (guint32 *)(pixels[0] + (y + j) * stride[0] + x * 4);
76         for (i = 0; i < width; i++)
77             p[i] = color;
78     }
79 }
80
81 static void draw_rect_BGRA(
82     guchar *pixels[3],
83     guint   stride[3],
84     gint    x,
85     gint    y,
86     guint   width,
87     guint   height,
88     guint32 color
89 )
90 {
91     // Converts ARGB color to BGRA
92     color = GUINT32_SWAP_LE_BE(color);
93
94     draw_rect_ARGB(pixels, stride, x, y, width, height, color);
95 }
96
97 static void draw_rect_RGBA(
98     guchar *pixels[3],
99     guint   stride[3],
100     gint    x,
101     gint    y,
102     guint   width,
103     guint   height,
104     guint32 color
105 )
106 {
107     // Converts ARGB color to RGBA
108     color = ((color >> 24) & 0xff) | ((color & 0xffffff) << 8);
109
110     draw_rect_ARGB(pixels, stride, x, y, width, height, color);
111 }
112
113 static void draw_rect_ABGR(
114     guchar *pixels[3],
115     guint   stride[3],
116     gint    x,
117     gint    y,
118     guint   width,
119     guint   height,
120     guint32 color
121 )
122 {
123     // Converts ARGB color to ABGR
124     color = ((color & 0xff00ff00)   |
125              ((color >> 16) & 0xff) |
126              ((color & 0xff) << 16));
127
128     draw_rect_ARGB(pixels, stride, x, y, width, height, color);
129 }
130
131 static void draw_rect_NV12( // Y, UV planes
132     guchar *pixels[3],
133     guint   stride[3],
134     gint    x,
135     gint    y,
136     guint   width,
137     guint   height,
138     guint32 color
139 )
140 {
141     const guchar Y  = color >> 16;
142     const guchar Cb = color >> 8;
143     const guchar Cr = color;
144     guchar *dst;
145     guint i, j;
146
147     dst = pixels[0] + y * stride[0] + x;
148     for (j = 0; j < height; j++, dst += stride[0])
149         for (i = 0; i < width; i++)
150             dst[i] = Y;
151
152     x      /= 2;
153     y      /= 2;
154     width  /= 2;
155     height /= 2;
156
157     dst = pixels[1] + y * stride[1] + x * 2;
158     for (j = 0; j < height; j++, dst += stride[1])
159         for (i = 0; i < width; i++) {
160             dst[2*i + 0] = Cb;
161             dst[2*i + 1] = Cr;
162         }
163 }
164
165 static void draw_rect_YV12( // Y, V, U planes
166     guchar *pixels[3],
167     guint   stride[3],
168     gint    x,
169     gint    y,
170     guint   width,
171     guint   height,
172     guint32 color
173 )
174 {
175     const guchar Y  = color >> 16;
176     const guchar Cb = color >> 8;
177     const guchar Cr = color;
178     guchar *pY, *pU, *pV;
179     guint i, j;
180
181     pY = pixels[0] + y * stride[0] + x;
182     for (j = 0; j < height; j++, pY += stride[0])
183         for (i = 0; i < width; i++)
184             pY[i] = Y;
185
186     x      /= 2;
187     y      /= 2;
188     width  /= 2;
189     height /= 2;
190
191     pV = pixels[1] + y * stride[1] + x;
192     pU = pixels[2] + y * stride[2] + x;
193     for (j = 0; j < height; j++, pU += stride[1], pV += stride[2])
194         for (i = 0; i < width; i++) {
195             pU[i] = Cb;
196             pV[i] = Cr;
197         }
198 }
199
200 static void draw_rect_I420( // Y, U, V planes
201     guchar *pixels[3],
202     guint   stride[3],
203     gint    x,
204     gint    y,
205     guint   width,
206     guint   height,
207     guint32 color
208 )
209 {
210     guchar *new_pixels[3] = { pixels[0], pixels[2], pixels[1] };
211     guint   new_stride[3] = { stride[0], stride[2], stride[1] };
212
213     draw_rect_YV12(new_pixels, new_stride, x, y, width, height, color);
214 }
215
216 static void draw_rect_AYUV(
217     guchar *pixels[3],
218     guint   stride[3],
219     gint    x,
220     gint    y,
221     guint   width,
222     guint   height,
223     guint32 color
224 )
225 {
226     guint i, j;
227
228     color = color | 0xff000000;
229
230     for (j = 0; j < height; j++) {
231         guint32 *p = (guint32 *)(pixels[0] + (y + j) * stride[0] + x * 4);
232         for (i = 0; i < width; i++)
233             p[i] = color;
234     }
235 }
236
237 static inline guint32 argb2yuv(guint32 color)
238 {
239     const gint32 r = (color >> 16) & 0xff;
240     const gint32 g = (color >>  8) & 0xff;
241     const gint32 b = (color      ) & 0xff;
242
243     const guint32 y = (( 263 * r + 516 * g + 100 * b) >> 10) +  16;
244     const guint32 u = ((-152 * r - 298 * g + 450 * b) >> 10) + 128;
245     const guint32 v = (( 450 * r - 376 * g -  73 * b) >> 10) + 128;
246
247     return (y << 16) | (u << 8) | v;
248 }
249
250 gboolean
251 image_draw_rectangle(
252     GstVaapiImage *image,
253     gint           x,
254     gint           y,
255     guint          width,
256     guint          height,
257     guint32        color
258 )
259 {
260     const GstVideoFormat      image_format = gst_vaapi_image_get_format(image);
261     const guint               image_width  = gst_vaapi_image_get_width(image);
262     const guint               image_height = gst_vaapi_image_get_height(image);
263     GstVaapiDisplay          *display;
264     guchar                   *pixels[3];
265     guint                     stride[3];
266     DrawRectFunc              draw_rect = NULL;
267     guint                     i;
268
269     static const struct {
270         GstVideoFormat        format;
271         DrawRectFunc          draw_rect;
272     }
273     map[] = {
274 #define _(FORMAT) { GST_VIDEO_FORMAT_##FORMAT, draw_rect_##FORMAT }
275         _(ARGB),
276         _(BGRA),
277         _(RGBA),
278         _(ABGR),
279         _(NV12),
280         _(YV12),
281         _(I420),
282         _(AYUV),
283 #undef  _
284         { 0, }
285     };
286
287     for (i = 0; !draw_rect && map[i].format; i++)
288         if (map[i].format == image_format)
289             draw_rect = map[i].draw_rect;
290     if (!draw_rect)
291         return FALSE;
292
293     display = gst_vaapi_object_get_display(GST_VAAPI_OBJECT(image));
294     if (!display)
295         return FALSE;
296
297     if (!gst_vaapi_image_map(image))
298         return FALSE;
299
300     for (i = 0; i < gst_vaapi_image_get_plane_count(image); i++) {
301         pixels[i] = gst_vaapi_image_get_plane(image, i);
302         stride[i] = gst_vaapi_image_get_pitch(image, i);
303     }
304
305     if (gst_vaapi_video_format_is_yuv(image_format))
306         color = argb2yuv(color);
307
308     if (x < 0)
309         x = 0;
310     if (y < 0)
311         y = 0;
312     if (width > image_width - x)
313         width = image_width - x;
314     if (height > image_height - y)
315         height = image_height - y;
316
317     gst_vaapi_display_lock(display);
318     draw_rect(pixels, stride, x, y, width, height, color);
319     gst_vaapi_display_unlock(display);
320     return gst_vaapi_image_unmap(image);
321 }
322
323 gboolean
324 image_upload(GstVaapiImage *image, GstVaapiSurface *surface)
325 {
326     GstVaapiDisplay    *display;
327     GstVideoFormat      format;
328     GstVaapiSubpicture *subpicture;
329
330     display = gst_vaapi_object_get_display(GST_VAAPI_OBJECT(surface));
331     if (!display)
332         return FALSE;
333
334     format = gst_vaapi_image_get_format(image);
335     if (!format)
336         return FALSE;
337
338     if (gst_vaapi_surface_put_image(surface, image))
339         return TRUE;
340
341     g_print("could not upload %s image to surface\n",
342             gst_vaapi_video_format_to_string(format));
343
344     if (!gst_vaapi_display_has_subpicture_format(display, format, NULL))
345         return FALSE;
346
347     g_print("trying as a subpicture\n");
348
349     subpicture = gst_vaapi_subpicture_new(image, 0);
350     if (!subpicture)
351         g_error("could not create VA subpicture");
352
353     if (!gst_vaapi_surface_associate_subpicture(surface, subpicture,
354                                                 NULL, NULL))
355         g_error("could not associate subpicture to surface");
356
357     /* The surface holds a reference to the subpicture. This is safe */
358     gst_vaapi_object_unref(subpicture);
359     return TRUE;
360 }