1 | <chapter id="chapter-helloworld"> |
---|
2 | <title>Your first application</title> |
---|
3 | <para> |
---|
4 | This chapter will summarize everything you've learned in the previous |
---|
5 | chapters. It describes all aspects of a simple &GStreamer; application, |
---|
6 | including initializing libraries, creating elements, packing elements |
---|
7 | together in a pipeline and playing this pipeline. By doing all this, |
---|
8 | you will be able to build a simple Ogg/Vorbis audio player. |
---|
9 | </para> |
---|
10 | |
---|
11 | <sect1 id="section-helloworld"> |
---|
12 | <title>Hello world</title> |
---|
13 | <para> |
---|
14 | We're going to create a simple first application, a simple Ogg/Vorbis |
---|
15 | command-line audio player. For this, we will use only standard |
---|
16 | &GStreamer; components. The player will read a file specified on |
---|
17 | the command-line. Let's get started! |
---|
18 | </para> |
---|
19 | <para> |
---|
20 | We've learned, in <xref linkend="chapter-init"/>, that the first thing |
---|
21 | to do in your application is to initialize &GStreamer; by calling |
---|
22 | <function>gst_init ()</function>. Also, make sure that the application |
---|
23 | includes <filename>gst/gst.h</filename> so all function names and |
---|
24 | objects are properly defined. Use <function>#include |
---|
25 | <gst/gst.h></function> to do that. |
---|
26 | </para> |
---|
27 | <para> |
---|
28 | Next, you'll want to create the different elements using |
---|
29 | <function>gst_element_factory_make ()</function>. For an Ogg/Vorbis |
---|
30 | audio player, we'll need a source element that reads files from a |
---|
31 | disk. &GStreamer; includes this element under the name |
---|
32 | <quote>filesrc</quote>. Next, we'll need something to parse the |
---|
33 | file and decoder it into raw audio. &GStreamer; has two elements |
---|
34 | for this: the first parses Ogg streams into elementary streams (video, |
---|
35 | audio) and is called <quote>oggdemux</quote>. The second is a Vorbis |
---|
36 | audio decoder, it's conveniently called <quote>vorbisdec</quote>. |
---|
37 | Since <quote>oggdemux</quote> creates dynamic pads for each elementary |
---|
38 | stream, you'll need to set a <quote>new-pad</quote> event handler |
---|
39 | on the <quote>oggdemux</quote> element, like you've learned in |
---|
40 | <xref linkend="section-pads-dynamic"/>, to link the Ogg parser and |
---|
41 | the Vorbis decoder elements together. At last, we'll also need an |
---|
42 | audio output element, we will use <quote>alsasink</quote>, which |
---|
43 | outputs sound to an ALSA audio device. |
---|
44 | </para> |
---|
45 | <para> |
---|
46 | The last thing left to do is to add all elements into a container |
---|
47 | element, a <classname>GstPipeline</classname>, and iterate this |
---|
48 | pipeline until we've played the whole song. We've previously |
---|
49 | learned how to add elements to a container bin in <xref |
---|
50 | linkend="chapter-bins"/>, and we've learned about element states |
---|
51 | in <xref linkend="section-elements-states"/>. We will use the function |
---|
52 | <function>gst_bin_sync_children_state ()</function> to synchronize |
---|
53 | the state of a bin on all of its contained children. |
---|
54 | </para> |
---|
55 | <para> |
---|
56 | Let's now add all the code together to get our very first audio |
---|
57 | player: |
---|
58 | </para> |
---|
59 | <programlisting> |
---|
60 | <!-- example-begin helloworld.c --> |
---|
61 | #include <gst/gst.h> |
---|
62 | |
---|
63 | /* |
---|
64 | * Global objects are usually a bad thing. For the purpose of this |
---|
65 | * example, we will use them, however. |
---|
66 | */ |
---|
67 | |
---|
68 | GstElement *pipeline, *source, *parser, *decoder, *sink; |
---|
69 | |
---|
70 | static void |
---|
71 | new_pad (GstElement *element, |
---|
72 | GstPad *pad, |
---|
73 | gpointer data) |
---|
74 | { |
---|
75 | /* We can now link this pad with the audio decoder and |
---|
76 | * add both decoder and audio output to the pipeline. */ |
---|
77 | gst_pad_link (pad, gst_element_get_pad (decoder, "sink")); |
---|
78 | gst_bin_add_many (GST_BIN (pipeline), decoder, sink, NULL); |
---|
79 | |
---|
80 | /* This function synchronizes a bins state on all of its |
---|
81 | * contained children. */ |
---|
82 | gst_bin_sync_children_state (GST_BIN (pipeline)); |
---|
83 | } |
---|
84 | |
---|
85 | int |
---|
86 | main (int argc, |
---|
87 | char *argv[]) |
---|
88 | { |
---|
89 | /* initialize GStreamer */ |
---|
90 | gst_init (&argc, &argv); |
---|
91 | |
---|
92 | /* check input arguments */ |
---|
93 | if (argc != 2) { |
---|
94 | g_print ("Usage: %s <Ogg/Vorbis filename>\n", argv[0]); |
---|
95 | return -1; |
---|
96 | } |
---|
97 | |
---|
98 | /* create elements */ |
---|
99 | pipeline = gst_pipeline_new ("audio-player"); |
---|
100 | source = gst_element_factory_make ("filesrc", "file-source"); |
---|
101 | parser = gst_element_factory_make ("oggdemux", "ogg-parser"); |
---|
102 | decoder = gst_element_factory_make ("vorbisdec", "vorbis-decoder"); |
---|
103 | sink = gst_element_factory_make ("alsasink", "alsa-output"); |
---|
104 | |
---|
105 | /* set filename property on the file source */ |
---|
106 | g_object_set (G_OBJECT (source), "location", argv[1], NULL); |
---|
107 | |
---|
108 | /* link together - note that we cannot link the parser and |
---|
109 | * decoder yet, becuse the parser uses dynamic pads. For that, |
---|
110 | * we set a new-pad signal handler. */ |
---|
111 | gst_element_link (source, parser); |
---|
112 | gst_element_link (decoder, sink); |
---|
113 | g_signal_connect (parser, "new-pad", G_CALLBACK (new_pad), NULL); |
---|
114 | |
---|
115 | /* put all elements in a bin - or at least the ones we will use |
---|
116 | * instantly. */ |
---|
117 | gst_bin_add_many (GST_BIN (pipeline), source, parser, NULL); |
---|
118 | |
---|
119 | /* Now set to playing and iterate. We will set the decoder and |
---|
120 | * audio output to ready so they initialize their memory already. |
---|
121 | * This will decrease the amount of time spent on linking these |
---|
122 | * elements when the Ogg parser emits the new-pad signal. */ |
---|
123 | gst_element_set_state (decoder, GST_STATE_READY); |
---|
124 | gst_element_set_state (sink, GST_STATE_READY); |
---|
125 | gst_element_set_state (pipeline, GST_STATE_PLAYING); |
---|
126 | |
---|
127 | /* and now iterate - the rest will be automatic from here on. |
---|
128 | * When the file is finished, gst_bin_iterate () will return |
---|
129 | * FALSE, thereby terminating this loop. */ |
---|
130 | while (gst_bin_iterate (GST_BIN (pipeline))) ; |
---|
131 | |
---|
132 | /* clean up nicely */ |
---|
133 | gst_element_set_state (pipeline, GST_STATE_NULL); |
---|
134 | gst_object_unref (GST_OBJECT (pipeline)); |
---|
135 | |
---|
136 | return 0; |
---|
137 | } |
---|
138 | <!-- example-end helloworld.c --> |
---|
139 | </programlisting> |
---|
140 | <!-- FIXME: this image needs updating --> |
---|
141 | <para> |
---|
142 | We now have created a complete pipeline. We can visualise the |
---|
143 | pipeline as follows: |
---|
144 | </para> |
---|
145 | <figure float="1" id="section-hello-img"> |
---|
146 | <title>The "hello world" pipeline</title> |
---|
147 | <mediaobject> |
---|
148 | <imageobject> |
---|
149 | <imagedata fileref="images/hello-world.ℑ" format="&IMAGE;" /> |
---|
150 | </imageobject> |
---|
151 | </mediaobject> |
---|
152 | </figure> |
---|
153 | </sect1> |
---|
154 | |
---|
155 | <sect1 id="section-helloworld-compilerun"> |
---|
156 | <title>Compiling and Running helloworld.c</title> |
---|
157 | <para> |
---|
158 | To compile the helloworld example, use: <command>gcc -Wall |
---|
159 | $(pkg-config --cflags --libs gstreamer-&GST_MAJORMINOR;) |
---|
160 | helloworld.c -o helloworld</command>. &GStreamer; makes use of |
---|
161 | <command>pkg-config</command> to get compiler and linker flags |
---|
162 | needed to compile this application. If you're running a |
---|
163 | non-standard installation, make sure the |
---|
164 | <classname>PKG_CONFIG_PATH</classname> environment variable is |
---|
165 | set to the correct location (<filename>$libdir/pkgconfig</filename>). |
---|
166 | application against the uninstalled location. |
---|
167 | </para> |
---|
168 | <para> |
---|
169 | You can run this example application with <command>./helloworld |
---|
170 | file.ogg</command>. Substitute <filename>file.ogg</filename> |
---|
171 | with your favourite Ogg/Vorbis file. |
---|
172 | </para> |
---|
173 | </sect1> |
---|
174 | |
---|
175 | <sect1 id="section-hello-world-conclusion"> |
---|
176 | <title>Conclusion</title> |
---|
177 | <para> |
---|
178 | This concludes our first example. As you see, setting up a pipeline |
---|
179 | is very low-level but powerful. You will see later in this manual how |
---|
180 | you can create a more powerful media player with even less effort |
---|
181 | using higher-level interfaces. We will discuss all that in <xref |
---|
182 | linkend="part-highlevel"/>. We will first, however, go more in-depth |
---|
183 | into more advanced &GStreamer; internals. |
---|
184 | </para> |
---|
185 | <para> |
---|
186 | It should be clear from the example that we can very easily replace |
---|
187 | the <quote>filesrc</quote> element with some other element that |
---|
188 | reads data from a network, or some other data source element that |
---|
189 | is better integrated with your desktop environment. Also, you can |
---|
190 | use other decoders and parsers to support other media types. You |
---|
191 | can use another audio sink if you're not running Linux, but Mac OS X, |
---|
192 | Windows or FreeBSD, or you can instead use a filesink to write audio |
---|
193 | files to disk instead of playing them back. By using an audio card |
---|
194 | source, you can even do audio capture instead of playback. All this |
---|
195 | shows the reusability of &GStreamer; elements, which is its greatest |
---|
196 | advantage. |
---|
197 | </para> |
---|
198 | </sect1> |
---|
199 | </chapter> |
---|