5 We'll first describe how to use the autoplugger. We will provide
6 a use case: autoplug an mpeg1 system stream for audio/video playback.
9 a) creating an autoplugger
10 --------------------------
12 Before any autoplugging can be done, you'll have to create an
13 autoplugger object. Autoplugger objects (autopluggers) are
14 provided by plugins and are created with gst_autoplugfactor_make().
16 GStreamer has provisions for two types of autopluggers:
18 - regular autopluggers, which act as a complex element construction
19 mechanism. They usually don't create threads and operate solely on
20 GstCaps* for the source and destination. The complex elements
21 created by regular autopluggers have src and sink pad compatible
22 with the requested GstCaps*.
24 - renderer autopluggers, which are designed to create a complex
25 object that can be used to playback media. Renderer autoplugged
26 complex elements have no src pads, only one sink pad.
28 We'll create a renderer autoplugger like this:
31 ! GstAutoplug *autoplug;
33 ! autoplug = gst_autoplugfactory_make ("staticrender");
37 b) finding out the source media type.
38 -------------------------------------
40 Before we can start the autoplugger, we have to find out the
41 source media type. This can be done using the typefind functions
42 provided by various plugins.
44 We will create a little pipeline to detect the media type by connecting
45 a disksrc element to a typefind element. The typefind element will
46 repeatedly call all registered typefind functions with the buffer it
47 receives on its sink pad. when a typefind function returns a non NULL
48 GstCaps*, that caps is set to the sink pad of the typefind element and
49 a signal is emitted to notify the app.
51 Due to caps negotiation, the disksrc will have the detected GstCaps*
54 We typically use a function like below to detect the type of a media stream
55 on an element (typically a disksrc). The function accepts a pipeline and the
56 element inside the pipeline on which the typefind should be performed (passing
57 a GstPad* is probably a better option FIXME).
61 ! gst_play_typefind (GstBin *bin, GstElement *element)
63 ! GstElement *typefind;
64 ! GstCaps *caps = NULL;
66 ! typefind = gst_elementfactory_make ("typefind", "typefind");
67 ! g_return_val_if_fail (typefind != NULL, FALSE);
69 ! gst_pad_connect (gst_element_get_pad (element, "src"),
70 ! gst_element_get_pad (typefind, "sink"));
72 ! gst_bin_add (bin, typefind);
74 ! gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING);
76 ! // push a buffer... the have_type signal handler will set the found flag
77 ! gst_bin_iterate (bin);
79 ! gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL);
81 ! caps = gst_pad_get_caps (gst_element_get_pad (element, "src"));
83 ! gst_pad_disconnect (gst_element_get_pad (element, "src"),
84 ! gst_element_get_pad (typefind, "sink"));
85 ! gst_bin_remove (bin, typefind);
86 ! gst_object_unref (GST_OBJECT (typefind));
92 Also note that the disksrc was added to the pipeline before calling this
95 When the function returns a non-NULL pointer, the media type has been
96 determined and autoplugging can commence.
98 Assume that in our mpeg1 use case the above function returns a GstCaps*
102 ! srccaps = GST_CAPS_NEW ("mpeg1system_typefind",
104 ! "mpegversion", GST_PROPS_INT (1),
105 ! "systemstream", GST_PROPS_BOOLEAN (TRUE)
110 c) Performing the autoplugging
111 ------------------------------
113 Since we use the renderer API, we have to create the output elements
114 that are going to be used as the final sink elements.
117 ! osssink = gst_elementfactory_make("osssink", "play_audio");
118 ! videosink = gst_elementfactory_make("xvideosink", "play_video");
121 We then create a complex element using the following code.
124 ! new_element = gst_autoplug_to_renderers (autoplug,
130 ! if (!new_element) {
131 ! g_print ("could not autoplug, no suitable codecs found...\n");
136 2) Autoplugging internals
137 -------------------------
139 We will now describe the internals of the above gst_autoplug_to_renderers()
140 function call. This code is implemented in a plugin found in:
142 gst/autoplug/gststaticautoplugrender.c
146 a) phase1: create lists of factories.
147 ---------------------------------------
149 The autoplugger will start with executing the following piece of
157 ! sinkpad = take the first sinkpad of the sink (HACK)
159 ! list[i] = gst_autoplug_caps (srccaps, sinkpad->caps);
165 gst_autoplug_caps will figure out (based on the padtemplates)
166 which elementfactories are needed to connect srccaps to sinkpad->caps
167 and will return them in a list.
169 The element list is created by using a modified shortest path algorithm
170 by Dijkstra (http://www.orie.cornell.edu/~or115/handouts/handout3/handout3.html).
171 The nodes of the graph are the elementfactories and the weight of the
172 arcs is based on the pad compatibility of the padtemplates of the
173 elementfactory. For incompatible elementfactories, we use a weight of
174 MAX_COST (999999) and for compatible padtemplates we use 1.
176 ex. we have two sinks with following caps:
179 ! video/raw audio/raw
183 gst_autoplug_caps will figure out that for the first sink the following
187 ! mpeg1parse, mp1videoparse, mpeg_play
190 for the second sink the following is needed:
196 Note that for the audio connection the element list "mpeg1parse, mp3parse,
197 mpg123" would also connect the srccaps to the audiosink caps. Since the
198 "mpeg1parse, mad" list is shorter, it it always preferred by the autoplugger.
200 We now have two lists of elementfactories.
203 b) phase2: collect common elements from the lists and add them to a bin.
204 ------------------------------------------------------------------------
206 The rationale is that from the lists we have created in phase1, there
207 must be some element that is a splitter and that it has to come first (HACK)
208 We try to find that element by comparing the lists until an element differs.
210 We start by creating a toplevel bin that is going to be our complex element.
212 In our use-case we find that mpeg1parse is an element common to both lists,
213 so we add it to the bin. We then try to find a good ghostpad for the resulting
214 complex element. This is done by looping over the sink pads of the first common
215 element and taking the pad that is compatible with the srcaps.
217 We end up with a bin like this:
219 ! (----------------------)
225 ! ! / (------------) !
227 ! (----------------------)
231 c) phase3: add remaining elements
232 ---------------------------------
234 now we loop over all the list and try to add the remaining elements
236 (HACK) we always use a new thread for the elements when there is a common
239 if a new thread is needed (either becuase the previous element is a common
240 element or the object flag of the next element is set to GST_SUGGEST_THREAD)
241 we add a queue to the bin and we add a new thread. We add the elements to
242 the bin and connect them using gst_pipeline_pads_autoplug.
244 we finally arrive at the sink element and we're done.
248 we have just found our mpeg1parse common element, so we start a thread.
249 We add a queue to the bin and a new thread, we add the elements
250 mp1videoparse and mpeg_play to the thread. We arrive at the videosink, we
251 see that the SUGGEST_THREAD flag is set, we add a queue and a thread and
252 add the videosink in the thread.
254 the same procedure happens for the audio part. We are now left with the
257 We will also have set a signal "new_pad" on the mpeg1parse element because
258 the element mp1videoparse could not be connected to the element just yet.
260 (---------------------------------------------------------------------------------------------)
263 ! (----------------------------------------) (------------) !
264 ! !thread ! ! thread ! !
265 ! (-----) ! (-------------) (---------) (-----) ! ! (---------)! !
266 ! !queue! ! !mp1videoparse! !mpeg_play! !queue! ! ! !videosink!! !
267 ! sink src-sink src-sink src-sink src-sink !! !
268 ! (-----------) (-----) ! (-------------) (---------) (-----) ! ! (---------)! !
269 ! ! mpeg1parse! (----------------------------------------) (------------) !
272 sink (----------------------------------------) (------------) !
273 ! !thread ! ! thread ! !
274 ! (-----) ! (-------------) (-----) ! ! (---------)! !
275 ! !queue! ! !mad ! !queue! ! ! !videosink!! !
276 ! sink src-sink src ------------ sink src-sink !! !
277 ! (-----) ! (-------------) (-----) ! ! (---------)! !
278 ! (----------------------------------------) (------------) !
279 (---------------------------------------------------------------------------------------------)
281 The autoplugger will return the autoplug_bin. the app will then connect the
282 disksrc to the sinkpad of the autoplugged bin.
284 Then we play, create_plan happens, data is flowing and the "new_pad" signal is called
285 from mpeg1parse, gst_pipeline_pad_autoplug is called and the connection between
286 mpeg1parse and the videoqueue is made. same for audio.
288 Et voila. same procedure for mp3/vorbis/avi/qt/mpeg2 etc...