mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-16 13:26:36 +00:00
203 lines
6.5 KiB
Text
203 lines
6.5 KiB
Text
|
A little explanation of the first autoplugger in GStreamer:
|
||
|
|
||
|
Autoplugging is implemented in the following places:
|
||
|
|
||
|
gstpipeline.c : construction of the pipeline
|
||
|
gstautoplug.c : selection of the elementfactories needed for autoplugging
|
||
|
|
||
|
1) pipeline setup
|
||
|
-----------------
|
||
|
|
||
|
before any autoplugging will take place, a new GstPipeline has to be created.
|
||
|
The autoplugger needs to have a src element and one or more sink elements. the
|
||
|
autoplugger will try to find the elements needed to connect the src element
|
||
|
to the sinks.
|
||
|
|
||
|
using:
|
||
|
|
||
|
gst_pipeline_add_src (GstPipeline *pipeline, GstElement *element);
|
||
|
|
||
|
a source element is added to the pipeline. only one src element can be added
|
||
|
for now.
|
||
|
|
||
|
using:
|
||
|
|
||
|
gst_pipeline_add_sink (GstPipeline *pipeline, GstElement *element);
|
||
|
|
||
|
a sink element can be added to the pipeline.
|
||
|
|
||
|
2) starting autoplug
|
||
|
--------------------
|
||
|
|
||
|
when the pipeline has been set up as above, you will call
|
||
|
|
||
|
gst_pipeline_autoplug (GstPipeline *pipeline);
|
||
|
|
||
|
to start the autoplugger. this will be done in four phases
|
||
|
|
||
|
ex. we are going to autoplug an mpeg1 system stream.
|
||
|
|
||
|
2a) phase1: figure out the type (GstCaps) of the src element.
|
||
|
-------------------------------------------------------------
|
||
|
|
||
|
the gsttypefind element is connected to the "src" pad of the source
|
||
|
element. gst_bin_iterate is called in a loop until gsttypefind
|
||
|
signals "have_type". the gst_bin_iterate is stopped and the GstCaps
|
||
|
is retrieved from the gsttypefind element.
|
||
|
|
||
|
gsttypefind is disconnected from the src element and removed from the
|
||
|
bin.
|
||
|
|
||
|
the GstCaps of the source element is called src_caps later on.
|
||
|
|
||
|
ex. all typefind functions are tried and the one in mpeg1types will
|
||
|
return a GstCaps:
|
||
|
|
||
|
video/mpeg,
|
||
|
"systemstream", GST_PROPS_BOOLEAN (TRUE),
|
||
|
"mpegversion", GST_PROPS_INT (1),
|
||
|
NULL
|
||
|
|
||
|
|
||
|
2b) phase2: create lists of factories.
|
||
|
---------------------------------------
|
||
|
|
||
|
for each sink:
|
||
|
{
|
||
|
sinkpad = take the first sinkpad of the sink (HACK)
|
||
|
call
|
||
|
|
||
|
list[i] = gst_autoplug_caps (src_caps, sinkpad->caps);
|
||
|
|
||
|
I++;
|
||
|
}
|
||
|
|
||
|
gst_autoplug_caps will figure out (based on the padtemplates)
|
||
|
which elementfactories are needed to connect src_caps to sinkpad->caps
|
||
|
and will return them in a list.
|
||
|
|
||
|
ex. we have two sinks with following caps:
|
||
|
|
||
|
video/raw audio/raw
|
||
|
"...." "...."
|
||
|
|
||
|
gst_autoplug_caps will figure out that for the first sink the following
|
||
|
elements are needed:
|
||
|
|
||
|
mpeg1parse, mp1videoparse, mpeg_play
|
||
|
|
||
|
for the second sink the following is needed:
|
||
|
|
||
|
mpeg1parse, mp3parse, mpg123
|
||
|
|
||
|
We now have two lists of elementfactories.
|
||
|
|
||
|
2c) phase3: collect common elements from the lists.
|
||
|
---------------------------------------------------
|
||
|
|
||
|
the rationale is that from the lists we have created in phase2, there
|
||
|
must be some element that is a splitter and that it has to come first (HACK)
|
||
|
We try to find that element by comparing the lists until an element differs.
|
||
|
|
||
|
we add the common elements to the bin and run gst_pipeline_pads_autoplug. this
|
||
|
function will loop over the pads of the previous element and the one we
|
||
|
just added, and tries to connect src to sink if possible.
|
||
|
|
||
|
If a connection between the two elements could not be made, a signal "new_pad"
|
||
|
is connected to the element so that pad connection can occur later on when
|
||
|
the pad is actually created.
|
||
|
|
||
|
ex. when we compare the two lists we see that we have common element: mpeg1parse.
|
||
|
|
||
|
we add this element to the bin and try to connect it to the previous element in
|
||
|
the bin, the disksrc.
|
||
|
|
||
|
we see that the src pad of the disksrc and the sinkpad of the mpeg1parse element
|
||
|
can be connected because they are compatible. We have a pipeline like:
|
||
|
|
||
|
---------) (--------
|
||
|
disksrc ! ! mpeg1parse
|
||
|
src --- sink
|
||
|
---------) (--------
|
||
|
|
||
|
|
||
|
2d) phase4: add remaining elements
|
||
|
----------------------------------
|
||
|
|
||
|
now we loop over all the list and try to add the remaining elements
|
||
|
|
||
|
(HACK) we always use a new thread for the elements when there is a common
|
||
|
element found.
|
||
|
|
||
|
if a new thread is needed (either bacuase the previous element is a common
|
||
|
element or the object flag of the next element is set to GST_SUGGEST_THREAD)
|
||
|
we add a queue to the bin and we add a new thread. We add the elements to
|
||
|
the bin and connect them using gst_pipeline_pads_autoplug.
|
||
|
|
||
|
If we add a queue, we have to copy the caps of the sink element of the queue
|
||
|
to the src pad of the queue (else they won't connect)
|
||
|
|
||
|
we finally arrive at the sink element and we're done.
|
||
|
|
||
|
ex.
|
||
|
|
||
|
we have just found our mpeg1parse common element, so we start a thread.
|
||
|
We add a queue to the bin and a new thread, we add the elements
|
||
|
mp1videoparse and mpeg_play to the thread. We arrive at the videosink, we
|
||
|
see that the SUGGEST_THREAD flag is set, we add a queue and a thread and
|
||
|
add the videosink in the thread.
|
||
|
|
||
|
the same procedure happens for the audio part. We are now left with the
|
||
|
following pipeline:
|
||
|
|
||
|
We will also have set a signal "new_pad" on the mpeg1parse element bacause
|
||
|
the element mp1videoparse could not be connected to the element just yet.
|
||
|
|
||
|
(------------------------------------) (----------
|
||
|
!thread ! ! thread
|
||
|
! (-------------) (---------) ! ! (---------)
|
||
|
! !mp1videoparse! !mpeg_play! ! ! !videosink!
|
||
|
videoqueue--sink src -- sink src -- queue --- sink !
|
||
|
---------) (-----------) ! (-------------) (---------) ! ! (---------)
|
||
|
disksrc ! ! mpeg1parse! (------------------------------------) (-------------
|
||
|
src --- sink !
|
||
|
---------) (-----------)
|
||
|
queue----- same for audio
|
||
|
|
||
|
|
||
|
then we play, create_plan happens, data is flowing and the "new_pad" signal is called
|
||
|
from mpeg1parse, gst_pipeline_pad_autoplug is called and the connection between
|
||
|
mpeg1parse and the videoqueue is made. same for audio.
|
||
|
|
||
|
voila. smame procedure for mp3/vorbis/avi/qt/mpeg2 etc...
|
||
|
|
||
|
|
||
|
Problems:
|
||
|
---------
|
||
|
|
||
|
this is obviously a very naive solution. the creation of the elements actually happens
|
||
|
beforehand. MPEG2, for one, fails bacause there are multiple possibilities to go
|
||
|
from the mpeg demuxer to audio/raw (ac3, mp3)
|
||
|
|
||
|
Also any intermedia elements like mixers (subtitles) are not possible because we
|
||
|
assume that after the common elements, the streams to not converge anymore.
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|