tests: icles: add video conversion benchmark
authorTim-Philipp Müller <tim@centricular.com>
Sat, 23 Mar 2019 12:24:04 +0000 (12:24 +0000)
committerTim-Philipp Müller <tim@centricular.com>
Sun, 24 Mar 2019 16:39:30 +0000 (16:39 +0000)
Split out the benchmarking code from the unit test
and make it a bit more useful.

tests/icles/.gitignore
tests/icles/Makefile.am
tests/icles/benchmark-video-conversion.c [new file with mode: 0644]
tests/icles/meson.build

index 51f9fe2..5eb9d9a 100644 (file)
@@ -1,6 +1,7 @@
 audio-trickplay
 benchmark-appsink
 benchmark-appsrc
+benchmark-video-conversion
 input-selector-test
 output-selector-test
 playbin-text
index a51da87..74b575c 100644 (file)
@@ -17,6 +17,13 @@ benchmark_appsrc_LDADD = \
        $(top_builddir)/gst-libs/gst/app/libgstapp-$(GST_API_VERSION).la \
        $(GST_LIBS)
 
+benchmark_video_conversion_SOURCES = benchmark-video-conversion.c
+benchmark_video_conversion_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \
+       $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+benchmark_video_conversion_LDADD = \
+       $(top_builddir)/gst-libs/gst/video/libgstvideo-$(GST_API_VERSION).la \
+       $(GST_LIBS) $(LIBM)
+
 if USE_X
 X_TESTS = stress-videooverlay
 
@@ -119,4 +126,4 @@ test_reverseplay_LDADD = $(GST_LIBS) $(LIBM)
 noinst_PROGRAMS = $(X_TESTS) $(PANGO_TESTS) \
        audio-trickplay playbin-text position-formats stress-playbin \
        test-scale test-box test-effect-switch test-overlay-blending test-reverseplay \
-       test-resample benchmark-appsink benchmark-appsrc
+       test-resample benchmark-appsink benchmark-appsrc benchmark-video-conversion
diff --git a/tests/icles/benchmark-video-conversion.c b/tests/icles/benchmark-video-conversion.c
new file mode 100644 (file)
index 0000000..f81377e
--- /dev/null
@@ -0,0 +1,154 @@
+/* GStreamer video format conversion benchmark
+ * Copyright (C) 2014 Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C) 2019 Tim-Philipp Müller <tim centricular com>
+
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+#define DEFAULT_WIDTH 1920
+#define DEFAULT_HEIGHT 1080
+
+#define DEFAULT_DURATION 2.0
+
+static gint
+get_num_formats (void)
+{
+  gint num_formats = 100;
+
+  while (gst_video_format_to_string (num_formats) == NULL)
+    --num_formats;
+  GST_INFO ("number of known video formats: %d", num_formats);
+  return num_formats + 1;
+}
+
+static void
+do_benchmark_conversions (guint width, guint height, const gchar * in_format,
+    const gchar * out_format, gdouble max_duration)
+{
+  const gchar *infmt_str, *outfmt_str;
+  GstVideoFormat infmt, outfmt;
+  GTimer *timer;
+  gint num_formats;
+
+  timer = g_timer_new ();
+
+  num_formats = get_num_formats ();
+
+  for (infmt = GST_VIDEO_FORMAT_I420; infmt < num_formats; infmt++) {
+    GstVideoInfo ininfo;
+    GstVideoFrame inframe;
+    GstBuffer *inbuffer;
+
+    infmt_str = gst_video_format_to_string (infmt);
+    if (in_format != NULL && !g_str_equal (in_format, infmt_str))
+      continue;
+
+    gst_video_info_set_format (&ininfo, infmt, width, height);
+    inbuffer = gst_buffer_new_and_alloc (ininfo.size);
+    gst_buffer_memset (inbuffer, 0, 0, -1);
+    gst_video_frame_map (&inframe, &ininfo, inbuffer, GST_MAP_READ);
+
+    for (outfmt = GST_VIDEO_FORMAT_I420; outfmt < num_formats; outfmt++) {
+      GstVideoInfo outinfo;
+      GstVideoFrame outframe;
+      GstBuffer *outbuffer;
+      GstVideoConverter *convert;
+      gdouble elapsed, convert_sec;
+      gint count;
+
+      outfmt_str = gst_video_format_to_string (outfmt);
+      if (out_format != NULL && !g_str_equal (out_format, outfmt_str))
+        continue;
+
+      /* Or maybe we should allocate more buffers to minimise cache effects? */
+      gst_video_info_set_format (&outinfo, outfmt, width, height);
+      outbuffer = gst_buffer_new_and_alloc (outinfo.size);
+      gst_video_frame_map (&outframe, &outinfo, outbuffer, GST_MAP_WRITE);
+
+      convert = gst_video_converter_new (&ininfo, &outinfo, NULL);
+      /* warmup */
+      gst_video_converter_frame (convert, &inframe, &outframe);
+
+      count = 0;
+      g_timer_start (timer);
+      while (TRUE) {
+        gst_video_converter_frame (convert, &inframe, &outframe);
+
+        count++;
+        elapsed = g_timer_elapsed (timer, NULL);
+        if (elapsed >= max_duration)
+          break;
+      }
+
+      convert_sec = count / elapsed;
+
+      gst_println ("%8.1f conversions/sec %s -> %s @ %ux%u, %d/%.5f",
+          convert_sec, infmt_str, outfmt_str, width, height, count, elapsed);
+
+      gst_video_converter_free (convert);
+
+      gst_video_frame_unmap (&outframe);
+      gst_buffer_unref (outbuffer);
+    }
+    gst_video_frame_unmap (&inframe);
+    gst_buffer_unref (inbuffer);
+  }
+
+  g_timer_destroy (timer);
+}
+
+int
+main (int argc, char **argv)
+{
+  GError *err = NULL;
+  gint width = DEFAULT_WIDTH;
+  gint height = DEFAULT_HEIGHT;
+  gdouble max_dur = DEFAULT_DURATION;
+  gchar *from_fmt = NULL;
+  gchar *to_fmt = NULL;
+  GOptionContext *ctx;
+  GOptionEntry options[] = {
+    {"width", 'w', 0, G_OPTION_ARG_INT, &width, "Width", NULL},
+    {"height", 'h', 0, G_OPTION_ARG_INT, &height, "Height", NULL},
+    {"from-format", 'f', 0, G_OPTION_ARG_STRING, &from_fmt, "From Format",
+        NULL},
+    {"to-format", 't', 0, G_OPTION_ARG_STRING, &to_fmt, "To Format", NULL},
+    {"duration", 'd', 0, G_OPTION_ARG_DOUBLE, &max_dur,
+        "Benchmark duration for each run (in seconds)", NULL},
+    {NULL}
+  };
+
+  ctx = g_option_context_new ("");
+  g_option_context_add_main_entries (ctx, options, NULL);
+  g_option_context_add_group (ctx, gst_init_get_option_group ());
+  if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
+    g_print ("Error initializing: %s\n", GST_STR_NULL (err->message));
+    g_option_context_free (ctx);
+    g_clear_error (&err);
+    return 1;
+  }
+  g_option_context_free (ctx);
+
+  do_benchmark_conversions (width, height, from_fmt, to_fmt, max_dur);
+  return 0;
+}
index d753761..5b9d519 100644 (file)
@@ -1,6 +1,7 @@
 base_icles = [
   [ 'benchmark-appsink.c', false, [gst_base_dep, app_dep], true ],
   [ 'benchmark-appsrc.c', false, [gst_base_dep, app_dep], true ],
+  [ 'benchmark-video-conversion.c', false, [gst_base_dep, video_dep], true ],
   [ 'audio-trickplay.c', false, [gst_controller_dep] ],
   [ 'playbin-text.c' ],
   [ 'stress-playbin.c' ],