| <chapter id="cha-hello2"> |
| <title>Your second application</title> |
| <para> |
| FIXME: delete this section, talk more about the spider. In a previous chapter we created a first |
| version of the helloworld application. We then explained a better way of creating the elements |
| using factories identified by MIME types and the autoplugger. |
| </para> |
| |
| <sect1> |
| <title>Autoplugging helloworld </title> |
| <para> |
| We will create a second version of the helloworld application using |
| autoplugging. Its source code is a bit more complicated but |
| it can handle many more data types. It can even play the audio track |
| of a video file. |
| </para> |
| <para> |
| Here is the full program listing. Start by looking at the main () |
| function. |
| </para> |
| |
| <programlisting> |
| /* example-begin helloworld2.c */ |
| #include <gst/gst.h> |
| |
| static void gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline); |
| static void gst_play_cache_empty (GstElement *element, GstElement *pipeline); |
| |
| static void |
| gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline) |
| { |
| GstElement *osssink; |
| GstElement *new_element; |
| GstAutoplug *autoplug; |
| GstElement *autobin; |
| GstElement *filesrc; |
| GstElement *cache; |
| |
| g_print ("GstPipeline: play have type\n"); |
| |
| gst_element_set_state (pipeline, GST_STATE_PAUSED); |
| |
| filesrc = gst_bin_get_by_name (GST_BIN (pipeline), "disk_source"); |
| autobin = gst_bin_get_by_name (GST_BIN (pipeline), "autobin"); |
| cache = gst_bin_get_by_name (GST_BIN (autobin), "cache"); |
| |
| /* unlink the typefind from the pipeline and remove it */ |
| gst_element_unlink (cache, typefind); |
| gst_bin_remove (GST_BIN (autobin), typefind); |
| |
| /* and an audio sink */ |
| osssink = gst_element_factory_make ("osssink", "play_audio"); |
| g_assert (osssink != NULL); |
| |
| autoplug = gst_autoplug_factory_make ("staticrender"); |
| g_assert (autoplug != NULL); |
| |
| new_element = gst_autoplug_to_renderers (autoplug, caps, osssink, NULL); |
| |
| if (!new_element) { |
| g_print ("could not autoplug, no suitable codecs found...\n"); |
| exit (-1); |
| } |
| |
| gst_element_set_name (new_element, "new_element"); |
| |
| gst_bin_add (GST_BIN (autobin), new_element); |
| |
| g_object_set (G_OBJECT (cache), "reset", TRUE, NULL); |
| |
| gst_element_link (cache, new_element); |
| |
| gst_element_set_state (pipeline, GST_STATE_PLAYING); |
| } |
| |
| static void |
| gst_play_cache_empty (GstElement *element, GstElement *pipeline) |
| { |
| GstElement *autobin; |
| GstElement *filesrc; |
| GstElement *cache; |
| GstElement *new_element; |
| |
| g_print ("have cache empty\n"); |
| |
| gst_element_set_state (pipeline, GST_STATE_PAUSED); |
| |
| filesrc = gst_bin_get_by_name (GST_BIN (pipeline), "disk_source"); |
| autobin = gst_bin_get_by_name (GST_BIN (pipeline), "autobin"); |
| cache = gst_bin_get_by_name (GST_BIN (autobin), "cache"); |
| new_element = gst_bin_get_by_name (GST_BIN (autobin), "new_element"); |
| |
| gst_element_unlink (filesrc, cache); |
| gst_element_unlink (cache, new_element); |
| gst_bin_remove (GST_BIN (autobin), cache); |
| gst_element_link (filesrc, new_element); |
| |
| gst_element_set_state (pipeline, GST_STATE_PLAYING); |
| |
| g_print ("done with cache_empty\n"); |
| } |
| |
| int |
| main (int argc, char *argv[]) |
| { |
| GstElement *filesrc; |
| GstElement *pipeline; |
| GstElement *autobin; |
| GstElement *typefind; |
| GstElement *cache; |
| |
| gst_init (&argc, &argv); |
| |
| if (argc != 2) { |
| g_print ("usage: %s <filename with audio>\n", argv[0]); |
| exit (-1); |
| } |
| |
| /* create a new pipeline to hold the elements */ |
| pipeline = gst_pipeline_new ("pipeline"); |
| g_assert (pipeline != NULL); |
| |
| /* create a disk reader */ |
| filesrc = gst_element_factory_make ("filesrc", "disk_source"); |
| g_assert (filesrc != NULL); |
| g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); |
| gst_bin_add (GST_BIN (pipeline), filesrc); |
| |
| autobin = gst_bin_new ("autobin"); |
| cache = gst_element_factory_make ("autoplugcache", "cache"); |
| g_signal_connect (G_OBJECT (cache), "cache_empty", |
| G_CALLBACK (gst_play_cache_empty), pipeline); |
| |
| typefind = gst_element_factory_make ("typefind", "typefind"); |
| g_signal_connect (G_OBJECT (typefind), "have_type", |
| G_CALLBACK (gst_play_have_type), pipeline); |
| gst_bin_add (GST_BIN (autobin), cache); |
| gst_bin_add (GST_BIN (autobin), typefind); |
| |
| gst_element_link (cache, typefind); |
| gst_element_add_ghost_pad (autobin, |
| gst_element_get_pad (cache, "sink"), "sink"); |
| |
| gst_bin_add (GST_BIN( pipeline), autobin); |
| gst_element_link (filesrc, autobin); |
| |
| /* start playing */ |
| gst_element_set_state( GST_ELEMENT (pipeline), GST_STATE_PLAYING); |
| |
| while (gst_bin_iterate (GST_BIN (pipeline))); |
| |
| /* stop the pipeline */ |
| gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); |
| |
| gst_object_unref (GST_OBJECT (pipeline)); |
| |
| exit(0); |
| } |
| /* example-end helloworld2.c */ |
| </programlisting> |
| <para> |
| We start by constructing a 'filesrc' element and an 'autobin' element that |
| holds the autoplugcache and the typefind element. |
| </para> |
| <para> |
| We attach the "cache_empty" signal to gst_play_cache_empty and the |
| "have_type" to our gst_play_have_type function. |
| </para> |
| |
| <para> |
| The _have_type function first sets the pipeline to the PAUSED state |
| so that it can safely modify the pipeline. It then finds the elements |
| it is going to manipulate in the pipeline with: |
| </para> |
| <programlisting> |
| filesrc = gst_bin_get_by_name (GST_BIN (pipeline), "disk_source"); |
| autobin = gst_bin_get_by_name (GST_BIN (pipeline), "autobin"); |
| cache = gst_bin_get_by_name (GST_BIN (autobin), "cache"); |
| </programlisting> |
| |
| <para> |
| Now we have a handle to the elements we are going to manipulate in |
| the next step. |
| </para> |
| <para> |
| We don't need the typefind element anymore so we remove it from |
| the pipeline: |
| </para> |
| <programlisting> |
| /* unlink the typefind from the pipeline and remove it */ |
| gst_element_unlink (cache, "src", typefind, "sink"); |
| gst_bin_remove (GST_BIN (autobin), typefind); |
| </programlisting> |
| |
| <para> |
| Our next step is to construct an element that can play the type we just |
| detected. We are going to use the autoplugger to create an element that |
| links the type to an osssink. We add the new element to our |
| autobin. |
| </para> |
| |
| <programlisting> |
| /* and an audio sink */ |
| osssink = gst_element_factory_make("osssink", "play_audio"); |
| g_assert(osssink != NULL); |
| |
| autoplug = gst_autoplug_factory_make ("staticrender"); |
| g_assert (autoplug != NULL); |
| |
| new_element = gst_autoplug_to_renderers (autoplug, |
| caps, |
| osssink, |
| NULL); |
| |
| if (!new_element) { |
| g_print ("could not autoplug, no suitable codecs found...\n"); |
| exit (-1); |
| } |
| |
| gst_element_set_name (new_element, "new_element"); |
| |
| gst_bin_add (GST_BIN (autobin), new_element); |
| </programlisting> |
| |
| <para> |
| Our next step is to reset the cache so that the buffers used by the |
| typefind element are fed into the new element we just created. We reset |
| the cache by setting the "reset" property of the cache element to TRUE. |
| </para> |
| <programlisting> |
| g_object_set (G_OBJECT (cache), "reset", TRUE, NULL); |
| |
| gst_element_link (cache, "src", new_element, "sink"); |
| </programlisting> |
| <para> |
| Finally we set the pipeline back to the playing state. At this point the |
| cache will replay the buffers. We will be notified when the cache is empty |
| by the gst_play_cache_empty callback function. |
| </para> |
| |
| <para> |
| The cache empty function simply removes the autoplugcache element from |
| the pipeline and relinks the filesrc to the autoplugged element. |
| </para> |
| |
| <para> |
| To compile the helloworld2 example, use: |
| </para> |
| <programlisting> |
| gcc -Wall `pkg-config gstreamer-&GST_MAJORMINOR; --cflags --libs` helloworld2.c \ |
| -o helloworld2 |
| </programlisting> |
| <para> |
| You can run the example with |
| (substitute helloworld.mp3 with you favorite audio file): |
| </para> |
| <programlisting> |
| ./helloworld2 helloworld.mp3 |
| </programlisting> |
| <para> |
| You can also try to use an AVI or MPEG file as its input. |
| Using autoplugging, |
| <application>GStreamer</application> |
| will automatically figure out how to |
| handle the stream. |
| Remember that only the audio part will be played because |
| we have only added an osssink to the pipeline. |
| </para> |
| <programlisting> |
| ./helloworld2 mymovie.mpeg |
| </programlisting> |
| |
| </sect1> |
| </chapter> |