Update theme submodule
[platform/upstream/gstreamer.git] / pwg-building-testapp.md
1 ---
2 title: Building a Test Application
3 ...
4
5 # Building a Test Application
6
7 Often, you will want to test your newly written plugin in an as small
8 setting as possible. Usually, `gst-launch-1.0` is a good first step at
9 testing a plugin. If you have not installed your plugin in a directory
10 that GStreamer searches, then you will need to set the plugin path.
11 Either set GST\_PLUGIN\_PATH to the directory containing your plugin, or
12 use the command-line option --gst-plugin-path. If you based your plugin
13 off of the gst-plugin template, then this will look something like `
14 gst-launch-1.0 --gst-plugin-path=$HOME/gst-template/gst-plugin/src/.libs
15 TESTPIPELINE
16 ` However, you will often need more testing features than gst-launch-1.0
17 can provide, such as seeking, events, interactivity and more. Writing
18 your own small testing program is the easiest way to accomplish this.
19 This section explains - in a few words - how to do that. For a complete
20 application development guide, see the [Application Development
21 Manual](../../manual/html/index.html).
22
23 At the start, you need to initialize the GStreamer core library by
24 calling `gst_init ()`. You can alternatively call
25 `gst_init_get_option_group ()`, which will return a pointer to
26 GOptionGroup. You can then use GOption to handle the initialization, and
27 this will finish the GStreamer initialization.
28
29 You can create elements using `gst_element_factory_make ()`, where the
30 first argument is the element type that you want to create, and the
31 second argument is a free-form name. The example at the end uses a
32 simple filesource - decoder - soundcard output pipeline, but you can use
33 specific debugging elements if that's necessary. For example, an
34 `identity` element can be used in the middle of the pipeline to act as a
35 data-to-application transmitter. This can be used to check the data for
36 misbehaviours or correctness in your test application. Also, you can use
37 a `fakesink` element at the end of the pipeline to dump your data to the
38 stdout (in order to do this, set the `dump` property to TRUE). Lastly,
39 you can use valgrind to check for memory errors.
40
41 During linking, your test application can use filtered caps as a way to
42 drive a specific type of data to or from your element. This is a very
43 simple and effective way of checking multiple types of input and output
44 in your element.
45
46 Note that during running, you should listen for at least the “error” and
47 “eos” messages on the bus and/or your plugin/element to check for
48 correct handling of this. Also, you should add events into the pipeline
49 and make sure your plugin handles these correctly (with respect to
50 clocking, internal caching, etc.).
51
52 Never forget to clean up memory in your plugin or your test application.
53 When going to the NULL state, your element should clean up allocated
54 memory and caches. Also, it should close down any references held to
55 possible support libraries. Your application should `unref ()` the
56 pipeline and make sure it doesn't crash.
57
58 ``` c
59 #include <gst/gst.h>
60
61 static gboolean
62 bus_call (GstBus     *bus,
63       GstMessage *msg,
64       gpointer    data)
65 {
66   GMainLoop *loop = data;
67
68   switch (GST_MESSAGE_TYPE (msg)) {
69     case GST_MESSAGE_EOS:
70       g_print ("End-of-stream\n");
71       g_main_loop_quit (loop);
72       break;
73     case GST_MESSAGE_ERROR: {
74       gchar *debug = NULL;
75       GError *err = NULL;
76
77       gst_message_parse_error (msg, &err, &debug);
78
79       g_print ("Error: %s\n", err->message);
80       g_error_free (err);
81
82       if (debug) {
83         g_print ("Debug details: %s\n", debug);
84         g_free (debug);
85       }
86
87       g_main_loop_quit (loop);
88       break;
89     }
90     default:
91       break;
92   }
93
94   return TRUE;
95 }
96
97 gint
98 main (gint   argc,
99       gchar *argv[])
100 {
101   GstStateChangeReturn ret;
102   GstElement *pipeline, *filesrc, *decoder, *filter, *sink;
103   GstElement *convert1, *convert2, *resample;
104   GMainLoop *loop;
105   GstBus *bus;
106   guint watch_id;
107
108   /* initialization */
109   gst_init (&argc, &argv);
110   loop = g_main_loop_new (NULL, FALSE);
111   if (argc != 2) {
112     g_print ("Usage: %s <mp3 filename>\n", argv[0]);
113     return 01;
114   }
115
116   /* create elements */
117   pipeline = gst_pipeline_new ("my_pipeline");
118
119   /* watch for messages on the pipeline's bus (note that this will only
120    * work like this when a GLib main loop is running) */
121   bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
122   watch_id = gst_bus_add_watch (bus, bus_call, loop);
123   gst_object_unref (bus);
124
125   filesrc  = gst_element_factory_make ("filesrc", "my_filesource");
126   decoder  = gst_element_factory_make ("mad", "my_decoder");
127
128   /* putting an audioconvert element here to convert the output of the
129    * decoder into a format that my_filter can handle (we are assuming it
130    * will handle any sample rate here though) */
131   convert1 = gst_element_factory_make ("audioconvert", "audioconvert1");
132
133   /* use "identity" here for a filter that does nothing */
134   filter   = gst_element_factory_make ("my_filter", "my_filter");
135
136   /* there should always be audioconvert and audioresample elements before
137    * the audio sink, since the capabilities of the audio sink usually vary
138    * depending on the environment (output used, sound card, driver etc.) */
139   convert2 = gst_element_factory_make ("audioconvert", "audioconvert2");
140   resample = gst_element_factory_make ("audioresample", "audioresample");
141   sink     = gst_element_factory_make ("pulsesink", "audiosink");
142
143   if (!sink || !decoder) {
144     g_print ("Decoder or output could not be found - check your install\n");
145     return -1;
146   } else if (!convert1 || !convert2 || !resample) {
147     g_print ("Could not create audioconvert or audioresample element, "
148              "check your installation\n");
149     return -1;
150   } else if (!filter) {
151     g_print ("Your self-written filter could not be found. Make sure it "
152              "is installed correctly in $(libdir)/gstreamer-1.0/ or "
153              "~/.gstreamer-1.0/plugins/ and that gst-inspect-1.0 lists it. "
154              "If it doesn't, check with 'GST_DEBUG=*:2 gst-inspect-1.0' for "
155              "the reason why it is not being loaded.");
156     return -1;
157   }
158
159   g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
160
161   gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, convert1, filter,
162                     convert2, resample, sink, NULL);
163
164   /* link everything together */
165   if (!gst_element_link_many (filesrc, decoder, convert1, filter, convert2,
166                               resample, sink, NULL)) {
167     g_print ("Failed to link one or more elements!\n");
168     return -1;
169   }
170
171   /* run */
172   ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
173   if (ret == GST_STATE_CHANGE_FAILURE) {
174     GstMessage *msg;
175
176     g_print ("Failed to start up pipeline!\n");
177
178     /* check if there is an error message with details on the bus */
179     msg = gst_bus_poll (bus, GST_MESSAGE_ERROR, 0);
180     if (msg) {
181       GError *err = NULL;
182
183       gst_message_parse_error (msg, &err, NULL);
184       g_print ("ERROR: %s\n", err->message);
185       g_error_free (err);
186       gst_message_unref (msg);
187     }
188     return -1;
189   }
190
191   g_main_loop_run (loop);
192
193   /* clean up */
194   gst_element_set_state (pipeline, GST_STATE_NULL);
195   gst_object_unref (pipeline);
196   g_source_remove (watch_id);
197   g_main_loop_unref (loop);
198
199   return 0;
200 }
201     
202 ```
203