test-filter.c 12.8 KB
Newer Older
1 2 3 4
/*
 *  test-filter.c - Test GstVaapiFilter
 *
 *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5
 *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
6
 *  Copyright (C) 2012-2013 Intel Corporation
7 8
 *    Author: Halley Zhao <halley.zhao@intel.com>
 *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 *  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.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  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
 */

#include "gst/vaapi/sysdeps.h"
27
#include <errno.h>
28 29 30 31 32 33
#include <gst/vaapi/gstvaapifilter.h>
#include <gst/vaapi/gstvaapiwindow.h>
#include "image.h"
#include "output.h"

static gchar *g_src_format_str;
34
static gchar *g_crop_rect_str;
35 36
static gchar *g_denoise_str;
static gchar *g_sharpen_str;
37 38
static gchar *g_deinterlace_str;
static gchar *g_deinterlace_flags_str;
39 40

static GOptionEntry g_options[] = {
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
  {"src-format", 's',
        0,
        G_OPTION_ARG_STRING, &g_src_format_str,
      "source surface format", NULL},
  {"crop-rect", 'c',
        0,
        G_OPTION_ARG_STRING, &g_crop_rect_str,
      "cropping rectangle", NULL},
  {"denoise", 0,
        0,
        G_OPTION_ARG_STRING, &g_denoise_str,
      "set noise reduction level", NULL},
  {"sharpen", 0,
        0,
        G_OPTION_ARG_STRING, &g_sharpen_str,
      "set sharpening level", NULL},
  {"deinterlace", 0,
        0,
        G_OPTION_ARG_STRING, &g_deinterlace_str,
      "enable deinterlacing", NULL},
  {"deinterlace-flags", 0,
        0,
        G_OPTION_ARG_STRING, &g_deinterlace_flags_str,
      "deinterlacing flags", NULL},
  {NULL,}
66 67 68 69
};

#define APP_ERROR app_error_quark()
static GQuark
70
app_error_quark (void)
71
{
72
  static gsize g_quark;
73

74 75 76 77 78
  if (g_once_init_enter (&g_quark)) {
    gsize quark = (gsize) g_quark_from_static_string ("AppError");
    g_once_init_leave (&g_quark, quark);
  }
  return g_quark;
79 80
}

81 82 83 84
typedef enum
{
  APP_ERROR_NONE,
  APP_ERROR_CREATE_TEST_SURFACE,
85 86 87
} AppError;

static inline void
88
pause (void)
89
{
90 91
  g_print ("Press any key to continue...\n");
  getchar ();
92 93 94
}

static GstVaapiSurface *
95 96
create_test_surface (GstVaapiDisplay * display, guint width, guint height,
    guint flags, GError ** error_ptr)
97
{
98 99 100 101
  GstVideoFormat format = GST_VIDEO_FORMAT_I420;
  GstVaapiSurface *surface = NULL;
  GstVaapiImage *image = NULL;
  GError *error = NULL;
102

103 104 105 106 107
  if (g_src_format_str) {
    format = gst_video_format_from_string (g_src_format_str);
    if (format == GST_VIDEO_FORMAT_UNKNOWN)
      goto error_invalid_format;
  }
108

109 110 111
  surface = gst_vaapi_surface_new_with_format (display, format, width, height);
  if (!surface)
    goto error_create_surface;
112

113 114 115
  image = image_generate_full (display, format, width, height, flags);
  if (!image)
    goto error_create_image;
116

117 118
  if (!image_upload (image, surface))
    goto error_upload_image;
119

120 121 122 123
  gst_vaapi_object_unref (image);
  return surface;

  /* ERRORS */
124
error_invalid_format:
125 126 127
  error = g_error_new (APP_ERROR, APP_ERROR_CREATE_TEST_SURFACE,
      "unknown format %s", g_src_format_str);
  goto error_cleanup;
128
error_create_surface:
129 130 131
  error = g_error_new (APP_ERROR, APP_ERROR_CREATE_TEST_SURFACE,
      "unsupported format %s", gst_vaapi_video_format_to_string (format));
  goto error_cleanup;
132
error_create_image:
133 134 135
  error = g_error_new (APP_ERROR, APP_ERROR_CREATE_TEST_SURFACE,
      "unsupported %s image", gst_vaapi_video_format_to_string (format));
  goto error_cleanup;
136
error_upload_image:
137 138 139
  error = g_error_new (APP_ERROR, APP_ERROR_CREATE_TEST_SURFACE,
      "failed to upload %s image", gst_vaapi_video_format_to_string (format));
  goto error_cleanup;
140
error_cleanup:
141 142 143 144 145 146 147 148 149
  if (image)
    gst_vaapi_object_unref (image);
  if (surface)
    gst_vaapi_object_unref (surface);
  if (error_ptr)
    *error_ptr = error;
  else
    g_error_free (error);
  return NULL;
150 151
}

152
static void
153
dump_operation (GstVaapiFilterOpInfo * op_info)
154
{
155
  GParamSpec *pspec;
156 157 158 159 160 161
  GValue value = G_VALUE_INIT;
  gchar *value_str;

  if (!op_info)
    return;

162
  pspec = op_info->pspec;
163 164 165 166 167 168 169
  g_print ("  %s: ", g_param_spec_get_name (pspec));
  g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
  g_param_value_set_default (pspec, &value);
  value_str = g_strdup_value_contents (&value);
  g_print ("%s (default: %s)\n", G_VALUE_TYPE_NAME (&value),
      value_str ? value_str : "<unknown>");
  g_free (value_str);
170 171 172
}

static void
173
dump_operations (GstVaapiFilter * filter)
174
{
175 176
  GPtrArray *const ops = gst_vaapi_filter_get_operations (filter);
  guint i;
177

178 179
  if (!ops)
    return;
180

181 182 183 184
  g_print ("%u operations\n", ops->len);
  for (i = 0; i < ops->len; i++)
    dump_operation (g_ptr_array_index (ops, i));
  g_ptr_array_unref (ops);
185 186 187
}

static void
188
dump_formats (GstVaapiFilter * filter)
189
{
190 191 192 193 194 195 196 197 198 199 200 201
  GArray *const formats = gst_vaapi_filter_get_formats (filter);
  guint i;

  if (!formats)
    return;

  g_print ("%u formats\n", formats->len);
  for (i = 0; i < formats->len; i++) {
    GstVideoFormat format = g_array_index (formats, GstVideoFormat, i);
    g_print ("  %s\n", gst_vaapi_video_format_to_string (format));
  }
  g_array_unref (formats);
202 203
}

204
static gboolean
205
parse_double (const gchar * str, gdouble * out_value_ptr)
206
{
207 208
  gchar *endptr = NULL;
  gdouble out_value;
209

210
  g_return_val_if_fail (out_value_ptr != NULL, FALSE);
211

212 213 214 215
  errno = 0;
  out_value = g_ascii_strtod (str, &endptr);
  if (!endptr || *endptr != '\0' || errno == ERANGE)
    return FALSE;
216

217 218
  *out_value_ptr = out_value;
  return TRUE;
219 220
}

221
static gboolean
222
parse_crop_rect (const gchar * str, GstVaapiRectangle * crop_rect)
223
{
224 225 226 227 228 229
  if (str) {
    // Format: <WIDTH> 'x' <HEIGHT>
    if (sscanf (str, "%ux%u", &crop_rect->width, &crop_rect->height) == 2) {
      crop_rect->x = 0;
      crop_rect->y = 0;
      return TRUE;
230
    }
231 232 233 234 235 236 237 238
    // Format: '('? <X> ',' <Y> ')'? <WIDTH> 'x' <HEIGHT>
    if (sscanf (str, "(%d,%d):%ux%u", &crop_rect->x, &crop_rect->y,
            &crop_rect->width, &crop_rect->height) == 4 ||
        sscanf (str, "%d,%d:%ux%u", &crop_rect->x, &crop_rect->y,
            &crop_rect->width, &crop_rect->height) == 4)
      return TRUE;
  }
  return FALSE;
239 240
}

241
static gboolean
242 243
parse_enum (const gchar * str, GType type, gint default_value,
    gint * out_value_ptr)
244
{
245
  gint out_value = default_value;
246

247
  g_return_val_if_fail (out_value_ptr != NULL, FALSE);
248

249 250 251
  if (str) {
    const GEnumValue *enum_value;
    GEnumClass *const enum_class = g_type_class_ref (type);
252

253 254
    if (!enum_class)
      return FALSE;
255

256 257 258 259
    enum_value = g_enum_get_value_by_nick (enum_class, str);
    if (enum_value)
      out_value = enum_value->value;
    g_type_class_unref (enum_class);
260

261 262 263 264 265
    if (!enum_value)
      return FALSE;
  }
  *out_value_ptr = out_value;
  return TRUE;
266 267 268
}

static gboolean
269
parse_flags (const gchar * str, GType type, guint * out_value_ptr)
270
{
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
  gchar **tokens = NULL;
  gint i, value, out_value = 0;
  gboolean success = FALSE;

  g_return_val_if_fail (out_value_ptr != NULL, FALSE);

  if (str) {
    tokens = g_strsplit (str, ",", 32);
    if (!tokens)
      return FALSE;

    for (i = 0; tokens[i] != NULL; i++) {
      if (!parse_enum (tokens[i], type, 0, &value))
        goto end;
      out_value |= value;
286
    }
287 288 289
  }
  *out_value_ptr = out_value;
  success = TRUE;
290 291

end:
292 293
  g_strfreev (tokens);
  return success;
294 295 296
}

static inline gboolean
297 298
parse_deinterlace (const gchar * str,
    GstVaapiDeinterlaceMethod * deinterlace_ptr)
299
{
300
  g_return_val_if_fail (deinterlace_ptr != NULL, FALSE);
301

302 303 304 305 306 307
  if (!str) {
    *deinterlace_ptr = GST_VAAPI_DEINTERLACE_METHOD_NONE;
    return TRUE;
  }
  return parse_enum (str, GST_VAAPI_TYPE_DEINTERLACE_METHOD,
      GST_VAAPI_DEINTERLACE_METHOD_NONE, (gint *) deinterlace_ptr);
308 309 310
}

static inline gboolean
311
parse_deinterlace_flags (const gchar * str, guint * deinterlace_flags_ptr)
312
{
313 314
  return parse_flags (str, GST_VAAPI_TYPE_DEINTERLACE_FLAGS,
      deinterlace_flags_ptr);
315 316
}

317
int
318
main (int argc, char *argv[])
319
{
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
  GstVaapiDisplay *display;
  GstVaapiWindow *window;
  GstVaapiSurface *src_surface, *dst_surface;
  GstVaapiFilter *filter = NULL;
  GstVaapiFilterStatus status;
  GstVaapiDeinterlaceMethod deinterlace_method;
  guint deinterlace_flags = 0;
  guint filter_flags = 0;
  guint surface_flags = 0;
  gdouble denoise_level, sharpen_level;
  GError *error = NULL;

  static const guint src_width = 320;
  static const guint src_height = 240;
  static const guint dst_width = 480;
  static const guint dst_height = 360;
  static const guint win_width = 640;
  static const guint win_height = 480;

  if (!video_output_init (&argc, argv, g_options))
    g_error ("failed to initialize video output subsystem");

  if (g_denoise_str && !parse_double (g_denoise_str, &denoise_level))
    g_error ("failed to parse noise reduction level");

  if (g_sharpen_str && !parse_double (g_sharpen_str, &sharpen_level))
    g_error ("failed to parse sharpening level");

  if (!parse_deinterlace (g_deinterlace_str, &deinterlace_method))
    g_error ("failed to parse deinterlace method `%s'", g_deinterlace_str);

  if (!parse_deinterlace_flags (g_deinterlace_flags_str, &deinterlace_flags))
    g_error ("failed to parse deinterlace flags `%s'", g_deinterlace_flags_str);

  display = video_output_create_display (NULL);
  if (!display)
    g_error ("failed to create VA display");

  window = video_output_create_window (display, win_width, win_height);
  if (!window)
    g_error ("failed to create window");

  filter = gst_vaapi_filter_new (display);
  if (!filter)
    g_error ("failed to create video processing pipeline");

  dump_operations (filter);
  dump_formats (filter);

  if (g_crop_rect_str) {
    GstVaapiRectangle crop_rect;

    if (!parse_crop_rect (g_crop_rect_str, &crop_rect))
      g_error ("failed to parse cropping rectangle");

    printf ("Frame cropping: (%d,%d), size %ux%u\n",
        crop_rect.x, crop_rect.y, crop_rect.width, crop_rect.height);

    if (!gst_vaapi_filter_set_cropping_rectangle (filter, &crop_rect))
      g_error ("failed to set cropping rectangle");
  }

  if (g_denoise_str) {
    printf ("Noise reduction level: %f\n", denoise_level);

    if (!gst_vaapi_filter_set_denoising_level (filter, denoise_level))
      g_error ("failed to set denoising level");
  }

  if (g_sharpen_str) {
    printf ("Sharpening level: %f\n", sharpen_level);

    if (!gst_vaapi_filter_set_sharpening_level (filter, sharpen_level))
      g_error ("failed to set sharpening level");
  }

  if (deinterlace_method != GST_VAAPI_DEINTERLACE_METHOD_NONE) {
    printf ("Enable deinterlacing: %s\n", g_deinterlace_str);

    if (!gst_vaapi_filter_set_deinterlacing (filter, deinterlace_method,
            deinterlace_flags))
      g_error ("failed to set deinterlacing method");
  } else if (deinterlace_flags) {
    if (deinterlace_flags & GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD)
      filter_flags = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD;
    else
      filter_flags = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD;
  }

  if (deinterlace_method != GST_VAAPI_DEINTERLACE_METHOD_NONE ||
      deinterlace_flags) {
    if (!(deinterlace_flags & GST_VAAPI_DEINTERLACE_FLAG_ONEFIELD))
      surface_flags = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD |
          GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD;
    else if (deinterlace_flags & GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD)
      surface_flags = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD;
    else
      surface_flags = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD;
  }

  src_surface = create_test_surface (display, src_width, src_height,
      surface_flags, &error);
  if (!src_surface)
    g_error ("failed to create source VA surface: %s", error->message);

  dst_surface = gst_vaapi_surface_new (display, GST_VAAPI_CHROMA_TYPE_YUV420,
      dst_width, dst_height);
  if (!dst_surface)
    g_error ("failed to create target VA surface");

  status = gst_vaapi_filter_process (filter, src_surface, dst_surface,
      filter_flags);
  if (status != GST_VAAPI_FILTER_STATUS_SUCCESS)
    g_error ("failed to process video filters");

  gst_vaapi_window_show (window);

  if (!gst_vaapi_window_put_surface (window, dst_surface, NULL, NULL,
          GST_VAAPI_PICTURE_STRUCTURE_FRAME))
    g_error ("failed to render target surface");

  pause ();

  gst_vaapi_filter_unref (filter);
  gst_vaapi_object_unref (dst_surface);
  gst_vaapi_object_unref (src_surface);
  gst_vaapi_window_unref (window);
447
  gst_object_unref (display);
448 449 450 451 452 453 454 455
  video_output_exit ();
  g_free (g_src_format_str);
  g_free (g_crop_rect_str);
  g_free (g_denoise_str);
  g_free (g_sharpen_str);
  g_free (g_deinterlace_str);
  g_free (g_deinterlace_flags_str);
  return 0;
456
}