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