1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 #include <gst/gst.h>
24 
25 #include <stdlib.h>
26 
27 static GMainLoop *loop;
28 
29 static GstElement *
gen_video_element(void)30 gen_video_element (void)
31 {
32   GstElement *element;
33   GstElement *conv;
34   GstElement *sink;
35   GstPad *pad;
36 
37   element = gst_bin_new ("vbin");
38   conv = gst_element_factory_make ("videoconvert", "conv");
39   sink = gst_element_factory_make (DEFAULT_VIDEOSINK, "sink");
40   g_assert (sink);
41 
42   gst_bin_add (GST_BIN (element), conv);
43   gst_bin_add (GST_BIN (element), sink);
44   gst_element_link_pads (conv, "src", sink, "sink");
45 
46   pad = gst_element_get_static_pad (conv, "sink");
47   gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad));
48   gst_object_unref (pad);
49 
50   return element;
51 }
52 
53 static GstElement *
gen_audio_element(void)54 gen_audio_element (void)
55 {
56   GstElement *element;
57   GstElement *conv;
58   GstElement *sink;
59   GstPad *pad;
60 
61   element = gst_bin_new ("abin");
62   conv = gst_element_factory_make ("audioconvert", "conv");
63   sink = gst_element_factory_make (DEFAULT_AUDIOSINK, "sink");
64   g_assert (sink);
65 
66   gst_bin_add (GST_BIN (element), conv);
67   gst_bin_add (GST_BIN (element), sink);
68   gst_element_link_pads (conv, "src", sink, "sink");
69 
70   pad = gst_element_get_static_pad (conv, "sink");
71   gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad));
72   gst_object_unref (pad);
73 
74   return element;
75 }
76 
77 static void
pad_added_cb(GstElement * decodebin,GstPad * pad,gpointer data)78 pad_added_cb (GstElement * decodebin, GstPad * pad, gpointer data)
79 {
80   GstCaps *caps;
81   GstStructure *str;
82   GstPad *sinkpad;
83   GstElement *sink;
84   GstElement *pipeline;
85   const gchar *name;
86   GstStateChangeReturn ret;
87   GstPadLinkReturn lret;
88 
89   /* check media type */
90   caps = gst_pad_query_caps (pad, NULL);
91   str = gst_caps_get_structure (caps, 0);
92 
93   name = gst_structure_get_name (str);
94   g_print ("name: %s\n", name);
95 
96   if (g_strrstr (name, "audio")) {
97     sink = gen_audio_element ();
98   } else if (g_strrstr (name, "video")) {
99     sink = gen_video_element ();
100   } else {
101     sink = NULL;
102   }
103   gst_caps_unref (caps);
104 
105   if (sink) {
106     pipeline = GST_ELEMENT_CAST (data);
107 
108     /* add new sink to the pipeline */
109     gst_bin_add (GST_BIN_CAST (pipeline), sink);
110 
111     /* set the new sink tp PAUSED as well */
112     ret = gst_element_set_state (sink, GST_STATE_PAUSED);
113     if (ret == GST_STATE_CHANGE_FAILURE)
114       goto state_error;
115 
116     /* get the ghostpad of the sink bin */
117     sinkpad = gst_element_get_static_pad (sink, "sink");
118 
119     /* link'n'play */
120     lret = gst_pad_link (pad, sinkpad);
121     if (lret != GST_PAD_LINK_OK)
122       goto link_failed;
123 
124     gst_object_unref (sinkpad);
125   }
126   return;
127 
128   /* ERRORS */
129 state_error:
130   {
131     gst_bin_remove (GST_BIN_CAST (pipeline), sink);
132     g_warning ("could not change state of new sink (%d)", ret);
133     return;
134   }
135 link_failed:
136   {
137     g_warning ("could not link pad and sink (%d)", lret);
138     return;
139   }
140 }
141 
142 static void
error_eos_cb(GstBus * bus,GstMessage * msg,GMainLoop * main_loop)143 error_eos_cb (GstBus * bus, GstMessage * msg, GMainLoop * main_loop)
144 {
145   g_main_loop_quit (main_loop);
146 }
147 
148 gint
main(gint argc,gchar * argv[])149 main (gint argc, gchar * argv[])
150 {
151   GstElement *pipeline, *filesrc, *decodebin;
152   GstStateChangeReturn res;
153   GstBus *bus;
154 
155   gst_init (&argc, &argv);
156 
157   pipeline = gst_pipeline_new ("pipeline");
158 
159   filesrc = gst_element_factory_make ("filesrc", "filesrc");
160   g_assert (filesrc);
161   decodebin = gst_element_factory_make ("decodebin", "decodebin");
162   g_assert (decodebin);
163 
164   loop = g_main_loop_new (NULL, TRUE);
165   bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
166   gst_bus_add_signal_watch (bus);
167 
168   g_signal_connect (bus, "message::eos", G_CALLBACK (error_eos_cb), loop);
169   g_signal_connect (bus, "message::error", G_CALLBACK (error_eos_cb), loop);
170 
171   g_signal_connect (G_OBJECT (decodebin), "pad-added",
172       G_CALLBACK (pad_added_cb), pipeline);
173 
174   gst_bin_add_many (GST_BIN (pipeline), filesrc, decodebin, NULL);
175   gst_element_link (filesrc, decodebin);
176 
177   if (argc < 2) {
178     g_print ("usage: %s <uri>\n", argv[0]);
179     exit (-1);
180   }
181 
182   if (!g_str_has_prefix (argv[1], "file://")) {
183     g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
184   } else {
185     g_object_set (G_OBJECT (filesrc), "location", argv[1] + 7, NULL);
186   }
187 
188   /* set to paused, decodebin will autoplug and signal new_pad callbacks */
189   res = gst_element_set_state (pipeline, GST_STATE_PAUSED);
190   if (res == GST_STATE_CHANGE_FAILURE) {
191     g_print ("could not pause\n");
192     return -1;
193   }
194   /* wait for paused to complete */
195   res = gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
196   if (res == GST_STATE_CHANGE_FAILURE) {
197     g_print ("could not pause\n");
198     return -1;
199   }
200 
201   /* play, now all the sinks are added to the pipeline and are prerolled and
202    * ready to play. */
203   res = gst_element_set_state (pipeline, GST_STATE_PLAYING);
204   if (res == GST_STATE_CHANGE_FAILURE) {
205     g_print ("could not play\n");
206     return -1;
207   }
208 
209   /* go in the mainloop now */
210   g_main_loop_run (loop);
211 
212   return 0;
213 }
214