packaging: add packaging folder and update submodule pkgs
[platform/upstream/gstreamer-vaapi.git] / tests / test-filter.c
1 /*
2  *  test-filter.c - Test GstVaapiFilter
3  *
4  *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5  *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
6  *  Copyright (C) 2012-2013 Intel Corporation
7  *    Author: Halley Zhao <halley.zhao@intel.com>
8  *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
9  *
10  *  This library is free software; you can redistribute it and/or
11  *  modify it under the terms of the GNU Lesser General Public License
12  *  as published by the Free Software Foundation; either version 2.1
13  *  of the License, or (at your option) any later version.
14  *
15  *  This library is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  *  Lesser General Public License for more details.
19  *
20  *  You should have received a copy of the GNU Lesser General Public
21  *  License along with this library; if not, write to the Free
22  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  *  Boston, MA 02110-1301 USA
24  */
25
26 #include "gst/vaapi/sysdeps.h"
27 #include <errno.h>
28 #include <gst/vaapi/gstvaapifilter.h>
29 #include <gst/vaapi/gstvaapiwindow.h>
30 #include "image.h"
31 #include "output.h"
32
33 static gchar *g_src_format_str;
34 static gchar *g_crop_rect_str;
35 static gchar *g_denoise_str;
36 static gchar *g_sharpen_str;
37 static gchar *g_deinterlace_str;
38 static gchar *g_deinterlace_flags_str;
39
40 static GOptionEntry g_options[] = {
41     { "src-format", 's',
42       0,
43       G_OPTION_ARG_STRING, &g_src_format_str,
44       "source surface format", NULL },
45     { "crop-rect", 'c',
46       0,
47       G_OPTION_ARG_STRING, &g_crop_rect_str,
48       "cropping rectangle", NULL },
49     { "denoise", 0,
50       0,
51       G_OPTION_ARG_STRING, &g_denoise_str,
52       "set noise reduction level", NULL },
53     { "sharpen", 0,
54       0,
55       G_OPTION_ARG_STRING, &g_sharpen_str,
56       "set sharpening level", NULL },
57     { "deinterlace", 0,
58       0,
59       G_OPTION_ARG_STRING, &g_deinterlace_str,
60       "enable deinterlacing", NULL },
61     { "deinterlace-flags", 0,
62       0,
63       G_OPTION_ARG_STRING, &g_deinterlace_flags_str,
64       "deinterlacing flags", NULL },
65     { NULL, }
66 };
67
68 #define APP_ERROR app_error_quark()
69 static GQuark
70 app_error_quark(void)
71 {
72     static gsize g_quark;
73
74     if (g_once_init_enter(&g_quark)) {
75         gsize quark = (gsize)g_quark_from_static_string("AppError");
76         g_once_init_leave(&g_quark, quark);
77     }
78     return g_quark;
79 }
80
81 typedef enum {
82     APP_ERROR_NONE,
83     APP_ERROR_CREATE_TEST_SURFACE,
84 } AppError;
85
86 static inline void
87 pause(void)
88 {
89     g_print("Press any key to continue...\n");
90     getchar();
91 }
92
93 static GstVaapiSurface *
94 create_test_surface(GstVaapiDisplay *display, guint width, guint height,
95     guint flags, GError **error_ptr)
96 {
97     GstVideoFormat format = GST_VIDEO_FORMAT_I420;
98     GstVaapiSurface *surface = NULL;
99     GstVaapiImage *image = NULL;
100     GError *error = NULL;
101
102     if (g_src_format_str) {
103         format = gst_vaapi_video_format_from_string(g_src_format_str);
104         if (format == GST_VIDEO_FORMAT_UNKNOWN)
105             goto error_invalid_format;
106     }
107
108     surface = gst_vaapi_surface_new_with_format(display, format, width, height);
109     if (!surface)
110         goto error_create_surface;
111
112     image = image_generate_full(display, format, width, height, flags);
113     if (!image)
114         goto error_create_image;
115
116     if (!image_upload(image, surface))
117         goto error_upload_image;
118
119     gst_vaapi_object_unref(image);
120     return surface;
121
122     /* ERRORS */
123 error_invalid_format:
124     error = g_error_new(APP_ERROR, APP_ERROR_CREATE_TEST_SURFACE,
125         "unknown format %s", g_src_format_str);
126     goto error_cleanup;
127 error_create_surface:
128     error = g_error_new(APP_ERROR, APP_ERROR_CREATE_TEST_SURFACE,
129         "unsupported format %s", gst_vaapi_video_format_to_string(format));
130     goto error_cleanup;
131 error_create_image:
132     error = g_error_new(APP_ERROR, APP_ERROR_CREATE_TEST_SURFACE,
133         "unsupported %s image", gst_vaapi_video_format_to_string(format));
134     goto error_cleanup;
135 error_upload_image:
136     error = g_error_new(APP_ERROR, APP_ERROR_CREATE_TEST_SURFACE,
137         "failed to upload %s image", gst_vaapi_video_format_to_string(format));
138     goto error_cleanup;
139 error_cleanup:
140     if (image)
141         gst_vaapi_object_unref(image);
142     if (surface)
143         gst_vaapi_object_unref(surface);
144     if (error_ptr)
145         *error_ptr = error;
146     else
147         g_error_free(error);
148     return NULL;
149 }
150
151 static void
152 dump_operation(GstVaapiFilterOpInfo *op_info)
153 {
154     GParamSpec * const pspec = op_info->pspec;
155     GValue value = G_VALUE_INIT;
156     gchar *value_str;
157
158     if (!op_info)
159         return;
160
161     g_print("  %s: ", g_param_spec_get_name(pspec));
162     g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec));
163     g_param_value_set_default(pspec, &value);
164     value_str = g_strdup_value_contents(&value);
165     g_print("%s (default: %s)\n", G_VALUE_TYPE_NAME(&value),
166         value_str ? value_str : "<unknown>");
167     g_free(value_str);
168 }
169
170 static void
171 dump_operations(GstVaapiFilter *filter)
172 {
173     GPtrArray * const ops = gst_vaapi_filter_get_operations(filter);
174     guint i;
175
176     if (!ops)
177         return;
178
179     g_print("%u operations\n", ops->len);
180     for (i = 0; i < ops->len; i++)
181         dump_operation(g_ptr_array_index(ops, i));
182     g_ptr_array_unref(ops);
183 }
184
185 static void
186 dump_formats(GstVaapiFilter *filter)
187 {
188     GArray * const formats = gst_vaapi_filter_get_formats(filter);
189     guint i;
190
191     if (!formats)
192         return;
193
194     g_print("%u formats\n", formats->len);
195     for (i = 0; i < formats->len; i++) {
196         GstVideoFormat format = g_array_index(formats, GstVideoFormat, i);
197         g_print("  %s\n", gst_vaapi_video_format_to_string(format));
198     }
199     g_array_unref(formats);
200 }
201
202 static gboolean
203 parse_double(const gchar *str, gdouble *out_value_ptr)
204 {
205     gchar *endptr = NULL;
206     gdouble out_value;
207
208     g_return_val_if_fail(out_value_ptr != NULL, FALSE);
209
210     errno = 0;
211     out_value = g_ascii_strtod(str, &endptr);
212     if (!endptr || *endptr != '\0' || errno == ERANGE)
213         return FALSE;
214
215     *out_value_ptr = out_value;
216     return TRUE;
217 }
218
219 static gboolean
220 parse_crop_rect(const gchar *str, GstVaapiRectangle *crop_rect)
221 {
222     if (str) {
223         // Format: <WIDTH> 'x' <HEIGHT>
224         if (sscanf(str, "%ux%u", &crop_rect->width, &crop_rect->height) == 2) {
225             crop_rect->x = 0;
226             crop_rect->y = 0;
227             return TRUE;
228         }
229
230         // Format: '('? <X> ',' <Y> ')'? <WIDTH> 'x' <HEIGHT>
231         if (sscanf(str, "(%d,%d):%ux%u", &crop_rect->x, &crop_rect->y,
232                    &crop_rect->width, &crop_rect->height) == 4 ||
233             sscanf(str, "%d,%d:%ux%u", &crop_rect->x, &crop_rect->y,
234                    &crop_rect->width, &crop_rect->height) == 4)
235             return TRUE;
236     }
237     return FALSE;
238 }
239
240 static gboolean
241 parse_enum(const gchar *str, GType type, gint default_value,
242     gint *out_value_ptr)
243 {
244     gint out_value = default_value;
245
246     g_return_val_if_fail(out_value_ptr != NULL, FALSE);
247
248     if (str) {
249         GEnumClass * const enum_class = g_type_class_ref(type);
250         if (!enum_class)
251             return FALSE;
252
253         const GEnumValue * const enum_value =
254             g_enum_get_value_by_nick(enum_class, str);
255         if (enum_value)
256             out_value = enum_value->value;
257         g_type_class_unref(enum_class);
258
259         if (!enum_value)
260             return FALSE;
261     }
262     *out_value_ptr = out_value;
263     return TRUE;
264 }
265
266 static gboolean
267 parse_flags(const gchar *str, GType type, guint *out_value_ptr)
268 {
269     gchar **tokens = NULL;
270     gint i, value, out_value = 0;
271     gboolean success = FALSE;
272
273     g_return_val_if_fail(out_value_ptr != NULL, FALSE);
274
275     if (str) {
276         tokens = g_strsplit(str, ",", 32);
277         if (!tokens)
278             return FALSE;
279
280         for (i = 0; tokens[i] != NULL; i++) {
281             if (!parse_enum(tokens[i], type, 0, &value))
282                 goto end;
283             out_value |= value;
284         }
285     }
286     *out_value_ptr = out_value;
287     success = TRUE;
288
289 end:
290     g_strfreev(tokens);
291     return success;
292 }
293
294 static inline gboolean
295 parse_deinterlace(const gchar *str, GstVaapiDeinterlaceMethod *deinterlace_ptr)
296 {
297     g_return_val_if_fail(deinterlace_ptr != NULL, FALSE);
298
299     if (!str) {
300         *deinterlace_ptr = GST_VAAPI_DEINTERLACE_METHOD_NONE;
301         return TRUE;
302     }
303     return parse_enum(str, GST_VAAPI_TYPE_DEINTERLACE_METHOD,
304         GST_VAAPI_DEINTERLACE_METHOD_NONE, (gint *)deinterlace_ptr);
305 }
306
307 static inline gboolean
308 parse_deinterlace_flags(const gchar *str, guint *deinterlace_flags_ptr)
309 {
310     return parse_flags(str, GST_VAAPI_TYPE_DEINTERLACE_FLAGS,
311         deinterlace_flags_ptr);
312 }
313
314 int
315 main(int argc, char *argv[])
316 {
317     GstVaapiDisplay *display;
318     GstVaapiWindow *window;
319     GstVaapiSurface *src_surface, *dst_surface;
320     GstVaapiFilter *filter = NULL;
321     GstVaapiFilterStatus status;
322     GstVaapiDeinterlaceMethod deinterlace_method;
323     guint deinterlace_flags = 0;
324     guint filter_flags = 0;
325     guint surface_flags = 0;
326     gdouble denoise_level, sharpen_level;
327     GError *error = NULL;
328
329     static const guint src_width        = 320;
330     static const guint src_height       = 240;
331     static const guint dst_width        = 480;
332     static const guint dst_height       = 360;
333     static const guint win_width        = 640;
334     static const guint win_height       = 480;
335
336     if (!video_output_init(&argc, argv, g_options))
337         g_error("failed to initialize video output subsystem");
338
339     if (g_denoise_str && !parse_double(g_denoise_str, &denoise_level))
340         g_error("failed to parse noise reduction level");
341
342     if (g_sharpen_str && !parse_double(g_sharpen_str, &sharpen_level))
343         g_error("failed to parse sharpening level");
344
345     if (!parse_deinterlace(g_deinterlace_str, &deinterlace_method))
346         g_error("failed to parse deinterlace method `%s'", g_deinterlace_str);
347
348     if (!parse_deinterlace_flags(g_deinterlace_flags_str, &deinterlace_flags))
349         g_error("failed to parse deinterlace flags `%s'",
350             g_deinterlace_flags_str);
351
352     display = video_output_create_display(NULL);
353     if (!display)
354         g_error("failed to create VA display");
355
356     window = video_output_create_window(display, win_width, win_height);
357     if (!window)
358         g_error("failed to create window");
359
360     filter = gst_vaapi_filter_new(display);
361     if (!filter)
362         g_error("failed to create video processing pipeline");
363
364     dump_operations(filter);
365     dump_formats(filter);
366
367     if (g_crop_rect_str) {
368         GstVaapiRectangle crop_rect;
369
370         if (!parse_crop_rect(g_crop_rect_str, &crop_rect))
371             g_error("failed to parse cropping rectangle");
372
373         printf("Frame cropping: (%d,%d), size %ux%u\n",
374                crop_rect.x, crop_rect.y, crop_rect.width, crop_rect.height);
375
376         if (!gst_vaapi_filter_set_cropping_rectangle(filter, &crop_rect))
377             g_error("failed to set cropping rectangle");
378     }
379
380     if (g_denoise_str) {
381         printf("Noise reduction level: %f\n", denoise_level);
382
383         if (!gst_vaapi_filter_set_denoising_level(filter, denoise_level))
384             g_error("failed to set denoising level");
385     }
386
387     if (g_sharpen_str) {
388         printf("Sharpening level: %f\n", sharpen_level);
389
390         if (!gst_vaapi_filter_set_sharpening_level(filter, sharpen_level))
391             g_error("failed to set sharpening level");
392     }
393
394     if (deinterlace_method != GST_VAAPI_DEINTERLACE_METHOD_NONE) {
395         printf("Enable deinterlacing: %s\n", g_deinterlace_str);
396
397         if (!gst_vaapi_filter_set_deinterlacing(filter, deinterlace_method,
398                 deinterlace_flags))
399             g_error("failed to set deinterlacing method");
400     }
401     else if (deinterlace_flags) {
402         if (deinterlace_flags & GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD)
403             filter_flags = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD;
404         else
405             filter_flags = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD;
406     }
407
408     if (deinterlace_method != GST_VAAPI_DEINTERLACE_METHOD_NONE ||
409         deinterlace_flags) {
410         if (!(deinterlace_flags & GST_VAAPI_DEINTERLACE_FLAG_ONEFIELD))
411             surface_flags = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD |
412                 GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD;
413         else if (deinterlace_flags & GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD)
414             surface_flags = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD;
415         else
416             surface_flags = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD;
417     }
418
419     src_surface = create_test_surface(display, src_width, src_height,
420         surface_flags, &error);
421     if (!src_surface)
422         g_error("failed to create source VA surface: %s", error->message);
423
424     dst_surface = gst_vaapi_surface_new(display, GST_VAAPI_CHROMA_TYPE_YUV420,
425         dst_width, dst_height);
426     if (!dst_surface)
427         g_error("failed to create target VA surface");
428
429     status = gst_vaapi_filter_process(filter, src_surface, dst_surface,
430         filter_flags);
431     if (status != GST_VAAPI_FILTER_STATUS_SUCCESS)
432         g_error("failed to process video filters");
433
434     gst_vaapi_window_show(window);
435
436     if (!gst_vaapi_window_put_surface(window, dst_surface, NULL, NULL,
437             GST_VAAPI_PICTURE_STRUCTURE_FRAME))
438         g_error("failed to render target surface");
439
440     pause();
441
442     gst_vaapi_filter_unref(filter);
443     gst_vaapi_object_unref(dst_surface);
444     gst_vaapi_object_unref(src_surface);
445     gst_vaapi_window_unref(window);
446     gst_vaapi_display_unref(display);
447     video_output_exit();
448     g_free(g_src_format_str);
449     g_free(g_crop_rect_str);
450     g_free(g_denoise_str);
451     g_free(g_sharpen_str);
452     g_free(g_deinterlace_str);
453     g_free(g_deinterlace_flags_str);
454     return 0;
455 }