1 /* GStreamer video format conversion benchmark
2  * Copyright (C) 2014 Wim Taymans <wim.taymans@gmail.com>
3  * Copyright (C) 2019 Tim-Philipp Müller <tim centricular com>
4 
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <gst/gst.h>
26 #include <gst/video/video.h>
27 
28 #define DEFAULT_WIDTH 1920
29 #define DEFAULT_HEIGHT 1080
30 
31 #define DEFAULT_DURATION 2.0
32 
33 static gint
get_num_formats(void)34 get_num_formats (void)
35 {
36   gint num_formats = 100;
37 
38   while (gst_video_format_to_string (num_formats) == NULL)
39     --num_formats;
40   GST_INFO ("number of known video formats: %d", num_formats);
41   return num_formats + 1;
42 }
43 
44 static void
do_benchmark_conversions(guint width,guint height,const gchar * in_format,const gchar * out_format,gdouble max_duration)45 do_benchmark_conversions (guint width, guint height, const gchar * in_format,
46     const gchar * out_format, gdouble max_duration)
47 {
48   const gchar *infmt_str, *outfmt_str;
49   GstVideoFormat infmt, outfmt;
50   GTimer *timer;
51   gint num_formats;
52 
53   timer = g_timer_new ();
54 
55   num_formats = get_num_formats ();
56 
57   for (infmt = GST_VIDEO_FORMAT_I420; infmt < num_formats; infmt++) {
58     GstVideoInfo ininfo;
59     GstVideoFrame inframe;
60     GstBuffer *inbuffer;
61 
62     infmt_str = gst_video_format_to_string (infmt);
63     if (in_format != NULL && !g_str_equal (in_format, infmt_str))
64       continue;
65 
66     gst_video_info_set_format (&ininfo, infmt, width, height);
67     inbuffer = gst_buffer_new_and_alloc (ininfo.size);
68     gst_buffer_memset (inbuffer, 0, 0, -1);
69     gst_video_frame_map (&inframe, &ininfo, inbuffer, GST_MAP_READ);
70 
71     for (outfmt = GST_VIDEO_FORMAT_I420; outfmt < num_formats; outfmt++) {
72       GstVideoInfo outinfo;
73       GstVideoFrame outframe;
74       GstBuffer *outbuffer;
75       GstVideoConverter *convert;
76       gdouble elapsed, convert_sec;
77       gint count;
78 
79       outfmt_str = gst_video_format_to_string (outfmt);
80       if (out_format != NULL && !g_str_equal (out_format, outfmt_str))
81         continue;
82 
83       /* Or maybe we should allocate more buffers to minimise cache effects? */
84       gst_video_info_set_format (&outinfo, outfmt, width, height);
85       outbuffer = gst_buffer_new_and_alloc (outinfo.size);
86       gst_video_frame_map (&outframe, &outinfo, outbuffer, GST_MAP_WRITE);
87 
88       convert = gst_video_converter_new (&ininfo, &outinfo, NULL);
89       /* warmup */
90       gst_video_converter_frame (convert, &inframe, &outframe);
91 
92       count = 0;
93       g_timer_start (timer);
94       while (TRUE) {
95         gst_video_converter_frame (convert, &inframe, &outframe);
96 
97         count++;
98         elapsed = g_timer_elapsed (timer, NULL);
99         if (elapsed >= max_duration)
100           break;
101       }
102 
103       convert_sec = count / elapsed;
104 
105       gst_println ("%8.1f conversions/sec %s -> %s @ %ux%u, %d/%.5f",
106           convert_sec, infmt_str, outfmt_str, width, height, count, elapsed);
107 
108       gst_video_converter_free (convert);
109 
110       gst_video_frame_unmap (&outframe);
111       gst_buffer_unref (outbuffer);
112     }
113     gst_video_frame_unmap (&inframe);
114     gst_buffer_unref (inbuffer);
115   }
116 
117   g_timer_destroy (timer);
118 }
119 
120 int
main(int argc,char ** argv)121 main (int argc, char **argv)
122 {
123   GError *err = NULL;
124   gint width = DEFAULT_WIDTH;
125   gint height = DEFAULT_HEIGHT;
126   gdouble max_dur = DEFAULT_DURATION;
127   gchar *from_fmt = NULL;
128   gchar *to_fmt = NULL;
129   GOptionContext *ctx;
130   GOptionEntry options[] = {
131     {"width", 'w', 0, G_OPTION_ARG_INT, &width, "Width", NULL},
132     {"height", 'h', 0, G_OPTION_ARG_INT, &height, "Height", NULL},
133     {"from-format", 'f', 0, G_OPTION_ARG_STRING, &from_fmt, "From Format",
134         NULL},
135     {"to-format", 't', 0, G_OPTION_ARG_STRING, &to_fmt, "To Format", NULL},
136     {"duration", 'd', 0, G_OPTION_ARG_DOUBLE, &max_dur,
137         "Benchmark duration for each run (in seconds)", NULL},
138     {NULL}
139   };
140 
141   ctx = g_option_context_new ("");
142   g_option_context_add_main_entries (ctx, options, NULL);
143   g_option_context_add_group (ctx, gst_init_get_option_group ());
144   if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
145     g_print ("Error initializing: %s\n", GST_STR_NULL (err->message));
146     g_option_context_free (ctx);
147     g_clear_error (&err);
148     return 1;
149   }
150   g_option_context_free (ctx);
151 
152   do_benchmark_conversions (width, height, from_fmt, to_fmt, max_dur);
153   return 0;
154 }
155