1 /* GStreamer
2 * Copyright (C) 2010 Stefan Kost <ensonic@users.sf.net>
3 *
4 * capsnego.c: benchmark for caps negotiation
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library 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 GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22 /* This benchmark recursively builds a pipeline and measures the time to go
23 * from READY to PAUSED state.
24 *
25 * The graph size and type can be controlled with a few command line options:
26 *
27 * -d depth: is the depth of the tree
28 * -c children: is the number of branches on each level
29 * -f <flavour>: can be "audio" or "video" and is controlling the kind of
30 * elements that are used.
31 */
32
33 #include <gst/gst.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 enum
38 {
39 FLAVOUR_AUDIO = 0,
40 FLAVOUR_VIDEO,
41 NUM_FLAVOURS
42 };
43
44 enum
45 {
46 ELEM_SRC = 0,
47 ELEM_MIX,
48 ELEM_PROC,
49 ELEM_CONV,
50 NUM_ELEM
51 };
52
53 static const gchar *factories[NUM_FLAVOURS][NUM_ELEM] = {
54 {"audiotestsrc", "adder", "volume", "audioconvert"},
55 {"videotestsrc", "videomixer", "videoscale", "videoconvert"}
56 };
57
58 static const gchar *sink_pads[NUM_FLAVOURS][NUM_ELEM] = {
59 {NULL, "sink_%u", NULL, NULL},
60 {NULL, "sink_%u", NULL, NULL}
61 };
62
63
64 static gboolean
create_node(GstBin * bin,GstElement * sink,const gchar * sinkpadname,GstElement ** new_sink,gint children,gint flavour)65 create_node (GstBin * bin, GstElement * sink, const gchar * sinkpadname,
66 GstElement ** new_sink, gint children, gint flavour)
67 {
68 GstElement *mix, *proc, *conv;
69
70 if (children >= 1) {
71 mix = gst_element_factory_make (factories[flavour][ELEM_MIX], NULL);
72 if (!mix) {
73 GST_WARNING ("need element '%s'", factories[flavour][ELEM_MIX]);
74 return FALSE;
75 }
76 } else {
77 mix = gst_element_factory_make ("identity", NULL);
78 }
79 proc = gst_element_factory_make (factories[flavour][ELEM_PROC], NULL);
80 if (!proc) {
81 GST_WARNING ("need element '%s'", factories[flavour][ELEM_PROC]);
82 return FALSE;
83 }
84 conv = gst_element_factory_make (factories[flavour][ELEM_CONV], NULL);
85 if (!conv) {
86 GST_WARNING ("need element '%s'", factories[flavour][ELEM_CONV]);
87 return FALSE;
88 }
89 gst_bin_add_many (bin, mix, proc, conv, NULL);
90 if (!gst_element_link_pads_full (mix, "src", proc, "sink",
91 GST_PAD_LINK_CHECK_NOTHING)
92 || !gst_element_link_pads_full (proc, "src", conv, "sink",
93 GST_PAD_LINK_CHECK_NOTHING)
94 || !gst_element_link_pads_full (conv, "src", sink, sinkpadname,
95 GST_PAD_LINK_CHECK_NOTHING)) {
96 GST_WARNING ("can't link elements");
97 return FALSE;
98 }
99 *new_sink = mix;
100 return TRUE;
101 }
102
103 static gboolean
create_nodes(GstBin * bin,GstElement * sink,gint depth,gint children,gint flavour)104 create_nodes (GstBin * bin, GstElement * sink, gint depth, gint children,
105 gint flavour)
106 {
107 GstElement *new_sink, *src;
108 gint i;
109
110 for (i = 0; i < children; i++) {
111 if (depth > 0) {
112 if (!create_node (bin, sink, sink_pads[flavour][ELEM_MIX], &new_sink,
113 children, flavour)) {
114 return FALSE;
115 }
116 if (!create_nodes (bin, new_sink, depth - 1, children, flavour)) {
117 return FALSE;
118 }
119 } else {
120 src = gst_element_factory_make (factories[flavour][ELEM_SRC], NULL);
121 if (!src) {
122 GST_WARNING ("need element '%s'", factories[flavour][ELEM_SRC]);
123 return FALSE;
124 }
125 gst_bin_add (bin, src);
126 if (!gst_element_link_pads_full (src, "src", sink,
127 sink_pads[flavour][ELEM_MIX], GST_PAD_LINK_CHECK_NOTHING)) {
128 GST_WARNING ("can't link elements");
129 return FALSE;
130 }
131 }
132 }
133 return TRUE;
134 }
135
136 static void
event_loop(GstElement * bin)137 event_loop (GstElement * bin)
138 {
139 GstBus *bus;
140 GstMessage *msg = NULL;
141 gboolean running = TRUE;
142
143 bus = gst_element_get_bus (bin);
144
145 while (running) {
146 msg = gst_bus_poll (bus,
147 GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR | GST_MESSAGE_WARNING, -1);
148
149 switch (GST_MESSAGE_TYPE (msg)) {
150 case GST_MESSAGE_ASYNC_DONE:
151 running = FALSE;
152 break;
153 case GST_MESSAGE_WARNING:{
154 GError *err = NULL;
155 gchar *dbg = NULL;
156
157 gst_message_parse_warning (msg, &err, &dbg);
158 GST_WARNING_OBJECT (GST_MESSAGE_SRC (msg), "%s (%s)", err->message,
159 (dbg ? dbg : "no details"));
160 g_clear_error (&err);
161 g_free (dbg);
162 break;
163 }
164 case GST_MESSAGE_ERROR:{
165 GError *err = NULL;
166 gchar *dbg = NULL;
167
168 gst_message_parse_error (msg, &err, &dbg);
169 GST_ERROR_OBJECT (GST_MESSAGE_SRC (msg), "%s (%s)", err->message,
170 (dbg ? dbg : "no details"));
171 g_clear_error (&err);
172 g_free (dbg);
173 running = FALSE;
174 break;
175 }
176 default:
177 break;
178 }
179 gst_message_unref (msg);
180 }
181 gst_object_unref (bus);
182 }
183
184 gint
main(gint argc,gchar * argv[])185 main (gint argc, gchar * argv[])
186 {
187 /* default parameters */
188 gchar *flavour_str = g_strdup ("audio");
189 gint flavour = FLAVOUR_AUDIO;
190 gint children = 3;
191 gint depth = 4;
192 gint loops = 50;
193
194 GOptionContext *ctx;
195 GOptionEntry options[] = {
196 {"children", 'c', 0, G_OPTION_ARG_INT, &children,
197 "Number of children (branches on each level) (default: 3)", NULL}
198 ,
199 {"depth", 'd', 0, G_OPTION_ARG_INT, &depth,
200 "Depth of pipeline hierarchy tree (default: 4)", NULL}
201 ,
202 {"flavour", 'f', 0, G_OPTION_ARG_STRING, &flavour_str,
203 "Flavour (video|audio) controlling the kind of elements used "
204 "(default: audio)", NULL}
205 ,
206 {"loops", 'l', 0, G_OPTION_ARG_INT, &loops,
207 "How many loops to run (default: 50)", NULL}
208 ,
209 {NULL}
210 };
211 GError *err = NULL;
212 GstBin *bin;
213 GstClockTime start, end;
214 GstElement *sink, *new_sink;
215 gint i;
216
217 g_set_prgname ("capsnego");
218
219 /* check command line options */
220 ctx = g_option_context_new ("");
221 g_option_context_add_main_entries (ctx, options, NULL);
222 g_option_context_add_group (ctx, gst_init_get_option_group ());
223 if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
224 g_print ("Error initializing: %s\n", GST_STR_NULL (err->message));
225 g_clear_error (&err);
226 g_option_context_free (ctx);
227 return 1;
228 }
229 g_option_context_free (ctx);
230
231 if (strcmp (flavour_str, "video") == 0)
232 flavour = FLAVOUR_VIDEO;
233
234 /* build pipeline */
235 g_print ("building %s pipeline with depth = %d and children = %d\n",
236 flavour_str, depth, children);
237 g_free (flavour_str);
238
239 start = gst_util_get_timestamp ();
240 bin = GST_BIN (gst_pipeline_new ("pipeline"));
241 sink = gst_element_factory_make ("fakesink", NULL);
242 gst_bin_add (bin, sink);
243 if (!create_node (bin, sink, "sink", &new_sink, children, flavour)) {
244 goto Error;
245 }
246 if (!create_nodes (bin, new_sink, depth, children, flavour)) {
247 goto Error;
248 }
249 end = gst_util_get_timestamp ();
250 /* num-threads = num-sources = pow (children, depth) */
251 g_print ("%" GST_TIME_FORMAT " built pipeline with %d elements\n",
252 GST_TIME_ARGS (end - start), GST_BIN_NUMCHILDREN (bin));
253
254 /* measure */
255 g_print ("starting pipeline\n");
256 gst_element_set_state (GST_ELEMENT (bin), GST_STATE_READY);
257 GST_DEBUG_BIN_TO_DOT_FILE (bin, GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE, "capsnego");
258
259 start = gst_util_get_timestamp ();
260 for (i = 0; i < loops; ++i) {
261 gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PAUSED);
262 event_loop (GST_ELEMENT (bin));
263 gst_element_set_state (GST_ELEMENT (bin), GST_STATE_READY);
264 }
265 end = gst_util_get_timestamp ();
266 g_print ("%" GST_TIME_FORMAT " reached PAUSED state (%d loop iterations)\n",
267 GST_TIME_ARGS (end - start), loops);
268 /* clean up */
269 Error:
270 gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL);
271 gst_object_unref (bin);
272 return 0;
273 }
274