mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-27 00:16:37 +00:00
More docs (most of them just empty...)
Original commit message from CVS: More docs (most of them just empty...) Added automatic pad plugging. Added automatic dynamic pad plugging. Changed some codecs to correctly set their pad types.
This commit is contained in:
parent
3cff190b74
commit
a703c01d94
19 changed files with 736 additions and 32 deletions
318
docs/manual/advanced.sgml
Normal file
318
docs/manual/advanced.sgml
Normal file
|
@ -0,0 +1,318 @@
|
||||||
|
<chapter id="cha-advanced">
|
||||||
|
<title>Threads</title>
|
||||||
|
<para>
|
||||||
|
The small application we created in the previous chapter used the
|
||||||
|
concept of a factory to create the elements. In this chapter we will
|
||||||
|
show you how to use the factory concepts.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<sect1>
|
||||||
|
<title>The problems with the helloworld example</title>
|
||||||
|
<para>
|
||||||
|
If we take a look at how the elements were created in the previous
|
||||||
|
example we used a rather crude mechanism:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
...
|
||||||
|
/* now it's time to get the parser */
|
||||||
|
parse = gst_elementfactory_make("mp3parse","parse");
|
||||||
|
decoder = gst_elementfactory_make("mpg123","decoder");
|
||||||
|
...
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
While this mechanism is quite effective it also has one big problems:
|
||||||
|
The elements are created base on their name. Indeed, we create an
|
||||||
|
element mpg123 by explicitly stating the mpg123 elements name.
|
||||||
|
Our little program therefore always uses the mpg123 decoder element
|
||||||
|
to decode the MP3 audio stream, even if there are 3 other MP3 decoders
|
||||||
|
in the system. We will see how we can use a more general way to create
|
||||||
|
an MP3 decoder element.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
We have to introduce the concept of MIME types added to the source and
|
||||||
|
sink pads.
|
||||||
|
</para>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1>
|
||||||
|
<title>MIME Types</title>
|
||||||
|
<para>
|
||||||
|
GStreamer uses MIME types to indentify the different types of data
|
||||||
|
that can be handled by the elements. They are the high level
|
||||||
|
mechanisms to make sure that everyone is talking about the right
|
||||||
|
kind of data.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
A MIME (Multipurpose Internet Mail Extension) types are a set of
|
||||||
|
string that donote a certain type of data. examples include:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
audio/raw : raw audio samples
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
audio/mpeg : mpeg audio
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
video/mpeg : mpeg video
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
An element must associate a MIME type to its source and sink pads
|
||||||
|
when it is loaded into the system. GStreamer knows about the
|
||||||
|
different elements and what type of data they expect and emit.
|
||||||
|
This allows for very dynamic and extensible element creation as we
|
||||||
|
will see.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
In our helloworld example the elements we constructed would have the
|
||||||
|
following MIME types associated with their source and sink pads:
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
We will see how you can create an element based on the MIME types
|
||||||
|
of its source and sink pads. This way the end-user will have the
|
||||||
|
ability to choose his/her favorite audio/mpeg decoder without
|
||||||
|
you even having to care about it.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The typing of the source and sink pads also makes it possible to
|
||||||
|
'autoplug' a pipeline. We will have the ability to say: "construct
|
||||||
|
me a pipeline that does an audio/mpeg to audio/raw conversion".
|
||||||
|
</para>
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
The basic GStreamer library does not try to solve all of your
|
||||||
|
autoplug problems. It leaves the hard decisions to the application
|
||||||
|
programmer, where they belong.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1>
|
||||||
|
<title>GStreamer types</title>
|
||||||
|
<para>
|
||||||
|
GStreamer assigns a unique number to all registered MIME types. It
|
||||||
|
also maintains a list of all elements that either uses this type
|
||||||
|
as a source or as a sink. GStreamer also keeps a reference to
|
||||||
|
a function that can be used to determine if a given buffer is of
|
||||||
|
the given MIME type.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
There is also an association between a MIME type and a file
|
||||||
|
extension.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The type information is maintained in a list of
|
||||||
|
<classname>GstType</classname>. The definition of a
|
||||||
|
<classname>GstType</classname> is like:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
typedef gboolean (*GstTypeFindFunc) (GstBuffer *buf,gpointer *priv);
|
||||||
|
|
||||||
|
typedef struct _GstType GstType;
|
||||||
|
|
||||||
|
struct _GstType {
|
||||||
|
guint16 id; /* type id (assigned) */
|
||||||
|
|
||||||
|
gchar *mime; /* MIME type */
|
||||||
|
gchar *exts; /* space-delimited list of extensions */
|
||||||
|
|
||||||
|
GstTypeFindFunc typefindfunc; /* typefind function */
|
||||||
|
|
||||||
|
GList *srcs; /* list of src objects for this type */
|
||||||
|
GList *sinks; /* list of sink objects for type */
|
||||||
|
};
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
All operations on <classname>GstType</classname> occur via their
|
||||||
|
<classname>guint16 id</classname> numbers, with <classname>GstType</classname>
|
||||||
|
structure private to the GStreamer library.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>MIME type to id conversion</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
We can obtain the id for a given MIME type
|
||||||
|
with the following piece of code:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
guint16 id;
|
||||||
|
|
||||||
|
id = gst_type_find_by_mime("audio/mpeg");
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
This function will return 0 if the type was not known.
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>id to <classname>GstType</classname> conversion</title>
|
||||||
|
<para>
|
||||||
|
We can obtain the <classname>GstType</classname> for a given id
|
||||||
|
with the following piece of code:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
GstType *type;
|
||||||
|
|
||||||
|
type = gst_type_find_by_id(id);
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
This function will return NULL if the id was associated with
|
||||||
|
any known <classname>GstType</classname>
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>extension to id conversion</title>
|
||||||
|
<para>
|
||||||
|
We can obtain the id for a given file extension
|
||||||
|
with the following piece of code:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
guint16 id;
|
||||||
|
|
||||||
|
id = gst_type_find_by_ext(".mp3");
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
This function will return 0 if the extension was not known.
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>id to <classname>GstElementFactory</classname> conversion</title>
|
||||||
|
<para>
|
||||||
|
When we have obtained a given type id using one of the above methods,
|
||||||
|
we can obtain a list of all the elements that operate on this MIME
|
||||||
|
type or extension.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Obtain a list of all the elements that use this id as source with:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
GList *list;
|
||||||
|
|
||||||
|
list = gst_type_gst_srcs(id);
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Obtain a list of all the elements that use this id as sink with:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
GList *list;
|
||||||
|
|
||||||
|
list = gst_type_gst_sinks(id);
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
When you have a list of elements, you can simply take the first
|
||||||
|
element of the list to obtain an appropriate element.
|
||||||
|
</para>
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
As you can see, there might be a multitude of elements that
|
||||||
|
are able to operate on video/raw types. some might include:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
an MP3 audio encoder.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
an audio sink.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
an audio resampler.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
a spectrum filter.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
Depending on the application, you might want to use a different
|
||||||
|
element. This is why GStreamer leaves that decision up to the
|
||||||
|
application programmer.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>id to id path detection</title>
|
||||||
|
<para>
|
||||||
|
You can obtain a <classname>GList</classname> of elements that
|
||||||
|
will transform the source id into the destination id.
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
GList *list;
|
||||||
|
|
||||||
|
list = gst_type_gst_sink_to_src(sourceid, sinkid);
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
This piece of code will give you the elements needed to construct
|
||||||
|
a path from sourceid to sinkid. This function is mainly used in
|
||||||
|
autoplugging the pipeline.
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1>
|
||||||
|
<title>creating elements with the factory</title>
|
||||||
|
<para>
|
||||||
|
In the previous section we described how you could obtain
|
||||||
|
an element factory using MIME types. One the factory has been
|
||||||
|
obtained, you can create an element using:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
GstElementFactory *factory;
|
||||||
|
GstElement *element;
|
||||||
|
|
||||||
|
// obtain the factory
|
||||||
|
factory = ...
|
||||||
|
|
||||||
|
element = gst_elementfactory_create(factory, "name");
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
This way, you do not have to create elements by name which
|
||||||
|
allows the end-user to select the elements he/she prefers for the
|
||||||
|
given MIME types.
|
||||||
|
</para>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1>
|
||||||
|
<title>GStreamer basic types</title>
|
||||||
|
<para>
|
||||||
|
GStreamer only has two builtin types:
|
||||||
|
</para>
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
audio/raw : raw audio samples
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
video/raw and image/raw : raw video data
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
<para>
|
||||||
|
All other MIME types are maintained by the plugin elements.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</sect1>
|
||||||
|
</chapter>
|
6
docs/manual/cothreads.sgml
Normal file
6
docs/manual/cothreads.sgml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<chapter id="cha-cothreads">
|
||||||
|
<title>Cothreads</title>
|
||||||
|
<para>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</chapter>
|
6
docs/manual/dynamic.sgml
Normal file
6
docs/manual/dynamic.sgml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<chapter id="cha-dynamic">
|
||||||
|
<title>Dynamic pipelines</title>
|
||||||
|
<para>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</chapter>
|
|
@ -3,9 +3,14 @@
|
||||||
<para>
|
<para>
|
||||||
The small application we created in the previous chapter used the
|
The small application we created in the previous chapter used the
|
||||||
concept of a factory to create the elements. In this chapter we will
|
concept of a factory to create the elements. In this chapter we will
|
||||||
show you how to use the factory concepts.
|
show you how to use the factory concepts to create elements based
|
||||||
|
on what they do instead of how they are called.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
We will first explain the concepts involved before we move on
|
||||||
|
to the reworked helloworld example using autoplugging.
|
||||||
|
</para>
|
||||||
<sect1>
|
<sect1>
|
||||||
<title>The problems with the helloworld example</title>
|
<title>The problems with the helloworld example</title>
|
||||||
<para>
|
<para>
|
||||||
|
@ -194,7 +199,7 @@ struct _GstType {
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2>
|
<sect2>
|
||||||
<title>id to <classname>GstElement</classname> conversion</title>
|
<title>id to <classname>GstElementFactory</classname> conversion</title>
|
||||||
<para>
|
<para>
|
||||||
When we have obtained a given type id using one of the above methods,
|
When we have obtained a given type id using one of the above methods,
|
||||||
we can obtain a list of all the elements that operate on this MIME
|
we can obtain a list of all the elements that operate on this MIME
|
||||||
|
@ -254,7 +259,49 @@ struct _GstType {
|
||||||
</note>
|
</note>
|
||||||
|
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>id to id path detection</title>
|
||||||
|
<para>
|
||||||
|
You can obtain a <classname>GList</classname> of elements that
|
||||||
|
will transform the source id into the destination id.
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
GList *list;
|
||||||
|
|
||||||
|
list = gst_type_gst_sink_to_src(sourceid, sinkid);
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
This piece of code will give you the elements needed to construct
|
||||||
|
a path from sourceid to sinkid. This function is mainly used in
|
||||||
|
autoplugging the pipeline.
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
|
<sect1>
|
||||||
|
<title>creating elements with the factory</title>
|
||||||
|
<para>
|
||||||
|
In the previous section we described how you could obtain
|
||||||
|
an element factory using MIME types. One the factory has been
|
||||||
|
obtained, you can create an element using:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
GstElementFactory *factory;
|
||||||
|
GstElement *element;
|
||||||
|
|
||||||
|
// obtain the factory
|
||||||
|
factory = ...
|
||||||
|
|
||||||
|
element = gst_elementfactory_create(factory, "name");
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
This way, you do not have to create elements by name which
|
||||||
|
allows the end-user to select the elements he/she prefers for the
|
||||||
|
given MIME types.
|
||||||
|
</para>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
<sect1>
|
<sect1>
|
||||||
<title>GStreamer basic types</title>
|
<title>GStreamer basic types</title>
|
||||||
<para>
|
<para>
|
||||||
|
|
6
docs/manual/ghostpads.sgml
Normal file
6
docs/manual/ghostpads.sgml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<chapter id="cha-ghostpads">
|
||||||
|
<title>Ghostpads</title>
|
||||||
|
<para>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</chapter>
|
|
@ -11,8 +11,20 @@
|
||||||
|
|
||||||
<!ENTITY HELLOWORLD SYSTEM "helloworld.sgml">
|
<!ENTITY HELLOWORLD SYSTEM "helloworld.sgml">
|
||||||
<!ENTITY FACTORIES SYSTEM "factories.sgml">
|
<!ENTITY FACTORIES SYSTEM "factories.sgml">
|
||||||
]>
|
<!ENTITY HELLOWORLD2 SYSTEM "helloworld2.sgml">
|
||||||
|
|
||||||
|
<!ENTITY THREADS SYSTEM "threads.sgml">
|
||||||
|
<!ENTITY QUEUES SYSTEM "queues.sgml">
|
||||||
|
<!ENTITY COTHREADS SYSTEM "cothreads.sgml">
|
||||||
|
<!ENTITY DYNAMIC SYSTEM "dynamic.sgml">
|
||||||
|
<!ENTITY GHOSTPADS SYSTEM "ghostpads.sgml">
|
||||||
|
<!ENTITY TYPEDETECTION SYSTEM "typedetection.sgml">
|
||||||
|
<!ENTITY UTILITY SYSTEM "utility.sgml">
|
||||||
|
|
||||||
|
<!ENTITY XML SYSTEM "xml.sgml">
|
||||||
|
<!ENTITY PLUGINS SYSTEM "plugins.sgml">
|
||||||
|
<!ENTITY PROGRAMS SYSTEM "programs.sgml">
|
||||||
|
]>
|
||||||
|
|
||||||
<book id="GStreamer">
|
<book id="GStreamer">
|
||||||
<bookinfo>
|
<bookinfo>
|
||||||
|
@ -110,6 +122,7 @@
|
||||||
|
|
||||||
&FACTORIES;
|
&FACTORIES;
|
||||||
|
|
||||||
|
&HELLOWORLD2;
|
||||||
</part>
|
</part>
|
||||||
|
|
||||||
<!-- ############ Advanced GStreamer - part ############# -->
|
<!-- ############ Advanced GStreamer - part ############# -->
|
||||||
|
@ -118,10 +131,27 @@
|
||||||
|
|
||||||
<partintro>
|
<partintro>
|
||||||
<para>
|
<para>
|
||||||
Wanna know more?
|
In this part we will cover the more advanced features of GStreamer.
|
||||||
|
With the basics you learned in the prevous part you should be
|
||||||
|
able to create a 'simple' pipeline. If you want more control over
|
||||||
|
the media types and the pipeline you should use the more
|
||||||
|
low-level features of GStreamer.
|
||||||
</para>
|
</para>
|
||||||
</partintro>
|
</partintro>
|
||||||
|
|
||||||
|
&THREADS;
|
||||||
|
|
||||||
|
&QUEUES;
|
||||||
|
|
||||||
|
&COTHREADS;
|
||||||
|
|
||||||
|
&DYNAMIC;
|
||||||
|
|
||||||
|
&GHOSTPADS;
|
||||||
|
|
||||||
|
&TYPEDETECTION;
|
||||||
|
|
||||||
|
&UTILITY;
|
||||||
</part>
|
</part>
|
||||||
|
|
||||||
<!-- ############ XML in GStreamer - part ############# -->
|
<!-- ############ XML in GStreamer - part ############# -->
|
||||||
|
@ -130,10 +160,13 @@
|
||||||
|
|
||||||
<partintro>
|
<partintro>
|
||||||
<para>
|
<para>
|
||||||
Just say how we use it...
|
GStreamer has the posibility to externalize the pipelines
|
||||||
|
you create using an XML format. You can load a previously
|
||||||
|
created pipeline by loading the XML file.
|
||||||
</para>
|
</para>
|
||||||
</partintro>
|
</partintro>
|
||||||
|
|
||||||
|
&XML;
|
||||||
</part>
|
</part>
|
||||||
|
|
||||||
<!-- ############ XML in GStreamer - part ############# -->
|
<!-- ############ XML in GStreamer - part ############# -->
|
||||||
|
@ -142,10 +175,12 @@
|
||||||
|
|
||||||
<partintro>
|
<partintro>
|
||||||
<para>
|
<para>
|
||||||
A lot of text will follow...
|
In this part we will describe how you create a new plugin
|
||||||
|
to be used in GStreamer.
|
||||||
</para>
|
</para>
|
||||||
</partintro>
|
</partintro>
|
||||||
|
|
||||||
|
&PLUGINS;
|
||||||
</part>
|
</part>
|
||||||
|
|
||||||
<!-- ############ Appendices - part ############# -->
|
<!-- ############ Appendices - part ############# -->
|
||||||
|
@ -155,8 +190,12 @@
|
||||||
|
|
||||||
<partintro>
|
<partintro>
|
||||||
<para>
|
<para>
|
||||||
|
GStreamer comes prepackaged with a few programs.
|
||||||
</para>
|
</para>
|
||||||
</partintro>
|
</partintro>
|
||||||
|
|
||||||
|
&PROGRAMS;
|
||||||
|
|
||||||
</part>
|
</part>
|
||||||
</book>
|
</book>
|
||||||
|
|
||||||
|
|
182
docs/manual/helloworld2.sgml
Normal file
182
docs/manual/helloworld2.sgml
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
<chapter id="cha-hello2">
|
||||||
|
<title>Your second application</title>
|
||||||
|
<para>
|
||||||
|
In the 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.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
In this chapter we will introduce you to autoplugging. Using the MIME
|
||||||
|
types of the elements GStreamer can automatically create a pipeline
|
||||||
|
for you.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<sect1>
|
||||||
|
<title>Autoplugging helloworld</title>
|
||||||
|
<para>
|
||||||
|
We will create a second version of the helloworld application using
|
||||||
|
autoplugging. Its source code is considerably more easy to write and
|
||||||
|
can also much more data types.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
|
||||||
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
static gboolean playing;
|
||||||
|
|
||||||
|
/* eos will be called when the src element has an end os stream */
|
||||||
|
void eos(GstSrc *src)
|
||||||
|
{
|
||||||
|
g_print("have eos, quitting\n");
|
||||||
|
|
||||||
|
playing = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc,char *argv[])
|
||||||
|
{
|
||||||
|
GstElement *disksrc, *audiosink;
|
||||||
|
GstPipeline *pipeline;
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
g_print("usage: %s <filename>\n", argv[0]);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_init(&argc,&argv);
|
||||||
|
gst_plugin_load_all();
|
||||||
|
g_print("\n");
|
||||||
|
|
||||||
|
/* create a new bin to hold the elements */
|
||||||
|
pipeline = gst_pipeline_new("pipeline");
|
||||||
|
|
||||||
|
/* create a disk reader */
|
||||||
|
disksrc = gst_elementfactory_make("disksrc", "disk_source");
|
||||||
|
gtk_object_set(GTK_OBJECT(disksrc),"location", argv[1],NULL);
|
||||||
|
gtk_signal_connect(GTK_OBJECT(disksrc),"eos",
|
||||||
|
GTK_SIGNAL_FUNC(eos),NULL);
|
||||||
|
|
||||||
|
/* and an audio sink */
|
||||||
|
audiosink = gst_elementfactory_make("audiosink", "play_audio");
|
||||||
|
|
||||||
|
/* add objects to the main pipeline */
|
||||||
|
gst_bin_add(GST_BIN(pipeline), disksrc);
|
||||||
|
gst_bin_add(GST_BIN(pipeline), audiosink);
|
||||||
|
|
||||||
|
if (!gst_pipeline_autoplug(pipeline)) {
|
||||||
|
g_print("unable to handle stream\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find out how to handle this bin */
|
||||||
|
gst_bin_create_plan(GST_BIN(pipeline));
|
||||||
|
|
||||||
|
/* make it ready */
|
||||||
|
gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_READY);
|
||||||
|
/* start playing */
|
||||||
|
gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_PLAYING);
|
||||||
|
|
||||||
|
playing = TRUE;
|
||||||
|
|
||||||
|
while (playing) {
|
||||||
|
gst_bin_iterate(GST_BIN(pipeline));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stop the bin */
|
||||||
|
gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_NULL);
|
||||||
|
|
||||||
|
gst_pipeline_destroy(pipeline);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
first of all, we do not use any mpg123 or mp3parse element in this example.
|
||||||
|
In fact, we only specify a source element and a sink element and add them
|
||||||
|
to a pipeline.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The most interesting change however is the following:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
|
||||||
|
...
|
||||||
|
if (!gst_pipeline_autoplug(pipeline)) {
|
||||||
|
g_print("unable to handle stream\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
...
|
||||||
|
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This piece of code does all the magic.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The source and the sink elements will be found inside the pipeline
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Since the source has no type, a typedetection will be started on
|
||||||
|
the source element.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The best set of elements that connect the MIME type of the source
|
||||||
|
element to the MIME type of the sink are found.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The elements are added to the pipeline and their pads are connected.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
After this autoplugging, the pipeline is ready to play. Remember that this
|
||||||
|
pipeline will be able to playback all of the media types for which an
|
||||||
|
appropriate plugin exists since the autoplugging is all done using MIME
|
||||||
|
types.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
I you really want, you can use the GSteamer components to do the
|
||||||
|
autoplugging yourself.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
To compile the helloworld2 example, use:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
gcc -Wall `gstreamer-config --cflags` `gtk-config --cflags` helloworld2.c \
|
||||||
|
-o helloworld2 `gstreamer-config --libs` `gtk-config --libs`
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
You can run the example with (substitute helloworld.mp3 with you favorite MP3 file):
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
./helloworld2 helloworld.mp3
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
You can also try to use an AVI or MPEG file as its input. Using autoplugging,
|
||||||
|
GStreamer will automatically figure out how to handle the stream. Remember that
|
||||||
|
only the audio part will be played because we have only added an audiosink to
|
||||||
|
the pipeline.
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
./helloworld2 helloworld.mpeg
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
</sect1>
|
||||||
|
</chapter>
|
|
@ -53,6 +53,8 @@ Building apps
|
||||||
MIME types
|
MIME types
|
||||||
GStreamer types
|
GStreamer types
|
||||||
Basic types
|
Basic types
|
||||||
|
Your second application
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
advanced concepts
|
advanced concepts
|
||||||
|
@ -61,24 +63,27 @@ advanced concepts
|
||||||
cothreads
|
cothreads
|
||||||
dynamic pipeline construction
|
dynamic pipeline construction
|
||||||
ghost pads
|
ghost pads
|
||||||
types
|
|
||||||
type detection
|
type detection
|
||||||
plugin registry
|
|
||||||
bufferpools
|
|
||||||
Quality of service
|
|
||||||
utility functions
|
utility functions
|
||||||
|
|
||||||
|
|
||||||
XML in GStreamer
|
XML in GStreamer
|
||||||
(saving)
|
(saving)
|
||||||
(loading a pipeline)
|
(loading a pipeline)
|
||||||
|
|
||||||
Plugin development
|
Plugin development
|
||||||
|
plugin types
|
||||||
|
chain based
|
||||||
|
loop based
|
||||||
buffers
|
buffers
|
||||||
metadata
|
metadata
|
||||||
subbufers
|
subbufers
|
||||||
adding pads
|
adding pads
|
||||||
libraries
|
libraries
|
||||||
|
plugin registry
|
||||||
|
types
|
||||||
|
type detection
|
||||||
|
QoS messages
|
||||||
|
clocks
|
||||||
|
|
||||||
GStreamer programs
|
GStreamer programs
|
||||||
editor
|
editor
|
||||||
|
|
6
docs/manual/plugins.sgml
Normal file
6
docs/manual/plugins.sgml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<chapter id="cha-plugins">
|
||||||
|
<title>Plugin development</title>
|
||||||
|
<para>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</chapter>
|
6
docs/manual/programs.sgml
Normal file
6
docs/manual/programs.sgml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<chapter id="cha-programs">
|
||||||
|
<title>Programs</title>
|
||||||
|
<para>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</chapter>
|
6
docs/manual/queues.sgml
Normal file
6
docs/manual/queues.sgml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<chapter id="cha-queues">
|
||||||
|
<title>Queues</title>
|
||||||
|
<para>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</chapter>
|
6
docs/manual/threads.sgml
Normal file
6
docs/manual/threads.sgml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<chapter id="cha-threads">
|
||||||
|
<title>Threads</title>
|
||||||
|
<para>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</chapter>
|
6
docs/manual/typedetection.sgml
Normal file
6
docs/manual/typedetection.sgml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<chapter id="cha-typedetection">
|
||||||
|
<title>Typedetection</title>
|
||||||
|
<para>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</chapter>
|
6
docs/manual/utility.sgml
Normal file
6
docs/manual/utility.sgml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<chapter id="cha-utility">
|
||||||
|
<title>Utility functions</title>
|
||||||
|
<para>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</chapter>
|
6
docs/manual/xml.sgml
Normal file
6
docs/manual/xml.sgml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<chapter id="cha-xml">
|
||||||
|
<title>XML in GStreamer</title>
|
||||||
|
<para>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</chapter>
|
|
@ -24,8 +24,6 @@ int main(int argc,char *argv[])
|
||||||
gst_plugin_load_all();
|
gst_plugin_load_all();
|
||||||
g_print("\n");
|
g_print("\n");
|
||||||
|
|
||||||
gst_type_dump();
|
|
||||||
|
|
||||||
/* create a new bin to hold the elements */
|
/* create a new bin to hold the elements */
|
||||||
pipeline = gst_pipeline_new("pipeline");
|
pipeline = gst_pipeline_new("pipeline");
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ static GstElementStateReturn gst_pipeline_change_state(GstElement *element);
|
||||||
static void gst_pipeline_prepare(GstPipeline *pipeline);
|
static void gst_pipeline_prepare(GstPipeline *pipeline);
|
||||||
|
|
||||||
static void gst_pipeline_have_type(GstSink *sink, GstSink *sink2, gpointer data);
|
static void gst_pipeline_have_type(GstSink *sink, GstSink *sink2, gpointer data);
|
||||||
|
static void gst_pipeline_pads_autoplug(GstElement *src, GstElement *sink);
|
||||||
|
|
||||||
static GstBin *parent_class = NULL;
|
static GstBin *parent_class = NULL;
|
||||||
//static guint gst_pipeline_signals[LAST_SIGNAL] = { 0 };
|
//static guint gst_pipeline_signals[LAST_SIGNAL] = { 0 };
|
||||||
|
@ -160,6 +161,66 @@ static guint16 gst_pipeline_typefind(GstPipeline *pipeline, GstElement *element)
|
||||||
return type_id;
|
return type_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void gst_pipeline_pads_autoplug_func(GstElement *src, GstPad *pad, GstElement *sink) {
|
||||||
|
GList *sinkpads;
|
||||||
|
GstPad *sinkpad;
|
||||||
|
|
||||||
|
g_print("gstpipeline: autoplug pad connect function type %d\n", pad->type);
|
||||||
|
|
||||||
|
sinkpads = gst_element_get_pad_list(sink);
|
||||||
|
while (sinkpads) {
|
||||||
|
sinkpad = (GstPad *)sinkpads->data;
|
||||||
|
|
||||||
|
// if we have a match, connect the pads
|
||||||
|
if (sinkpad->type == pad->type && sinkpad->direction == GST_PAD_SINK && !GST_PAD_CONNECTED(sinkpad)) {
|
||||||
|
gst_pad_connect(pad, sinkpad);
|
||||||
|
g_print("gstpipeline: autoconnect pad \"%s\" (%d) in element %s <-> ", pad->name, pad->type, gst_element_get_name(src));
|
||||||
|
g_print("pad \"%s\" (%d) in element %s\n", sinkpad->name, sinkpad->type, gst_element_get_name(sink));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sinkpads = g_list_next(sinkpads);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gst_pipeline_pads_autoplug(GstElement *src, GstElement *sink) {
|
||||||
|
GList *srcpads, *sinkpads;
|
||||||
|
gboolean connected = FALSE;
|
||||||
|
|
||||||
|
srcpads = gst_element_get_pad_list(src);
|
||||||
|
|
||||||
|
while (srcpads) {
|
||||||
|
GstPad *srcpad = (GstPad *)srcpads->data;
|
||||||
|
GstPad *sinkpad;
|
||||||
|
|
||||||
|
if (srcpad->direction == GST_PAD_SRC && !GST_PAD_CONNECTED(srcpad)) {
|
||||||
|
|
||||||
|
sinkpads = gst_element_get_pad_list(sink);
|
||||||
|
// FIXME could O(n) if the types were sorted...
|
||||||
|
while (sinkpads) {
|
||||||
|
sinkpad = (GstPad *)sinkpads->data;
|
||||||
|
|
||||||
|
// if we have a match, connect the pads
|
||||||
|
if (sinkpad->type == srcpad->type && sinkpad->direction == GST_PAD_SINK && !GST_PAD_CONNECTED(sinkpad)) {
|
||||||
|
gst_pad_connect(srcpad, sinkpad);
|
||||||
|
g_print("gstpipeline: autoconnect pad \"%s\" (%d) in element %s <-> ", srcpad->name, srcpad->type, gst_element_get_name(src));
|
||||||
|
g_print("pad \"%s\" (%d) in element %s\n", sinkpad->name, sinkpad->type, gst_element_get_name(sink));
|
||||||
|
connected = TRUE;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
sinkpads = g_list_next(sinkpads);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
srcpads = g_list_next(srcpads);
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (!connected) {
|
||||||
|
g_print("gstpipeline: delaying pad connections\n");
|
||||||
|
gtk_signal_connect(GTK_OBJECT(src),"new_pad",
|
||||||
|
GTK_SIGNAL_FUNC(gst_pipeline_pads_autoplug_func), sink);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gboolean gst_pipeline_autoplug(GstPipeline *pipeline) {
|
gboolean gst_pipeline_autoplug(GstPipeline *pipeline) {
|
||||||
GList *elements;
|
GList *elements;
|
||||||
GstElement *element, *srcelement, *sinkelement;
|
GstElement *element, *srcelement, *sinkelement;
|
||||||
|
@ -175,7 +236,7 @@ gboolean gst_pipeline_autoplug(GstPipeline *pipeline) {
|
||||||
|
|
||||||
elements = gst_bin_get_list(GST_BIN(pipeline));
|
elements = gst_bin_get_list(GST_BIN(pipeline));
|
||||||
|
|
||||||
// fase 1, find all the sinks and sources...
|
// fase 1, find all the sinks and sources... FIXME need better way to do this...
|
||||||
while (elements) {
|
while (elements) {
|
||||||
element = GST_ELEMENT(elements->data);
|
element = GST_ELEMENT(elements->data);
|
||||||
|
|
||||||
|
@ -250,10 +311,7 @@ gboolean gst_pipeline_autoplug(GstPipeline *pipeline) {
|
||||||
element = gst_elementfactory_create(factory, factory->name);
|
element = gst_elementfactory_create(factory, factory->name);
|
||||||
gst_bin_add(GST_BIN(pipeline), element);
|
gst_bin_add(GST_BIN(pipeline), element);
|
||||||
|
|
||||||
// FIXME match paths to connect with MIME types instead
|
gst_pipeline_pads_autoplug(srcelement, element);
|
||||||
// of names.
|
|
||||||
gst_pad_connect(gst_element_get_pad(srcelement,"src"),
|
|
||||||
gst_element_get_pad(element,"sink"));
|
|
||||||
|
|
||||||
srcelement = element;
|
srcelement = element;
|
||||||
|
|
||||||
|
@ -263,8 +321,7 @@ gboolean gst_pipeline_autoplug(GstPipeline *pipeline) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (complete) {
|
if (complete) {
|
||||||
gst_pad_connect(gst_element_get_pad(srcelement,"src"),
|
gst_pipeline_pads_autoplug(srcelement, sinkelement);
|
||||||
gst_element_get_pad(sinkelement,"sink"));
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,8 +339,6 @@ static GstElementStateReturn gst_pipeline_change_state(GstElement *element) {
|
||||||
switch (GST_STATE_PENDING(pipeline)) {
|
switch (GST_STATE_PENDING(pipeline)) {
|
||||||
case GST_STATE_READY:
|
case GST_STATE_READY:
|
||||||
// we need to set up internal state
|
// we need to set up internal state
|
||||||
g_print("preparing pipeline \"%s\" for iterations:\n",
|
|
||||||
gst_element_get_name(GST_ELEMENT(element)));
|
|
||||||
gst_pipeline_prepare(pipeline);
|
gst_pipeline_prepare(pipeline);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
GList *_gst_types;
|
GList *_gst_types;
|
||||||
guint16 _gst_maxtype;
|
guint16 _gst_maxtype;
|
||||||
|
|
||||||
|
#define MAX_COST 999999
|
||||||
|
|
||||||
struct _gst_type_node
|
struct _gst_type_node
|
||||||
{
|
{
|
||||||
int iNode;
|
int iNode;
|
||||||
|
@ -302,7 +304,7 @@ static GList *construct_path (gst_type_node *rgnNodes, gint chNode)
|
||||||
GstType *type;
|
GstType *type;
|
||||||
GList *converters;
|
GList *converters;
|
||||||
|
|
||||||
while (current != 999)
|
while (current != MAX_COST)
|
||||||
{
|
{
|
||||||
type = gst_type_find_by_id(current);
|
type = gst_type_find_by_id(current);
|
||||||
converters = (GList *)g_hash_table_lookup(type->converters, GUINT_TO_POINTER(src));
|
converters = (GList *)g_hash_table_lookup(type->converters, GUINT_TO_POINTER(src));
|
||||||
|
@ -322,7 +324,7 @@ static guint gst_type_find_cost(gint src, gint dest) {
|
||||||
GList *converters = (GList *)g_hash_table_lookup(type->converters, GUINT_TO_POINTER(dest));
|
GList *converters = (GList *)g_hash_table_lookup(type->converters, GUINT_TO_POINTER(dest));
|
||||||
|
|
||||||
if (converters) return 1;
|
if (converters) return 1;
|
||||||
return 999;
|
return MAX_COST;
|
||||||
}
|
}
|
||||||
|
|
||||||
GList *gst_type_get_sink_to_src(guint16 sinkid, guint16 srcid) {
|
GList *gst_type_get_sink_to_src(guint16 sinkid, guint16 srcid) {
|
||||||
|
@ -339,13 +341,13 @@ GList *gst_type_get_sink_to_src(guint16 sinkid, guint16 srcid) {
|
||||||
|
|
||||||
for (i=0; i< _gst_maxtype; i++) {
|
for (i=0; i< _gst_maxtype; i++) {
|
||||||
rgnNodes[i].iNode = i;
|
rgnNodes[i].iNode = i;
|
||||||
rgnNodes[i].iDist = 999;
|
rgnNodes[i].iDist = MAX_COST;
|
||||||
rgnNodes[i].iPrev = 999;
|
rgnNodes[i].iPrev = MAX_COST;
|
||||||
}
|
}
|
||||||
rgnNodes[sinkid].iDist = 0;
|
rgnNodes[sinkid].iDist = 0;
|
||||||
rgnNodes[sinkid].iPrev = 999;
|
rgnNodes[sinkid].iPrev = MAX_COST;
|
||||||
|
|
||||||
queue = gst_type_enqueue(queue, sinkid, 0, 999);
|
queue = gst_type_enqueue(queue, sinkid, 0, MAX_COST);
|
||||||
|
|
||||||
while (g_list_length(queue) > 0) {
|
while (g_list_length(queue) > 0) {
|
||||||
|
|
||||||
|
@ -353,8 +355,8 @@ GList *gst_type_get_sink_to_src(guint16 sinkid, guint16 srcid) {
|
||||||
|
|
||||||
for (i=0; i< _gst_maxtype; i++) {
|
for (i=0; i< _gst_maxtype; i++) {
|
||||||
iCost = gst_type_find_cost(iNode, i);
|
iCost = gst_type_find_cost(iNode, i);
|
||||||
if (iCost != 999) {
|
if (iCost != MAX_COST) {
|
||||||
if((999 == rgnNodes[i].iDist) ||
|
if((MAX_COST == rgnNodes[i].iDist) ||
|
||||||
(rgnNodes[i].iDist > (iCost + iDist))) {
|
(rgnNodes[i].iDist > (iCost + iDist))) {
|
||||||
rgnNodes[i].iDist = iDist + iCost;
|
rgnNodes[i].iDist = iDist + iCost;
|
||||||
rgnNodes[i].iPrev = iNode;
|
rgnNodes[i].iPrev = iNode;
|
||||||
|
|
|
@ -24,8 +24,6 @@ int main(int argc,char *argv[])
|
||||||
gst_plugin_load_all();
|
gst_plugin_load_all();
|
||||||
g_print("\n");
|
g_print("\n");
|
||||||
|
|
||||||
gst_type_dump();
|
|
||||||
|
|
||||||
/* create a new bin to hold the elements */
|
/* create a new bin to hold the elements */
|
||||||
pipeline = gst_pipeline_new("pipeline");
|
pipeline = gst_pipeline_new("pipeline");
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue