1 /* GStreamer
2 *
3 * codec-select.c: sample application to dynamically select a codec
4 *
5 * Copyright (C) <2008> Wim Taymans <wim dot taymans at gmail dot com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 /*
24 * This example sets up a pipeline to 'encode' an audiotestsrc into 3 different
25 * formats. The format can be selected dynamically at runtime.
26 *
27 * Each of the encoders require the audio in a specific different format.
28 *
29 * This example uses identity as the encoder and enforces the caps on identity
30 * with a capsfilter.
31 *
32 * This is a good example of input and output selector and how these elements
33 * preserve segment and timing information while switching between streams.
34 */
35
36 #include <string.h>
37 #include <gst/gst.h>
38
39 /* Create an encoder element.
40 * We make a bin containing:
41 *
42 * audioresample ! <enccaps> ! identity
43 *
44 * The sinkpad of audioresample and source pad of identity are ghosted on the
45 * bin.
46 */
47 static GstElement *
make_encoder(const GstCaps * caps)48 make_encoder (const GstCaps * caps)
49 {
50 GstElement *result;
51 GstElement *audioresample;
52 GstElement *capsfilter;
53 GstElement *identity;
54 GstPad *pad;
55
56 /* create result bin */
57 result = gst_bin_new (NULL);
58 g_assert (result);
59
60 /* create elements */
61 audioresample = gst_element_factory_make ("audioresample", NULL);
62 g_assert (audioresample);
63
64 capsfilter = gst_element_factory_make ("capsfilter", NULL);
65 g_assert (capsfilter);
66 g_object_set (capsfilter, "caps", caps, NULL);
67
68 identity = gst_element_factory_make ("identity", NULL);
69 g_assert (identity);
70 g_object_set (identity, "silent", TRUE, NULL);
71
72 /* add elements to result bin */
73 gst_bin_add (GST_BIN (result), audioresample);
74 gst_bin_add (GST_BIN (result), capsfilter);
75 gst_bin_add (GST_BIN (result), identity);
76
77 /* link elements */
78 gst_element_link_pads (audioresample, "src", capsfilter, "sink");
79 gst_element_link_pads (capsfilter, "src", identity, "sink");
80
81 /* ghost src and sink pads */
82 pad = gst_element_get_static_pad (audioresample, "sink");
83 gst_element_add_pad (result, gst_ghost_pad_new ("sink", pad));
84 gst_object_unref (pad);
85
86 pad = gst_element_get_static_pad (identity, "src");
87 gst_element_add_pad (result, gst_ghost_pad_new ("src", pad));
88 gst_object_unref (pad);
89
90 return result;
91 }
92
93 /*
94 * We generate:
95 *
96 * audiotestsrc ! <audiocaps> ! output-selector ! [enc1 .. enc3] ! input-selector
97 * select-all = true ! fakesink
98 *
99 * <audiocaps> makes sure we only produce one format from the audiotestsrc.
100 *
101 * Each encX element consists of:
102 *
103 * audioresample ! <enccaps> ! identity !
104 *
105 * This way we can simply switch encoders without having to renegotiate.
106 */
107 static GstElement *
make_pipeline(void)108 make_pipeline (void)
109 {
110 GstElement *result;
111 GstElement *audiotestsrc;
112 GstElement *audiocaps;
113 GstElement *outputselect;
114 GstElement *inputselect;
115 GstElement *sink;
116 GstCaps *caps;
117 GstCaps *capslist[3];
118 gint i;
119
120 /* create result pipeline */
121 result = gst_pipeline_new (NULL);
122 g_assert (result);
123
124 /* create various elements */
125 audiotestsrc = gst_element_factory_make ("audiotestsrc", NULL);
126 g_object_set (audiotestsrc, "num-buffers", 1000, NULL);
127 g_assert (audiotestsrc);
128
129 audiocaps = gst_element_factory_make ("capsfilter", NULL);
130 g_assert (audiocaps);
131
132 caps =
133 gst_caps_from_string ("audio/x-raw,format=S16LE,rate=48000,channels=1");
134 g_object_set (audiocaps, "caps", caps, NULL);
135 gst_caps_unref (caps);
136
137 outputselect = gst_element_factory_make ("output-selector", "select");
138 g_assert (outputselect);
139
140 inputselect = gst_element_factory_make ("input-selector", NULL);
141 g_assert (inputselect);
142 g_object_set (inputselect, "select-all", TRUE, NULL);
143
144 sink = gst_element_factory_make ("fakesink", NULL);
145 g_object_set (sink, "sync", TRUE, NULL);
146 g_object_set (sink, "silent", TRUE, NULL);
147 g_assert (sink);
148
149 /* add elements */
150 gst_bin_add (GST_BIN (result), audiotestsrc);
151 gst_bin_add (GST_BIN (result), audiocaps);
152 gst_bin_add (GST_BIN (result), outputselect);
153 gst_bin_add (GST_BIN (result), inputselect);
154 gst_bin_add (GST_BIN (result), sink);
155
156 /* link elements */
157 gst_element_link_pads (audiotestsrc, "src", audiocaps, "sink");
158 gst_element_link_pads (audiocaps, "src", outputselect, "sink");
159 gst_element_link_pads (inputselect, "src", sink, "sink");
160
161 /* make caps */
162 capslist[0] =
163 gst_caps_from_string ("audio/x-raw,format=S16LE,rate=48000,channels=1");
164 capslist[1] =
165 gst_caps_from_string ("audio/x-raw,format=S16LE,rate=16000,channels=1");
166 capslist[2] =
167 gst_caps_from_string ("audio/x-raw,format=S16LE,rate=8000,channels=1");
168
169 /* create encoder elements */
170 for (i = 0; i < 3; i++) {
171 GstElement *encoder;
172 GstPad *srcpad, *sinkpad;
173
174 encoder = make_encoder (capslist[i]);
175 g_assert (encoder);
176
177 gst_bin_add (GST_BIN (result), encoder);
178
179 srcpad = gst_element_request_pad_simple (outputselect, "src_%u");
180 sinkpad = gst_element_get_static_pad (encoder, "sink");
181 gst_pad_link (srcpad, sinkpad);
182 gst_object_unref (srcpad);
183 gst_object_unref (sinkpad);
184
185 srcpad = gst_element_get_static_pad (encoder, "src");
186 sinkpad = gst_element_request_pad_simple (inputselect, "sink_%u");
187 gst_pad_link (srcpad, sinkpad);
188 gst_object_unref (srcpad);
189 gst_object_unref (sinkpad);
190 }
191
192 return result;
193 }
194
195 static gboolean
do_switch(GstElement * pipeline)196 do_switch (GstElement * pipeline)
197 {
198 gint rand;
199 GstElement *select;
200 gchar *name;
201 GstPad *pad;
202
203 rand = g_random_int_range (0, 3);
204
205 g_print ("switching to %d\n", rand);
206
207 /* find the selector */
208 select = gst_bin_get_by_name (GST_BIN (pipeline), "select");
209
210 /* get the named pad */
211 name = g_strdup_printf ("src_%u", rand);
212 pad = gst_element_get_static_pad (select, name);
213 g_free (name);
214
215 /* set the active pad */
216 g_object_set (select, "active-pad", pad, NULL);
217 gst_object_unref (select);
218
219 return TRUE;
220 }
221
222 static gboolean
my_bus_callback(GstBus * bus,GstMessage * message,gpointer data)223 my_bus_callback (GstBus * bus, GstMessage * message, gpointer data)
224 {
225 GstElement *sender = (GstElement *) GST_MESSAGE_SRC (message);
226 gchar *name = gst_element_get_name (sender);
227 GMainLoop *loop = (GMainLoop *) data;
228
229 g_print ("Got %s message from %s\n", GST_MESSAGE_TYPE_NAME (message), name);
230 g_free (name);
231
232 switch (GST_MESSAGE_TYPE (message)) {
233
234 case GST_MESSAGE_ERROR:{
235 GError *err;
236 gchar *debug;
237
238 gst_message_parse_error (message, &err, &debug);
239 g_print ("Error: %s (%s)\n", err->message, debug);
240 g_error_free (err);
241 g_free (debug);
242
243 g_main_loop_quit (loop);
244 break;
245 }
246 case GST_MESSAGE_EOS:
247 /* end-of-stream */
248 g_main_loop_quit (loop);
249 break;
250 default:
251 /* unhandled message */
252 break;
253 }
254
255 return TRUE;
256 }
257
258 gint
main(gint argc,gchar * argv[])259 main (gint argc, gchar * argv[])
260 {
261 GstElement *pipeline;
262 GstBus *bus;
263 GMainLoop *loop;
264
265 /* init GStreamer */
266 gst_init (&argc, &argv);
267 loop = g_main_loop_new (NULL, FALSE);
268
269 /* set up */
270 pipeline = make_pipeline ();
271
272 g_signal_connect (pipeline, "deep_notify",
273 G_CALLBACK (gst_object_default_deep_notify), NULL);
274
275 bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
276 gst_bus_add_watch (bus, my_bus_callback, loop);
277 gst_object_unref (bus);
278
279 g_print ("Starting pipeline\n");
280
281 gst_element_set_state (pipeline, GST_STATE_PLAYING);
282
283 /* add a timeout to cycle between the formats */
284 g_timeout_add_seconds (1, (GSourceFunc) do_switch, pipeline);
285
286 /* now run */
287 g_main_loop_run (loop);
288
289 g_print ("Nulling pipeline\n");
290
291 /* also clean up */
292 gst_element_set_state (pipeline, GST_STATE_NULL);
293 gst_object_unref (pipeline);
294
295 return 0;
296 }
297