• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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