mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 11:41:09 +00:00
commiting wim's preliminary threaded work to a branch
Original commit message from CVS: commiting wim's preliminary threaded work to a branch
This commit is contained in:
parent
047c0a3e9b
commit
3ffce00efc
91 changed files with 7047 additions and 7866 deletions
39
ChangeLog
39
ChangeLog
|
@ -1,41 +1,7 @@
|
||||||
2004-12-08 Thomas Vander Stichele <thomas at apestaart dot org>
|
2004-12-08 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||||
|
|
||||||
* autogen.sh:
|
* commited Wim's preliminary work according to his design to
|
||||||
remove patch if autopoint fails
|
BRANCH-THREADED
|
||||||
|
|
||||||
2004-12-08 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
|
|
||||||
|
|
||||||
* docs/gst/gstreamer-sections.txt:
|
|
||||||
Document Thomas' addition, fix build, make Luis the sheriff happy.
|
|
||||||
|
|
||||||
2004-12-07 Thomas Vander Stichele <thomas at apestaart dot org>
|
|
||||||
|
|
||||||
* gst/gstplugin.c:
|
|
||||||
* gst/gstplugin.h:
|
|
||||||
add accessor for version field
|
|
||||||
|
|
||||||
2004-12-06 Thomas Vander Stichele <thomas at apestaart dot org>
|
|
||||||
|
|
||||||
submitted by: Luca Ferretti <elle.uca@infinito.it>
|
|
||||||
|
|
||||||
* po/LINGUAS:
|
|
||||||
* po/it.po:
|
|
||||||
New tranlation added: Italian
|
|
||||||
|
|
||||||
2004-12-03 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
|
|
||||||
|
|
||||||
* gst/gstpad.c: (gst_pad_is_negotiated),
|
|
||||||
(gst_pad_get_negotiated_caps):
|
|
||||||
GST_RPAD_* will only operate on a RealPad (it casts the pointer,
|
|
||||||
it doesn't actually check the contents), so be sure to hand it
|
|
||||||
a RealPad else we'll crash.
|
|
||||||
|
|
||||||
2004-12-03 Wim Taymans <wim@fluendo.com>
|
|
||||||
|
|
||||||
* gst/gstqueue.c: (gst_queue_init), (gst_queue_getcaps),
|
|
||||||
(gst_queue_link), (gst_queue_handle_src_query):
|
|
||||||
Reverted to 1.110 until this makes the testsuite and various
|
|
||||||
apps work.
|
|
||||||
|
|
||||||
2004-12-01 Christian Fredrik Kalager Schaller christian@fluendo.com
|
2004-12-01 Christian Fredrik Kalager Schaller christian@fluendo.com
|
||||||
|
|
||||||
|
@ -594,7 +560,6 @@
|
||||||
* gst/elements/gstidentity.h:
|
* gst/elements/gstidentity.h:
|
||||||
Added datarate properties to limit the datarate.
|
Added datarate properties to limit the datarate.
|
||||||
|
|
||||||
>>>>>>> 1.808
|
|
||||||
2004-08-25 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
2004-08-25 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
|
|
||||||
* gst/autoplug/gstspider.c: (plugin_init):
|
* gst/autoplug/gstspider.c: (plugin_init):
|
||||||
|
|
|
@ -8,13 +8,17 @@ SUBDIRS_DOCS =
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if BUILD_TESTS
|
if BUILD_TESTS
|
||||||
SUBDIRS_TESTS = tests testsuite
|
## SUBDIRS_TESTS = tests testsuite
|
||||||
|
## FIXME: write tests from scratch
|
||||||
|
SUBDIRS_TESTS =
|
||||||
else
|
else
|
||||||
SUBDIRS_TESTS =
|
SUBDIRS_TESTS =
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if BUILD_EXAMPLES
|
if BUILD_EXAMPLES
|
||||||
SUBDIRS_EXAMPLES = examples
|
## FIXME: write examples from scratch
|
||||||
|
# SUBDIRS_EXAMPLES = examples
|
||||||
|
SUBDIRS_EXAMPLES =
|
||||||
else
|
else
|
||||||
SUBDIRS_EXAMPLES =
|
SUBDIRS_EXAMPLES =
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -67,7 +67,7 @@ if test -f po/Makefile.in.in;
|
||||||
then
|
then
|
||||||
patch -p0 -R < common/gettext.patch
|
patch -p0 -R < common/gettext.patch
|
||||||
fi
|
fi
|
||||||
tool_run "$autopoint" "--force" "patch -p0 < common/gettext.patch"
|
tool_run "$autopoint --force"
|
||||||
patch -p0 < common/gettext.patch
|
patch -p0 < common/gettext.patch
|
||||||
|
|
||||||
# aclocal
|
# aclocal
|
||||||
|
|
|
@ -1186,7 +1186,6 @@ gst_plugin_get_license
|
||||||
gst_plugin_get_package
|
gst_plugin_get_package
|
||||||
gst_plugin_get_origin
|
gst_plugin_get_origin
|
||||||
gst_plugin_get_module
|
gst_plugin_get_module
|
||||||
gst_plugin_get_version
|
|
||||||
gst_plugin_is_loaded
|
gst_plugin_is_loaded
|
||||||
gst_plugin_feature_filter
|
gst_plugin_feature_filter
|
||||||
gst_plugin_list_feature_filter
|
gst_plugin_list_feature_filter
|
||||||
|
|
|
@ -348,10 +348,28 @@ If the refcount is 1, this function just returns the original buffer.
|
||||||
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<<<<<<< gstbuffer.sgml
|
||||||
|
@GST_BUFFER_READONLY: the buffer is read-only.
|
||||||
|
@GST_BUFFER_SUBBUFFER: the buffer is a subbuffer, the parent buffer can be
|
||||||
|
found with the GST_BUFFER_POOL_PRIVATE() macro.
|
||||||
|
@GST_BUFFER_ORIGINAL: buffer is not a copy of another buffer.
|
||||||
|
@GST_BUFFER_DONTFREE: do not try to free the data when this buffer is
|
||||||
|
unreferenced.
|
||||||
|
@GST_BUFFER_KEY_UNIT: the buffer holds a key unit, a unit that can be
|
||||||
|
decoded independently of other buffers.
|
||||||
|
@GST_BUFFER_DONTKEEP:
|
||||||
|
<<<<<<< gstbuffer.sgml
|
||||||
|
@GST_BUFFER_IN_CAPS:
|
||||||
|
=======
|
||||||
|
@GST_BUFFER_IN_CAPS: the buffer has been added as a field in a #GstCaps.
|
||||||
|
>>>>>>> 1.44
|
||||||
|
@GST_BUFFER_FLAG_LAST: additional flags can be added starting from this flag.
|
||||||
|
=======
|
||||||
@buf1:
|
@buf1:
|
||||||
@buf2:
|
@buf2:
|
||||||
@Returns:
|
@Returns:
|
||||||
|
|
||||||
|
>>>>>>> 1.48
|
||||||
|
|
||||||
<!-- ##### FUNCTION gst_buffer_default_free ##### -->
|
<!-- ##### FUNCTION gst_buffer_default_free ##### -->
|
||||||
<para>
|
<para>
|
||||||
|
|
|
@ -2,37 +2,20 @@
|
||||||
gstcontrol
|
gstcontrol
|
||||||
|
|
||||||
<!-- ##### SECTION Short_Description ##### -->
|
<!-- ##### SECTION Short_Description ##### -->
|
||||||
dynamic parameter functionality.
|
|
||||||
|
|
||||||
<!-- ##### SECTION Long_Description ##### -->
|
<!-- ##### SECTION Long_Description ##### -->
|
||||||
<para>
|
<para>
|
||||||
This library provides a Manager that maintains a list of dynamically
|
|
||||||
controlable parameters for a GstElement.
|
|
||||||
Just think of a volume slider in a mixer.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
|
||||||
To use this library one needs to add some code to initialize it.
|
|
||||||
<example>
|
|
||||||
<title>Adding the control library to a project</title>
|
|
||||||
<programlisting>
|
|
||||||
...
|
|
||||||
&hash;include <gst/gst.h>
|
|
||||||
&hash;include <gst/control/control.h>
|
|
||||||
...
|
|
||||||
gst_init(&argc,&argv);
|
|
||||||
gst_control_init(&argc,&argv);
|
|
||||||
...
|
|
||||||
</programlisting>
|
|
||||||
</example>
|
|
||||||
The next step is to get hold of the GstDParamManager instance of a GstElement.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<!-- ##### SECTION See_Also ##### -->
|
<!-- ##### SECTION See_Also ##### -->
|
||||||
<para>
|
<para>
|
||||||
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION gst_control_init ##### -->
|
<!-- ##### FUNCTION gst_control_init ##### -->
|
||||||
<para>
|
<para>
|
||||||
|
|
||||||
|
@ -124,10 +107,8 @@ The next step is to get hold of the GstDParamManager instance of a GstElement.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@dpman:
|
@dpman:
|
||||||
@dparam_name:
|
|
||||||
@Returns:
|
|
||||||
<!-- # Unused Parameters # -->
|
|
||||||
@name:
|
@name:
|
||||||
|
@Returns:
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION gst_dpman_get_dparam_type ##### -->
|
<!-- ##### FUNCTION gst_dpman_get_dparam_type ##### -->
|
||||||
|
@ -136,40 +117,10 @@ The next step is to get hold of the GstDParamManager instance of a GstElement.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@dpman:
|
@dpman:
|
||||||
@dparam_name:
|
|
||||||
@Returns:
|
|
||||||
<!-- # Unused Parameters # -->
|
|
||||||
@name:
|
@name:
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION gst_dpman_list_dparam_specs ##### -->
|
|
||||||
<para>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@dpman:
|
|
||||||
@Returns:
|
@Returns:
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION gst_dpman_get_param_spec ##### -->
|
|
||||||
<para>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@dpman:
|
|
||||||
@dparam_name:
|
|
||||||
@Returns:
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION gst_dpman_set_rate ##### -->
|
|
||||||
<para>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@dpman:
|
|
||||||
@rate:
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION gst_dpman_register_mode ##### -->
|
<!-- ##### FUNCTION gst_dpman_register_mode ##### -->
|
||||||
<para>
|
<para>
|
||||||
|
|
||||||
|
@ -259,12 +210,3 @@ The next step is to get hold of the GstDParamManager instance of a GstElement.
|
||||||
@update_info:
|
@update_info:
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION gst_dpsmooth_new ##### -->
|
|
||||||
<para>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@type:
|
|
||||||
@Returns:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,18 +2,20 @@
|
||||||
gstgetbits
|
gstgetbits
|
||||||
|
|
||||||
<!-- ##### SECTION Short_Description ##### -->
|
<!-- ##### SECTION Short_Description ##### -->
|
||||||
accelerated routines for getting bits from a data stream.
|
|
||||||
|
|
||||||
<!-- ##### SECTION Long_Description ##### -->
|
<!-- ##### SECTION Long_Description ##### -->
|
||||||
<para>
|
<para>
|
||||||
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### SECTION See_Also ##### -->
|
<!-- ##### SECTION See_Also ##### -->
|
||||||
<para>
|
<para>
|
||||||
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### STRUCT gst_getbits_t ##### -->
|
<!-- ##### STRUCT gst_getbits_t ##### -->
|
||||||
<para>
|
<para>
|
||||||
|
|
||||||
|
@ -130,8 +132,6 @@ accelerated routines for getting bits from a data stream.
|
||||||
|
|
||||||
@gb:
|
@gb:
|
||||||
@n:
|
@n:
|
||||||
<!-- # Unused Parameters # -->
|
|
||||||
@num:
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### MACRO gst_getbits1 ##### -->
|
<!-- ##### MACRO gst_getbits1 ##### -->
|
||||||
|
@ -325,8 +325,6 @@ accelerated routines for getting bits from a data stream.
|
||||||
|
|
||||||
@gb:
|
@gb:
|
||||||
@n:
|
@n:
|
||||||
<!-- # Unused Parameters # -->
|
|
||||||
@num:
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### MACRO gst_showbits1 ##### -->
|
<!-- ##### MACRO gst_showbits1 ##### -->
|
||||||
|
@ -536,8 +534,6 @@ accelerated routines for getting bits from a data stream.
|
||||||
|
|
||||||
@gb:
|
@gb:
|
||||||
@n:
|
@n:
|
||||||
<!-- # Unused Parameters # -->
|
|
||||||
@num:
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### MACRO gst_flushbits32 ##### -->
|
<!-- ##### MACRO gst_flushbits32 ##### -->
|
||||||
|
@ -555,8 +551,6 @@ accelerated routines for getting bits from a data stream.
|
||||||
|
|
||||||
@gb:
|
@gb:
|
||||||
@n:
|
@n:
|
||||||
<!-- # Unused Parameters # -->
|
|
||||||
@num:
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### MACRO gst_backbits24 ##### -->
|
<!-- ##### MACRO gst_backbits24 ##### -->
|
||||||
|
|
257
docs/manual/advanced-autoplugging.xml
Normal file
257
docs/manual/advanced-autoplugging.xml
Normal file
|
@ -0,0 +1,257 @@
|
||||||
|
<chapter id="chapter-factories">
|
||||||
|
<title>More on factories</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 to create elements based
|
||||||
|
on what they do instead of what they are called.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
We will first explain the concepts involved before we move on
|
||||||
|
to the reworked helloworld example using autoplugging.
|
||||||
|
</para>
|
||||||
|
<sect1 id="section-factories-helloworld-problems">
|
||||||
|
<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 */
|
||||||
|
decoder = gst_element_factory_make ("mad", "decoder");
|
||||||
|
...
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
While this mechanism is quite effective it also has some big problems:
|
||||||
|
The elements are created based on their name. Indeed, we create an
|
||||||
|
element, mad, by explicitly stating the mad element's name. Our little
|
||||||
|
program therefore always uses the mad decoder element to decode
|
||||||
|
the MP3 audio stream, even if there are three 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 and capabilities
|
||||||
|
added to the source and sink pads.
|
||||||
|
</para>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="section-factories-mime">
|
||||||
|
<title>More on MIME Types</title>
|
||||||
|
<para>
|
||||||
|
GStreamer uses MIME types to identify 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) type is a pair of
|
||||||
|
strings that denote a certain type of data. Examples include:
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
audio/x-raw-int : 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>
|
||||||
|
As we have seen in the previous chapter, MIME types are added
|
||||||
|
to the Capability structure of a pad.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<xref linkend="section-mime-img"/> shows the MIME types associated with
|
||||||
|
each pad from the "hello world" example.
|
||||||
|
</para>
|
||||||
|
<figure float="1" id="section-mime-img">
|
||||||
|
<title>The Hello world pipeline with MIME types</title>
|
||||||
|
<mediaobject>
|
||||||
|
<imageobject>
|
||||||
|
<imagedata fileref="images/mime-world.ℑ" format="&IMAGE;" />
|
||||||
|
</imageobject>
|
||||||
|
</mediaobject>
|
||||||
|
|
||||||
|
</figure>
|
||||||
|
<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
|
||||||
|
a pipeline that does an audio/mpeg to audio/x-raw-int 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 id="section-factories-gstreamer-types">
|
||||||
|
<title>GStreamer types</title>
|
||||||
|
<para>
|
||||||
|
GStreamer assigns a unique number to all registered MIME types.
|
||||||
|
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,
|
||||||
|
but the use of typefind functions (similar to file(1)) is preferred.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The type information is maintained in a list of
|
||||||
|
<classname>GstType</classname>. The definition of a
|
||||||
|
<classname>GstType</classname> is like:
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<programlisting>
|
||||||
|
typedef GstCaps (*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 */
|
||||||
|
};
|
||||||
|
</programlisting>
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
All operations on <classname>GstType</classname> occur
|
||||||
|
via their <classname>guint16 id</classname> numbers, with
|
||||||
|
the <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 not 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>
|
||||||
|
<para>
|
||||||
|
For more information, see <xref linkend="chapter-autoplug"/>.
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="section-factories-create">
|
||||||
|
<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_element_factory_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 id="section-factories-basic-types">
|
||||||
|
<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>
|
5
docs/manual/advanced-clocks.xml
Normal file
5
docs/manual/advanced-clocks.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<chapter id="chapter-clocks">
|
||||||
|
<title>Clocks in GStreamer</title>
|
||||||
|
<para>
|
||||||
|
</para>
|
||||||
|
</chapter>
|
198
docs/manual/advanced-dparams.xml
Normal file
198
docs/manual/advanced-dparams.xml
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
<chapter id="chapter-dparams">
|
||||||
|
<title>Dynamic Parameters</title>
|
||||||
|
|
||||||
|
<sect1 id="section-dparams-getting-started">
|
||||||
|
<title>Getting Started</title>
|
||||||
|
<para>
|
||||||
|
The Dynamic Parameters subsystem is contained within the
|
||||||
|
<filename>gstcontrol</filename> library.
|
||||||
|
|
||||||
|
You need to include the header in your application's source file:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
...
|
||||||
|
#include <gst/gst.h>
|
||||||
|
#include <gst/control/control.h>
|
||||||
|
...
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
Your application should link to the shared library <filename>gstcontrol</filename>.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The <filename>gstcontrol</filename> library needs to be initialized
|
||||||
|
when your application is run. This can be done after the the GStreamer
|
||||||
|
library has been initialized.
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
...
|
||||||
|
gst_init(&argc,&argv);
|
||||||
|
gst_control_init(&argc,&argv);
|
||||||
|
...
|
||||||
|
</programlisting>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="section-dparams-creating">
|
||||||
|
<title>Creating and Attaching Dynamic Parameters</title>
|
||||||
|
<para>
|
||||||
|
Once you have created your elements you can create and attach dparams to them.
|
||||||
|
First you need to get the element's dparams manager. If you know exactly what kind of element
|
||||||
|
you have, you may be able to get the dparams manager directly. However if this is not possible,
|
||||||
|
you can get the dparams manager by calling <filename>gst_dpman_get_manager</filename>.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Once you have the dparams manager, you must set the mode that the manager will run in.
|
||||||
|
There is currently only one mode implemented called <filename>"synchronous"</filename> - this is used for real-time
|
||||||
|
applications where the dparam value cannot be known ahead of time (such as a slider in a GUI).
|
||||||
|
The mode is called <filename>"synchronous"</filename> because the dparams are polled by the element for changes before
|
||||||
|
each buffer is processed. Another yet-to-be-implemented mode is <filename>"asynchronous"</filename>. This is used when
|
||||||
|
parameter changes are known ahead of time - such as with a timelined editor. The mode is called
|
||||||
|
<filename>"asynchronous"</filename> because parameter changes may happen in the middle of a buffer being processed.
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
GstElement *sinesrc;
|
||||||
|
GstDParamManager *dpman;
|
||||||
|
...
|
||||||
|
sinesrc = gst_element_factory_make("sinesrc","sine-source");
|
||||||
|
...
|
||||||
|
dpman = gst_dpman_get_manager (sinesrc);
|
||||||
|
gst_dpman_set_mode(dpman, "synchronous");
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
If you don't know the names of the required dparams for your element you can call
|
||||||
|
<filename>gst_dpman_list_dparam_specs(dpman)</filename> to get a NULL terminated array of param specs.
|
||||||
|
This array should be freed after use. You can find the name of the required dparam by calling
|
||||||
|
<filename>g_param_spec_get_name</filename> on each param spec in the array. In our example,
|
||||||
|
<filename>"volume"</filename> will be the name of our required dparam.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Each type of dparam currently has its own <filename>new</filename> function. This may eventually
|
||||||
|
be replaced by a factory method for creating new instances. A default dparam instance can be created
|
||||||
|
with the <filename>gst_dparam_new</filename> function. Once it is created it can be attached to a
|
||||||
|
required dparam in the element.
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
GstDParam *volume;
|
||||||
|
...
|
||||||
|
volume = gst_dparam_new(G_TYPE_DOUBLE);
|
||||||
|
if (gst_dpman_attach_dparam (dpman, "volume", volume)){
|
||||||
|
/* the dparam was successfully attached */
|
||||||
|
...
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="section-dparams-changing">
|
||||||
|
<title>Changing Dynamic Parameter Values</title>
|
||||||
|
<para>
|
||||||
|
All interaction with dparams to actually set the dparam value is done through simple GObject properties.
|
||||||
|
There is a property value for each type that dparams supports - these currently being
|
||||||
|
<filename>"value_double"</filename>, <filename>"value_float"</filename>, <filename>"value_int"</filename> and <filename>"value_int64"</filename>.
|
||||||
|
To set the value of a dparam, simply set the property which matches the type of your dparam instance.
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
#define ZERO(mem) memset(&mem, 0, sizeof(mem))
|
||||||
|
...
|
||||||
|
|
||||||
|
gdouble set_to_value;
|
||||||
|
GstDParam *volume;
|
||||||
|
GValue set_val;
|
||||||
|
ZERO(set_val);
|
||||||
|
g_value_init(&set_val, G_TYPE_DOUBLE);
|
||||||
|
...
|
||||||
|
g_value_set_double(&set_val, set_to_value);
|
||||||
|
g_object_set_property(G_OBJECT(volume), "value_double", &set_val);
|
||||||
|
</programlisting>
|
||||||
|
<para>Or if you create an actual GValue instance:</para>
|
||||||
|
<programlisting>
|
||||||
|
gdouble set_to_value;
|
||||||
|
GstDParam *volume;
|
||||||
|
GValue *set_val;
|
||||||
|
set_val = g_new0(GValue,1);
|
||||||
|
g_value_init(set_val, G_TYPE_DOUBLE);
|
||||||
|
...
|
||||||
|
g_value_set_double(set_val, set_to_value);
|
||||||
|
g_object_set_property(G_OBJECT(volume), "value_double", set_val);
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="section-dparams-types">
|
||||||
|
<title>Different Types of Dynamic Parameter</title>
|
||||||
|
<para>
|
||||||
|
There are currently only two implementations of dparams so far. They are both for real-time use so
|
||||||
|
should be run in the <filename>"synchronous"</filename> mode.
|
||||||
|
</para>
|
||||||
|
<sect2>
|
||||||
|
<title>GstDParam - the base dparam type</title>
|
||||||
|
<para>
|
||||||
|
All dparam implementations will subclass from this type. It provides a basic implementation which simply
|
||||||
|
propagates any value changes as soon as it can.
|
||||||
|
A new instance can be created with the function <filename>GstDParam* gst_dparam_new (GType type)</filename>.
|
||||||
|
It has the following object properties:
|
||||||
|
</para>
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para><filename>"value_double"</filename>
|
||||||
|
- the property to set and get if it is a double dparam
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><filename>"value_float"</filename>
|
||||||
|
- the property to set and get if it is a float dparam
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><filename>"value_int"</filename>
|
||||||
|
- the property to set and get if it is an integer dparam
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><filename>"value_int64"</filename>
|
||||||
|
- the property to set and get if it is a 64 bit integer dparam
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><filename>"is_log"</filename>
|
||||||
|
- readonly boolean which is TRUE if the param should be displayed on a log scale
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><filename>"is_rate"</filename>
|
||||||
|
- readonly boolean which is TRUE if the value is a proportion of the sample rate.
|
||||||
|
For example with a sample rate of 44100, 0.5 would be 22050 Hz and 0.25 would be 11025 Hz.
|
||||||
|
</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</sect2>
|
||||||
|
<sect2>
|
||||||
|
<title>GstDParamSmooth - smoothing real-time dparam</title>
|
||||||
|
<para>
|
||||||
|
Some parameter changes can create audible artifacts if they change too rapidly. The GstDParamSmooth
|
||||||
|
implementation can greatly reduce these artifacts by limiting the rate at which the value can change.
|
||||||
|
This is currently only supported for double and float dparams - the other types fall back to the default implementation.
|
||||||
|
A new instance can be created with the function <filename>GstDParam* gst_dpsmooth_new (GType type)</filename>.
|
||||||
|
It has the following object properties:
|
||||||
|
</para>
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para><filename>"update_period"</filename>
|
||||||
|
- an int64 value specifying the number nanoseconds between updates. This will be ignored in
|
||||||
|
<filename>"synchronous"</filename> mode since the buffer size dictates the update period.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><filename>"slope_time"</filename>
|
||||||
|
- an int64 value specifying the time period to use in the maximum slope calculation
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><filename>"slope_delta_double"</filename>
|
||||||
|
- a double specifying the amount a double value can change in the given slope_time.
|
||||||
|
</para></listitem>
|
||||||
|
<listitem><para><filename>"slope_delta_float"</filename>
|
||||||
|
- a float specifying the amount a float value can change in the given slope_time.
|
||||||
|
</para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
<para>
|
||||||
|
Audible artifacts may not be completely eliminated by using this dparam. The only way to eliminate
|
||||||
|
artifacts such as "zipper noise" would be for the element to implement its required dparams using the
|
||||||
|
array method. This would allow dparams to change parameters at the sample rate which should eliminate
|
||||||
|
any artifacts.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</sect2>
|
||||||
|
<sect2>
|
||||||
|
<title>Timelined dparams</title>
|
||||||
|
<para>
|
||||||
|
A yet-to-be-implemented subclass of GstDParam will add an API which allows the creation and manipulation
|
||||||
|
of points on a timeline. This subclass will also provide a dparam implementation which uses linear
|
||||||
|
interpolation between these points to find the dparam value at any given time. Further subclasses can
|
||||||
|
extend this functionality to implement more exotic interpolation algorithms such as splines.
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
</chapter>
|
168
docs/manual/advanced-threads.xml
Normal file
168
docs/manual/advanced-threads.xml
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
<chapter id="chapter-threads">
|
||||||
|
<title>Threads</title>
|
||||||
|
<para>
|
||||||
|
GStreamer has support for multithreading through the use of
|
||||||
|
the <ulink type="http" url="../../gstreamer/html/GstThread.html"><classname>
|
||||||
|
GstThread</classname></ulink> object. This object is in fact
|
||||||
|
a special <ulink type="http" url="../../gstreamer/html/GstBin.html"><classname>
|
||||||
|
GstBin</classname></ulink> that will become a thread when started.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
To construct a new thread you will perform something like:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<programlisting>
|
||||||
|
GstElement *my_thread;
|
||||||
|
|
||||||
|
/* create the thread object */
|
||||||
|
my_thread = gst_thread_new ("my_thread");
|
||||||
|
/* you could have used gst_element_factory_make ("thread", "my_thread"); */
|
||||||
|
g_return_if_fail (my_thread != NULL);
|
||||||
|
|
||||||
|
/* add some plugins */
|
||||||
|
gst_bin_add (GST_BIN (my_thread), GST_ELEMENT (funky_src));
|
||||||
|
gst_bin_add (GST_BIN (my_thread), GST_ELEMENT (cool_effect));
|
||||||
|
|
||||||
|
/* link the elements here... */
|
||||||
|
...
|
||||||
|
|
||||||
|
/* start playing */
|
||||||
|
gst_element_set_state (GST_ELEMENT (my_thread), GST_STATE_PLAYING);
|
||||||
|
|
||||||
|
</programlisting>
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The above program will create a thread with two elements in it. As soon
|
||||||
|
as it is set to the PLAYING state, the thread will start to iterate
|
||||||
|
itself. You never need to explicitly iterate a thread.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<sect1 id="section-threads-constraints">
|
||||||
|
<title>Constraints placed on the pipeline by the GstThread</title>
|
||||||
|
<para>
|
||||||
|
Within the pipeline, everything is the same as in any other bin. The
|
||||||
|
difference lies at the thread boundary, at the link between the
|
||||||
|
thread and the outside world (containing bin). Since GStreamer is
|
||||||
|
fundamentally buffer-oriented rather than byte-oriented, the natural
|
||||||
|
solution to this problem is an element that can "buffer" the buffers
|
||||||
|
between the threads, in a thread-safe fashion. This element is the
|
||||||
|
queue, described more fully in <xref linkend="chapter-queues"/>. It doesn't
|
||||||
|
matter if the queue is placed in the containing bin or in the thread
|
||||||
|
itself, but it needs to be present on one side or the other to enable
|
||||||
|
inter-thread communication.
|
||||||
|
</para>
|
||||||
|
</sect1>
|
||||||
|
<sect1 id="section-threads-when">
|
||||||
|
<title>When would you want to use a thread?</title>
|
||||||
|
<para>
|
||||||
|
If you are writing a GUI application, making the top-level bin a thread will make your GUI
|
||||||
|
more responsive. If it were a pipeline instead, it would have to be iterated by your
|
||||||
|
application's event loop, which increases the latency between events (say, keyboard presses)
|
||||||
|
and responses from the GUI. In addition, any slight hang in the GUI would delay iteration of
|
||||||
|
the pipeline, which (for example) could cause pops in the output of the sound card, if it is
|
||||||
|
an audio pipeline.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<xref linkend="section-threads-img"/> shows how a thread can be visualised.
|
||||||
|
</para>
|
||||||
|
<figure float="1" id="section-threads-img">
|
||||||
|
<title>A thread</title>
|
||||||
|
<mediaobject>
|
||||||
|
<imageobject>
|
||||||
|
<imagedata fileref="images/thread.ℑ" format="&IMAGE;" />
|
||||||
|
</imageobject>
|
||||||
|
</mediaobject>
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
As an example we show the helloworld program using a thread.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<programlisting>
|
||||||
|
/* example-begin threads.c */
|
||||||
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
/* we set this to TRUE right before gst_main (), but there could still
|
||||||
|
be a race condition between setting it and entering the function */
|
||||||
|
gboolean can_quit = FALSE;
|
||||||
|
|
||||||
|
/* eos will be called when the src element has an end of stream */
|
||||||
|
void
|
||||||
|
eos (GstElement *src, gpointer data)
|
||||||
|
{
|
||||||
|
GstThread *thread = GST_THREAD (data);
|
||||||
|
g_print ("have eos, quitting\n");
|
||||||
|
|
||||||
|
/* stop the bin */
|
||||||
|
gst_element_set_state (GST_ELEMENT (thread), GST_STATE_NULL);
|
||||||
|
|
||||||
|
while (!can_quit) /* waste cycles */ ;
|
||||||
|
gst_main_quit ();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
GstElement *filesrc, *demuxer, *decoder, *converter, *audiosink;
|
||||||
|
GstElement *thread;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
g_print ("usage: %s <Ogg/Vorbis filename>\n", argv[0]);
|
||||||
|
exit (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_init (&argc, &argv);
|
||||||
|
|
||||||
|
/* create a new thread to hold the elements */
|
||||||
|
thread = gst_thread_new ("thread");
|
||||||
|
g_assert (thread != 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);
|
||||||
|
g_signal_connect (G_OBJECT (filesrc), "eos",
|
||||||
|
G_CALLBACK (eos), thread);
|
||||||
|
|
||||||
|
/* create an ogg demuxer */
|
||||||
|
demuxer = gst_element_factory_make ("oggdemux", "demuxer");
|
||||||
|
g_assert (demuxer != NULL);
|
||||||
|
|
||||||
|
/* create a vorbis decoder */
|
||||||
|
decoder = gst_element_factory_make ("vorbisdec", "decoder");
|
||||||
|
g_assert (decoder != NULL);
|
||||||
|
|
||||||
|
/* create an audio converter */
|
||||||
|
converter = gst_element_factory_make ("audioconvert", "converter");
|
||||||
|
g_assert (decoder != NULL);
|
||||||
|
|
||||||
|
/* and an audio sink */
|
||||||
|
audiosink = gst_element_factory_make ("osssink", "play_audio");
|
||||||
|
g_assert (audiosink != NULL);
|
||||||
|
|
||||||
|
/* add objects to the thread */
|
||||||
|
gst_bin_add_many (GST_BIN (thread), filesrc, demuxer, decoder, converter, audiosink, NULL);
|
||||||
|
/* link them in the logical order */
|
||||||
|
gst_element_link_many (filesrc, demuxer, decoder, converter, audiosink, NULL);
|
||||||
|
|
||||||
|
/* start playing */
|
||||||
|
gst_element_set_state (thread, GST_STATE_PLAYING);
|
||||||
|
|
||||||
|
/* do whatever you want here, the thread will be playing */
|
||||||
|
g_print ("thread is playing\n");
|
||||||
|
|
||||||
|
can_quit = TRUE;
|
||||||
|
gst_main ();
|
||||||
|
|
||||||
|
gst_object_unref (GST_OBJECT (thread));
|
||||||
|
|
||||||
|
exit (0);
|
||||||
|
}
|
||||||
|
/* example-end threads.c */
|
||||||
|
</programlisting>
|
||||||
|
</para>
|
||||||
|
</sect1>
|
||||||
|
</chapter>
|
253
docs/manual/appendix-quotes.xml
Normal file
253
docs/manual/appendix-quotes.xml
Normal file
|
@ -0,0 +1,253 @@
|
||||||
|
<chapter id="chapter-quotes">
|
||||||
|
<title>Quotes from the Developers</title>
|
||||||
|
<para>
|
||||||
|
As well as being a cool piece of software,
|
||||||
|
<application>GStreamer</application> is a lively project, with
|
||||||
|
developers from around the globe very actively contributing.
|
||||||
|
We often hang out on the #gstreamer IRC channel on
|
||||||
|
irc.freenode.net: the following are a selection of amusing<footnote>
|
||||||
|
<para>No guarantee of sense of humour compatibility is given.</para>
|
||||||
|
</footnote> quotes from our conversations.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<variablelist>
|
||||||
|
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>2 Nov 2004</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<emphasis>zaheerm</emphasis>:
|
||||||
|
wtay: unfair u fixed the bug i was using as a feature!
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>14 Oct 2004</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<emphasis>* zaheerm</emphasis>
|
||||||
|
wonders how he can break gstreamer today :)
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>ensonic</emphasis>:
|
||||||
|
zaheerm, spider is always a good starting point
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>14 Jun 2004</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<emphasis>teuf</emphasis>: ok, things work much better when I don't write incredibly stupid and buggy code
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>thaytan</emphasis>: I find that too
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>23 Nov 2003</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<emphasis>Uraeus</emphasis>: ah yes, the sleeping part, my mind
|
||||||
|
is not multitasking so I was still thinking about exercise
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>dolphy</emphasis>: Uraeus: your mind is multitasking
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>dolphy</emphasis>: Uraeus: you just miss low latency patches
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>14 Sep 2002</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
--- <emphasis>wingo-party</emphasis> is now known as
|
||||||
|
<emphasis>wingo</emphasis>
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
* <emphasis>wingo</emphasis> holds head
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>16 Feb 2001</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<emphasis>wtay:</emphasis>
|
||||||
|
I shipped a few commerical products to >40000 people now but
|
||||||
|
GStreamer is way more exciting...
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>16 Feb 2001</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
*
|
||||||
|
<emphasis>tool-man</emphasis>
|
||||||
|
is a gstreamer groupie
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>14 Jan 2001</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<emphasis>Omega:</emphasis>
|
||||||
|
did you run ldconfig? maybe it talks to init?
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>wtay:</emphasis>
|
||||||
|
not sure, don't think so...
|
||||||
|
I did run gstreamer-register though :-)
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>Omega:</emphasis>
|
||||||
|
ah, that did it then ;-)
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>wtay:</emphasis>
|
||||||
|
right
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>Omega:</emphasis>
|
||||||
|
probably not, but in case GStreamer starts turning into an OS, someone please let me know?
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>9 Jan 2001</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<emphasis>wtay:</emphasis>
|
||||||
|
me tar, you rpm?
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>wtay:</emphasis>
|
||||||
|
hehe, forgot "zan"
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>Omega:</emphasis>
|
||||||
|
?
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>wtay:</emphasis>
|
||||||
|
me tar"zan", you ...
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>7 Jan 2001</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<emphasis>Omega:</emphasis>
|
||||||
|
that means probably building an agreggating, cache-massaging
|
||||||
|
queue to shove N buffers across all at once, forcing cache
|
||||||
|
transfer.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>wtay:</emphasis>
|
||||||
|
never done that before...
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>Omega:</emphasis>
|
||||||
|
nope, but it's easy to do in gstreamer <g>
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>wtay:</emphasis>
|
||||||
|
sure, I need to rewrite cp with gstreamer too, someday :-)
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>7 Jan 2001</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<emphasis>wtay:</emphasis>
|
||||||
|
GStreamer; always at least one developer is awake...
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>5/6 Jan 2001</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<emphasis>wtay:</emphasis>
|
||||||
|
we need to cut down the time to create an mp3 player down to
|
||||||
|
seconds...
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>richardb:</emphasis>
|
||||||
|
:)
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>Omega:</emphasis>
|
||||||
|
I'm wanting to something more interesting soon, I did the "draw an mp3
|
||||||
|
player in 15sec" back in October '99.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>wtay:</emphasis>
|
||||||
|
by the time Omega gets his hands on the editor, you'll see a
|
||||||
|
complete audio mixer in the editor :-)
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>richardb:</emphasis>
|
||||||
|
Well, it clearly has the potential...
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>Omega:</emphasis>
|
||||||
|
Working on it... ;-)
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>28 Dec 2000</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<emphasis>MPAA:</emphasis>
|
||||||
|
We will sue you now, you have violated our IP rights!
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>wtay:</emphasis>
|
||||||
|
hehehe
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>MPAA:</emphasis>
|
||||||
|
How dare you laugh at us? We have lawyers! We have Congressmen! We have <emphasis>LARS</emphasis>!
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>wtay:</emphasis>
|
||||||
|
I'm so sorry your honor
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<emphasis>MPAA:</emphasis>
|
||||||
|
Hrumph.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
*
|
||||||
|
<emphasis>wtay</emphasis>
|
||||||
|
bows before thy
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>4 Jun 2001</term>
|
||||||
|
<listitem>
|
||||||
|
<para><emphasis>taaz:</emphasis> you witchdoctors and your voodoo mpeg2 black magic... </para>
|
||||||
|
<para><emphasis>omega_:</emphasis> um. I count three, no four different cults there <g> </para>
|
||||||
|
<para><emphasis>ajmitch:</emphasis> hehe </para>
|
||||||
|
<para><emphasis>omega_:</emphasis> witchdoctors, voodoo, black magic, </para>
|
||||||
|
<para><emphasis>omega_:</emphasis> and mpeg </para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
</chapter>
|
49
docs/manual/basics-bins.xml
Normal file
49
docs/manual/basics-bins.xml
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<chapter id="chapter-bins">
|
||||||
|
<title>Bins</title>
|
||||||
|
<para>
|
||||||
|
A bin is a container element. You can add elements to a bin. Since a bin is
|
||||||
|
an element itself, it can also be added to another bin.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Bins allow you to combine a group of linked elements into one logical element. You do
|
||||||
|
not deal with the individual elements anymore but with just one element, the bin.
|
||||||
|
We will see that this is extremely powerful when you are going to construct
|
||||||
|
complex pipelines since it allows you to break up the pipeline in smaller chunks.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The bin will also manage the elements contained in it. It will figure out how
|
||||||
|
the data will flow in the bin and generate an optimal plan for that data flow. Plan
|
||||||
|
generation is one of the most complicated procedures in GStreamer.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<figure float="1" id="section-bin-img">
|
||||||
|
<title>Visualisation of a bin with some elements in it</title>
|
||||||
|
<mediaobject>
|
||||||
|
<imageobject>
|
||||||
|
<imagedata fileref="images/bin-element.ℑ" format="&IMAGE;" />
|
||||||
|
</imageobject>
|
||||||
|
</mediaobject>
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
There are two specialized bins available to the GStreamer programmer:
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
a pipeline: a generic container that allows scheduling of the
|
||||||
|
containing elements. The toplevel bin has to be a pipeline.
|
||||||
|
Every application thus needs at least one of these.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
a thread: a bin that will be run in a separate execution thread.
|
||||||
|
You will have to use this bin if you have to carefully
|
||||||
|
synchronize audio and video, or for buffering. You will learn
|
||||||
|
more about threads in <xref linkend="chapter-threads"/>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
</chapter>
|
66
docs/manual/basics-data.xml
Normal file
66
docs/manual/basics-data.xml
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
<chapter id="chapter-buffers">
|
||||||
|
<title>Buffers</title>
|
||||||
|
<para>
|
||||||
|
Buffers contain the data that will flow through the pipeline you have
|
||||||
|
created. A source element will typically create a new buffer and pass
|
||||||
|
it through a pad to the next element in the chain. When using the
|
||||||
|
GStreamer infrastructure to create a media pipeline you will not have
|
||||||
|
to deal with buffers yourself; the elements will do that for you.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
A buffer consists of:
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
a pointer to a piece of memory.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
the size of the memory.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
a timestamp for the buffer.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
A refcount that indicates how many elements are using this
|
||||||
|
buffer. This refcount will be used to destroy the buffer when no
|
||||||
|
element has a reference to it.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<!-- FIXME: this is outdated, there is no GstBufferPool in gst-0.8.X -->
|
||||||
|
GStreamer provides functions to create custom buffer create/destroy algorithms, called
|
||||||
|
a <classname>GstBufferPool</classname>. This makes it possible to efficiently
|
||||||
|
allocate and destroy buffer memory. It also makes it possible to exchange memory between
|
||||||
|
elements by passing the <classname>GstBufferPool</classname>. A video element can,
|
||||||
|
for example, create a custom buffer allocation algorithm that creates buffers with XSHM
|
||||||
|
as the buffer memory. An element can use this algorithm to create and fill the buffer
|
||||||
|
with data.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The simple case is that a buffer is created, memory allocated, data put
|
||||||
|
in it, and passed to the next element. That element reads the data, does
|
||||||
|
something (like creating a new buffer and decoding into it), and
|
||||||
|
unreferences the buffer. This causes the data to be freed and the buffer
|
||||||
|
to be destroyed. A typical MPEG audio decoder works like this.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
A more complex case is when the filter modifies the data in place. It
|
||||||
|
does so and simply passes on the buffer to the next element. This is just
|
||||||
|
as easy to deal with. An element that works in place has to be careful when
|
||||||
|
the buffer is used in more than one element; a copy on write has to made in this
|
||||||
|
situation.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</chapter>
|
122
docs/manual/basics-elements.xml
Normal file
122
docs/manual/basics-elements.xml
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
<chapter id="chapter-elements">
|
||||||
|
<title>Elements</title>
|
||||||
|
<para>
|
||||||
|
The most important object in <application>GStreamer</application> for the
|
||||||
|
application programmer is the <ulink type="http"
|
||||||
|
url="../../gstreamer/html/GstElement.html"><classname>GstElement</classname>
|
||||||
|
</ulink>object.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<sect1 id="section-elements-design">
|
||||||
|
<title>What is an element ?</title>
|
||||||
|
<para>
|
||||||
|
An element is the basic building block for the media pipeline.
|
||||||
|
All the different high-level components you are going to use are
|
||||||
|
derived from <ulink type="http" url="../../gstreamer/html/GstElement.html">
|
||||||
|
<classname>GstElement</classname></ulink>. This means that a
|
||||||
|
lot of functions you are going to use operate on objects of this class.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Elements, from the perspective of GStreamer, are viewed as "black boxes"
|
||||||
|
with a number of different aspects. One of these aspects is the presence
|
||||||
|
of "pads" (see <xref linkend="chapter-pads"/>), or link points.
|
||||||
|
This terminology arises from soldering; pads are where wires can be
|
||||||
|
attached.
|
||||||
|
</para>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="section-elements-types">
|
||||||
|
<title>Types of elements</title>
|
||||||
|
|
||||||
|
<sect2 id="section-elements-src">
|
||||||
|
<title>Source elements</title>
|
||||||
|
<para>
|
||||||
|
Source elements generate data for use by a pipeline, for example
|
||||||
|
reading from disk or from a sound card.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
<xref linkend="section-element-srcimg"/> shows how we will visualise
|
||||||
|
a source element.
|
||||||
|
We always draw a source pad to the right of the element.
|
||||||
|
</para>
|
||||||
|
<figure float="1" id="section-element-srcimg">
|
||||||
|
<title>Visualisation of a source element</title>
|
||||||
|
<mediaobject>
|
||||||
|
<imageobject>
|
||||||
|
<imagedata fileref="images/src-element.ℑ" format="&IMAGE;" />
|
||||||
|
</imageobject>
|
||||||
|
</mediaobject>
|
||||||
|
</figure>
|
||||||
|
<para>
|
||||||
|
Source elements do not accept data, they only generate data. You can
|
||||||
|
see this in the figure because it only has a source pad. A source
|
||||||
|
pad can only generate data.
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2 id="section-elements-filter">
|
||||||
|
<title>Filters and codecs</title>
|
||||||
|
<para>
|
||||||
|
Filter elements have both input and output pads. They operate on
|
||||||
|
data they receive in their sink pads and produce data on their source
|
||||||
|
pads. For example, MPEG decoders and volume filters would fall into
|
||||||
|
this category.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Elements are not constrained as to the number of pads they might have;
|
||||||
|
for example, a video mixer might have two input pads (the images of
|
||||||
|
the two different video streams) and one output pad.
|
||||||
|
</para>
|
||||||
|
<figure float="1" id="section-element-filterimg">
|
||||||
|
<title>Visualisation of a filter element</title>
|
||||||
|
<mediaobject>
|
||||||
|
<imageobject>
|
||||||
|
<imagedata fileref="images/filter-element.ℑ" format="&IMAGE;" />
|
||||||
|
</imageobject>
|
||||||
|
</mediaobject>
|
||||||
|
</figure>
|
||||||
|
<para>
|
||||||
|
<xref linkend="section-element-filterimg"/> shows how we will visualise
|
||||||
|
a filter element.
|
||||||
|
This element has one sink (input) pad and one source (output) pad.
|
||||||
|
Sink pads are drawn on the left of the element.
|
||||||
|
</para>
|
||||||
|
<figure float="1" id="section-element-multifilterimg">
|
||||||
|
<title>Visualisation of a filter element with
|
||||||
|
more than one output pad</title>
|
||||||
|
<mediaobject>
|
||||||
|
<imageobject>
|
||||||
|
<imagedata fileref="images/filter-element-multi.ℑ"
|
||||||
|
format="&IMAGE;" />
|
||||||
|
</imageobject>
|
||||||
|
</mediaobject>
|
||||||
|
</figure>
|
||||||
|
<para>
|
||||||
|
<xref linkend="section-element-multifilterimg"/> shows the visualisation of a filter element with
|
||||||
|
more than one output pad. An example of such a filter is the AVI
|
||||||
|
demultiplexer. This element will parse the input data and
|
||||||
|
extract the audio and video data. Most of these filters dynamically
|
||||||
|
send out a signal when a new pad is created so that the application
|
||||||
|
programmer can link an arbitrary element to the newly created pad.
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2 id="section-elements-sink">
|
||||||
|
<title>Sink elements</title>
|
||||||
|
<para>
|
||||||
|
Sink elements are end points in a media pipeline. They accept
|
||||||
|
data but do not produce anything. Disk writing, soundcard playback,
|
||||||
|
and video output would all be implemented by sink elements.
|
||||||
|
<xref linkend="section-element-sinkimg"/> shows a sink element.
|
||||||
|
</para>
|
||||||
|
<figure float="1" id="section-element-sinkimg">
|
||||||
|
<title>Visualisation of a sink element</title>
|
||||||
|
<mediaobject>
|
||||||
|
<imageobject>
|
||||||
|
<imagedata fileref="images/sink-element.ℑ" format="&IMAGE;" />
|
||||||
|
</imageobject>
|
||||||
|
</mediaobject>
|
||||||
|
</figure>
|
||||||
|
</sect2>
|
||||||
|
</sect1>
|
||||||
|
</chapter>
|
280
docs/manual/basics-helloworld.xml
Normal file
280
docs/manual/basics-helloworld.xml
Normal file
|
@ -0,0 +1,280 @@
|
||||||
|
<chapter id="chapter-hello-world">
|
||||||
|
<title>Your first application</title>
|
||||||
|
<para>
|
||||||
|
This chapter describes the most rudimentary aspects of a
|
||||||
|
<application>GStreamer</application> application, including initializing
|
||||||
|
the libraries, creating elements, packing them into a pipeline and playing,
|
||||||
|
pausing and stopping the pipeline.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<sect1 id="section-hello-world">
|
||||||
|
<title>Hello world</title>
|
||||||
|
<para>
|
||||||
|
We will create a simple first application, a complete MP3 player, using
|
||||||
|
standard <application>GStreamer</application> components. The player
|
||||||
|
will read from a file that is given as the first argument to the program.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
/* example-begin helloworld.c */
|
||||||
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
GstElement *pipeline, *filesrc, *decoder, *audiosink;
|
||||||
|
|
||||||
|
gst_init(&argc, &argv);
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
g_print ("usage: %s <mp3 filename>\n", argv[0]);
|
||||||
|
exit (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create a new pipeline to hold the elements */
|
||||||
|
pipeline = gst_pipeline_new ("pipeline");
|
||||||
|
|
||||||
|
/* create a disk reader */
|
||||||
|
filesrc = gst_element_factory_make ("filesrc", "disk_source");
|
||||||
|
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
|
||||||
|
|
||||||
|
/* now it's time to get the decoder */
|
||||||
|
decoder = gst_element_factory_make ("mad", "decoder");
|
||||||
|
|
||||||
|
/* and an audio sink */
|
||||||
|
audiosink = gst_element_factory_make ("osssink", "play_audio");
|
||||||
|
|
||||||
|
/* add objects to the main pipeline */
|
||||||
|
gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, audiosink, NULL);
|
||||||
|
|
||||||
|
/* link src to sink */
|
||||||
|
gst_element_link_many (filesrc, decoder, audiosink, NULL);
|
||||||
|
|
||||||
|
/* start playing */
|
||||||
|
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||||
|
|
||||||
|
while (gst_bin_iterate (GST_BIN (pipeline)));
|
||||||
|
|
||||||
|
/* stop the pipeline */
|
||||||
|
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||||
|
|
||||||
|
/* we don't need a reference to these objects anymore */
|
||||||
|
gst_object_unref (GST_OBJECT (pipeline));
|
||||||
|
/* unreffing the pipeline unrefs the contained elements as well */
|
||||||
|
|
||||||
|
exit (0);
|
||||||
|
}
|
||||||
|
/* example-end helloworld.c */
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Let's go through this example step by step.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The first thing you have to do is to include the standard
|
||||||
|
<application>GStreamer</application> headers and
|
||||||
|
initialize the framework.
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
|
||||||
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
...
|
||||||
|
gst_init(&argc, &argv);
|
||||||
|
...
|
||||||
|
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
We are going to create three elements and one pipeline. Since all
|
||||||
|
elements share the same base type, <ulink type="http"
|
||||||
|
url="../../gstreamer/html/GstElement.html"><classname>GstElement</classname></ulink>,
|
||||||
|
we can define them as:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
...
|
||||||
|
GstElement *pipeline, *filesrc, *decoder, *audiosink;
|
||||||
|
...
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Next, we are going to create an empty pipeline. As you have seen in
|
||||||
|
the basic introduction, this pipeline will hold and manage all the
|
||||||
|
elements we are going to pack into it.
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
/* create a new pipeline to hold the elements */
|
||||||
|
pipeline = gst_pipeline_new ("pipeline");
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
We use the standard constructor for a pipeline: gst_pipeline_new ().
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
We then create a disk source element. The disk source element is able to
|
||||||
|
read from a file. We use the standard GObject property mechanism to set
|
||||||
|
a property of the element: the file to read from.
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
/* create a disk reader */
|
||||||
|
filesrc = gst_element_factory_make ("filesrc", "disk_source");
|
||||||
|
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
|
||||||
|
</programlisting>
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
You can check if the filesrc != NULL to verify the creation of the
|
||||||
|
disk source element.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
We now create the MP3 decoder element. This assumes that the 'mad' plugin
|
||||||
|
is installed on the system where this application is executed.
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
/* now it's time to get the decoder */
|
||||||
|
decoder = gst_element_factory_make ("mad", "decoder");
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
gst_element_factory_make() takes two arguments: a string that will
|
||||||
|
identify the element you need and a second argument: how you want
|
||||||
|
to name the element. The name of the element is something you can
|
||||||
|
choose yourself and might be used to retrieve the element from a
|
||||||
|
bin/pipeline.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Finally we create our audio sink element. This element will be able
|
||||||
|
to play back the audio using OSS.
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
/* and an audio sink */
|
||||||
|
audiosink = gst_element_factory_make ("osssink", "play_audio");
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
We then add the elements to the pipeline.
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
/* add objects to the main pipeline */
|
||||||
|
gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, audiosink, NULL);
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
We link the different pads of the elements together like this:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
/* link src to sink */
|
||||||
|
gst_element_link_many (filesrc, decoder, audiosink, NULL);
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
We now have created a complete pipeline. We can visualise the
|
||||||
|
pipeline as follows:
|
||||||
|
</para>
|
||||||
|
<figure float="1" id="section-hello-img">
|
||||||
|
<title>The "hello world" pipeline</title>
|
||||||
|
<mediaobject>
|
||||||
|
<imageobject>
|
||||||
|
<imagedata fileref="images/hello-world.ℑ" format="&IMAGE;" />
|
||||||
|
</imageobject>
|
||||||
|
</mediaobject>
|
||||||
|
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Everything is now set up to start streaming. We use the following
|
||||||
|
statements to change the state of the pipeline:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
/* start playing */
|
||||||
|
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||||
|
|
||||||
|
</programlisting>
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
<application>GStreamer</application> will take care of the READY and PAUSED state for
|
||||||
|
you when going from NULL to PLAYING.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Since we do not use threads, nothing will happen yet. We have to
|
||||||
|
call gst_bin_iterate() to execute one iteration of the pipeline.
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
while (gst_bin_iterate (GST_BIN (pipeline)));
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
The gst_bin_iterate() function will return TRUE as long as something
|
||||||
|
interesting happened inside the pipeline. When the end-of-file has been
|
||||||
|
reached the _iterate function will return FALSE and we can end the loop.
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
/* stop the pipeline */
|
||||||
|
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||||
|
|
||||||
|
gst_object_unref (GST_OBJECT (pipeline));
|
||||||
|
|
||||||
|
exit (0);
|
||||||
|
</programlisting>
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
Don't forget to set the state of the pipeline to NULL. This will free
|
||||||
|
all of the resources held by the elements.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="section-hello-world-compile">
|
||||||
|
<title>Compiling helloworld.c</title>
|
||||||
|
<para>
|
||||||
|
To compile the helloworld example, use:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
gcc -Wall `pkg-config gstreamer-&GST_MAJORMINOR; --cflags --libs` helloworld.c \
|
||||||
|
-o helloworld
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
We use pkg-config to get the compiler flags needed to compile
|
||||||
|
this application. Make sure to have your PKG_CONFIG_PATH environment
|
||||||
|
variable set to the correct location if you are building this
|
||||||
|
application against the uninstalled location.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
You can run the example with
|
||||||
|
(substitute helloworld.mp3 with you favorite MP3 file):
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
./helloworld helloworld.mp3
|
||||||
|
</programlisting>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="section-hello-world-conclusion">
|
||||||
|
<title>Conclusion</title>
|
||||||
|
<para>
|
||||||
|
This concludes our first example. As you see, setting up a pipeline
|
||||||
|
is very low-level but powerful. You will see later in this manual how
|
||||||
|
you can create a custom MP3 element with a higher-level API.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
It should be clear from the example that we can very easily replace the
|
||||||
|
filesrc element with the gnomevfssrc element, giving you instant streaming
|
||||||
|
from any gnomevfs URL.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
We can also choose to use another type of sink instead of the audiosink.
|
||||||
|
We could use a filesink to write the raw samples to a file, for example.
|
||||||
|
It should also be clear that inserting filters, like a stereo effect,
|
||||||
|
into the pipeline is not that hard to do. The most important thing is
|
||||||
|
that you can reuse already existing elements.
|
||||||
|
</para>
|
||||||
|
</sect1>
|
||||||
|
</chapter>
|
99
docs/manual/basics-init.xml
Normal file
99
docs/manual/basics-init.xml
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
<chapter id="chapter-initialisation">
|
||||||
|
<title>Initializing <application>GStreamer</application></title>
|
||||||
|
<para>
|
||||||
|
When writing a <application>GStreamer</application> application, you can
|
||||||
|
simply include <filename class='headerfile'>gst/gst.h</filename> to get
|
||||||
|
access to the library functions.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Before the <application>GStreamer</application> libraries can be used,
|
||||||
|
<function>gst_init</function> has to be called from the main application.
|
||||||
|
This call will perform the necessary initialization of the library as
|
||||||
|
well as parse the GStreamer-specific command line options.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
A typical program
|
||||||
|
&EXAFOOT;
|
||||||
|
would have code to initialize GStreamer that
|
||||||
|
looks like this:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
<![CDATA[
|
||||||
|
/* example-begin init.c */
|
||||||
|
|
||||||
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
guint major, minor, micro;
|
||||||
|
|
||||||
|
gst_init (&argc, &argv);
|
||||||
|
|
||||||
|
gst_version (&major, &minor, &micro);
|
||||||
|
printf ("This program is linked against GStreamer %d.%d.%d\n",
|
||||||
|
major, minor, micro);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* example-end init.c */
|
||||||
|
]]>
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
Use the <symbol>GST_VERSION_MAJOR</symbol>,
|
||||||
|
<symbol>GST_VERSION_MINOR</symbol> and <symbol>GST_VERSION_MICRO</symbol>
|
||||||
|
macros to get the <application>GStreamer</application> version you are
|
||||||
|
building against, or use the function <function>gst_version</function>
|
||||||
|
to get the version your application is linked against.
|
||||||
|
<!-- FIXME: include an automatically generated list of these options. -->
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
It is also possible to call the <function>gst_init</function> function
|
||||||
|
with two <symbol>NULL</symbol> arguments, in which case no command line
|
||||||
|
options will be parsed by <application>GStreamer</application>.
|
||||||
|
</para>
|
||||||
|
<sect1>
|
||||||
|
<title>The popt interface</title>
|
||||||
|
<para>
|
||||||
|
You can also use a popt table to initialize your own parameters as shown in the
|
||||||
|
next example:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
/* example-begin popt.c */
|
||||||
|
|
||||||
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
gboolean silent = FALSE;
|
||||||
|
gchar *savefile = NULL;
|
||||||
|
struct poptOption options[] = {
|
||||||
|
{"silent", 's', POPT_ARG_NONE|POPT_ARGFLAG_STRIP, &silent, 0,
|
||||||
|
"do not output status information", NULL},
|
||||||
|
{"output", 'o', POPT_ARG_STRING|POPT_ARGFLAG_STRIP, &savefile, 0,
|
||||||
|
"save xml representation of pipeline to FILE and exit", "FILE"},
|
||||||
|
POPT_TABLEEND
|
||||||
|
};
|
||||||
|
|
||||||
|
gst_init_with_popt_table (&argc, &argv, options);
|
||||||
|
|
||||||
|
printf ("Run me with --help to see the Application options appended.\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* example-end popt.c */
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
As shown in this fragment, you can use a <ulink
|
||||||
|
url="http://developer.gnome.org/doc/guides/popt/"
|
||||||
|
type="http">popt</ulink> table to define your application-specific
|
||||||
|
command line options, and pass this table to the
|
||||||
|
function <function>gst_init_with_popt_table</function>. Your
|
||||||
|
application options will be parsed in addition to the standard
|
||||||
|
<application>GStreamer</application> options.
|
||||||
|
</para>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
</chapter>
|
244
docs/manual/basics-pads.xml
Normal file
244
docs/manual/basics-pads.xml
Normal file
|
@ -0,0 +1,244 @@
|
||||||
|
<chapter id="chapter-pads">
|
||||||
|
<title>Pads</title>
|
||||||
|
<para>
|
||||||
|
As we have seen in <xref linkend="chapter-elements"/>, the pads are the element's
|
||||||
|
interface to the outside world.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The specific type of media that the element can handle will be exposed by the pads.
|
||||||
|
The description of this media type is done with capabilities(see
|
||||||
|
<xref linkend="section-caps"/>)
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Pads are either source or sink pads. The terminology is defined from the
|
||||||
|
view of the element itself: elements accept data on their sink pads, and
|
||||||
|
send data out on their source pads. Sink pads are drawn on the left,
|
||||||
|
while source pads are drawn on the right of an element. In general,
|
||||||
|
data flows from left to right in the graph.<footnote>
|
||||||
|
<para>
|
||||||
|
In reality, there is no objection to data flowing from a
|
||||||
|
source pad to the sink pad of an element upstream. Data will, however,
|
||||||
|
always flow from a source pad of one element to the sink pad of
|
||||||
|
another.
|
||||||
|
</para></footnote>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<sect1 id="section-pads-type">
|
||||||
|
<title>Types of pad</title>
|
||||||
|
|
||||||
|
<sect2 id="section-pads-dynamic">
|
||||||
|
<title>Dynamic pads</title>
|
||||||
|
<para>
|
||||||
|
Some elements might not have all of their pads when the element is
|
||||||
|
created. This
|
||||||
|
can happen, for example, with an MPEG system demultiplexer. The
|
||||||
|
demultiplexer will create its pads at runtime when it detects the
|
||||||
|
different elementary streams in the MPEG system stream.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Running <application>gst-inspect mpegdemux</application> will show that
|
||||||
|
the element has only one pad: a sink pad called 'sink'. The other pads are
|
||||||
|
"dormant". You can see this in the pad template because there is
|
||||||
|
an 'Exists: Sometimes'
|
||||||
|
property. Depending on the type of MPEG file you play, the pads will
|
||||||
|
be created. We
|
||||||
|
will see that this is very important when you are going to create dynamic
|
||||||
|
pipelines later on in this manual.
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
|
<sect2 id="section-pads-request">
|
||||||
|
<title>Request pads</title>
|
||||||
|
<para>
|
||||||
|
An element can also have request pads. These pads are not created
|
||||||
|
automatically but are only created on demand. This is very useful
|
||||||
|
for multiplexers, aggregators and tee elements.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The tee element, for example, has one input pad and a request padtemplate for the
|
||||||
|
output pads. Whenever an element wants to get an output pad from the tee element, it
|
||||||
|
has to request the pad.
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="section-caps">
|
||||||
|
<title>Capabilities of a pad</title>
|
||||||
|
<para>
|
||||||
|
Since the pads play a very important role in how the element is viewed by the
|
||||||
|
outside world, a mechanism is implemented to describe the data that can
|
||||||
|
flow through the pad by using capabilities.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
We will briefly describe what capabilities are, enough for you to get a basic understanding
|
||||||
|
of the concepts. You will find more information on how to create capabilities in the
|
||||||
|
Plugin Writer's Guide.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<sect2 id="section-pads-caps">
|
||||||
|
<title>Capabilities</title>
|
||||||
|
<para>
|
||||||
|
Capabilities are attached to a pad in order to describe
|
||||||
|
what type of media the pad can handle.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Capabilities is shorthand for "capability chain". A capability chain
|
||||||
|
is a chain of one capability or more.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The basic entity is a capability, and is defined by a name, a MIME
|
||||||
|
type and a set of properties. A capability can be chained to
|
||||||
|
another capability, which is why we commonly refer to a chain of
|
||||||
|
capability entities as "capabilities".
|
||||||
|
<footnote>
|
||||||
|
<para>
|
||||||
|
It is important to understand that the term "capabilities" refers
|
||||||
|
to a chain of one capability or more. This will be clearer when
|
||||||
|
you see the structure definition of a <ulink type="http"
|
||||||
|
url="../../gstreamer/html/gstreamer-GstCaps.html"><classname>GstCaps
|
||||||
|
</classname></ulink>element.
|
||||||
|
</para>
|
||||||
|
</footnote>
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Below is a dump of the capabilities of the element mad, as shown by
|
||||||
|
<command>gst-inspect</command>.
|
||||||
|
You can see two pads: sink and src. Both pads have capability information attached to them.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The sink pad (input pad) is called 'sink' and takes data of MIME type 'audio/mp3'. It also has
|
||||||
|
three properties: layer, bitrate and framed.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The source pad (output pad) is called 'src' and outputs data of
|
||||||
|
MIME type 'audio/raw'. It also has four properties: format, depth,
|
||||||
|
rate and channels.
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
Pads:
|
||||||
|
SINK template: 'sink'
|
||||||
|
Availability: Always
|
||||||
|
Capabilities:
|
||||||
|
'mad_sink':
|
||||||
|
MIME type: 'audio/mp3':
|
||||||
|
|
||||||
|
SRC template: 'src'
|
||||||
|
Availability: Always
|
||||||
|
Capabilities:
|
||||||
|
'mad_src':
|
||||||
|
MIME type: 'audio/raw':
|
||||||
|
format: String: int
|
||||||
|
endianness: Integer: 1234
|
||||||
|
width: Integer: 16
|
||||||
|
depth: Integer: 16
|
||||||
|
channels: Integer range: 1 - 2
|
||||||
|
law: Integer: 0
|
||||||
|
signed: Boolean: TRUE
|
||||||
|
rate: Integer range: 11025 - 48000
|
||||||
|
</programlisting>
|
||||||
|
</sect2>
|
||||||
|
<sect2 id="section-pads-props">
|
||||||
|
<title>What are properties ?</title>
|
||||||
|
<para>
|
||||||
|
Properties are used to describe extra information for
|
||||||
|
capabilities. A property consists of a key (a string) and
|
||||||
|
a value. There are different possible value types that can be used:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
basic types:
|
||||||
|
</para>
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
an integer value: the property has this exact value.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
a boolean value: the property is either TRUE or FALSE.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
a fourcc value: this is a value that is commonly used to
|
||||||
|
describe an encoding for video,
|
||||||
|
as used for example by the AVI specification.
|
||||||
|
<footnote><para>
|
||||||
|
fourcc values consist of four bytes.
|
||||||
|
<ulink url="http://www.fourcc.org" type="http">The FOURCC
|
||||||
|
Definition List</ulink> is the most complete resource
|
||||||
|
on the allowed fourcc values.
|
||||||
|
</para></footnote>
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
a float value: the property has this exact floating point value.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
a string value.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
range types:
|
||||||
|
</para>
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
an integer range value: the property denotes a range of
|
||||||
|
possible integers. For example, the wavparse element has
|
||||||
|
a source pad where the "rate" property can go from 8000 to
|
||||||
|
48000.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
a float range value: the property denotes a range of possible
|
||||||
|
floating point values.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
a list value: the property can take any value from a list of
|
||||||
|
basic value types or range types.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
|
||||||
|
</sect2>
|
||||||
|
<sect2 id="section-pads-caps-use">
|
||||||
|
<title>What capabilities are used for</title>
|
||||||
|
<para>
|
||||||
|
Capabilities describe in great detail the type of media that is handled by the pads.
|
||||||
|
They are mostly used for:
|
||||||
|
</para>
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Autoplugging: automatically finding plugins for a set of capabilities
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Compatibility detection: when two pads are linked, <application>GStreamer</application>
|
||||||
|
can verify if the two pads are talking about the same media types.
|
||||||
|
The process of linking two pads and checking if they are compatible
|
||||||
|
is called "caps negotiation".
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</sect2>
|
||||||
|
</sect1>
|
||||||
|
</chapter>
|
31
docs/manual/basics-plugins.xml
Normal file
31
docs/manual/basics-plugins.xml
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<chapter id="chapter-plugins">
|
||||||
|
<title>Plugins</title>
|
||||||
|
<!-- FIXME: introduce type definitions before this chapter -->
|
||||||
|
<para>
|
||||||
|
A plugin is a shared library that contains at least one of the following
|
||||||
|
items:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
one or more element factories
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
one or more type definitions
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
one or more auto-pluggers
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
exported symbols for use in other plugins
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</chapter>
|
37
docs/manual/highlevel-components.xml
Normal file
37
docs/manual/highlevel-components.xml
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<chapter id="chapter-components">
|
||||||
|
<title>Components</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
FIXME: This chapter is way out of date.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<application>GStreamer</application> includes components that people can include
|
||||||
|
in their programs.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<sect1 id="section-components-gst-play">
|
||||||
|
<title>GstPlay</title>
|
||||||
|
<para>
|
||||||
|
GstPlay is a GtkWidget with a simple API to play, pause and stop a media file.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="section-components-gst-media-play">
|
||||||
|
<title>GstMediaPlay</title>
|
||||||
|
<para>
|
||||||
|
GstMediaPlay is a complete player widget.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="section-components-gst-editor">
|
||||||
|
<title>GstEditor</title>
|
||||||
|
<para>
|
||||||
|
GstEditor is a set of widgets to display a graphical representation of a
|
||||||
|
pipeline.
|
||||||
|
</para>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
</chapter>
|
283
docs/manual/highlevel-xml.xml
Normal file
283
docs/manual/highlevel-xml.xml
Normal file
|
@ -0,0 +1,283 @@
|
||||||
|
<chapter id="chapter-xml">
|
||||||
|
<title>XML in <application>GStreamer</application></title>
|
||||||
|
<para>
|
||||||
|
<application>GStreamer</application> uses XML to store and load
|
||||||
|
its pipeline definitions. XML is also used internally to manage the
|
||||||
|
plugin registry. The plugin registry is a file that contains the definition
|
||||||
|
of all the plugins <application>GStreamer</application> knows about to have
|
||||||
|
quick access to the specifics of the plugins.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
We will show you how you can save a pipeline to XML and how you can reload that
|
||||||
|
XML file again for later use.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<sect1 id="section-xml-write">
|
||||||
|
<title>Turning GstElements into XML</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
We create a simple pipeline and write it to stdout with
|
||||||
|
gst_xml_write_file (). The following code constructs an MP3 player
|
||||||
|
pipeline with two threads and then writes out the XML both to stdout
|
||||||
|
and to a file. Use this program with one argument: the MP3 file on disk.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
/* example-begin xml-mp3.c */
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
gboolean playing;
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
GstElement *filesrc, *osssink, *queue, *queue2, *decode;
|
||||||
|
GstElement *bin;
|
||||||
|
GstElement *thread, *thread2;
|
||||||
|
|
||||||
|
gst_init (&argc,&argv);
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
g_print ("usage: %s <mp3 filename>\n", argv[0]);
|
||||||
|
exit (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create a new thread to hold the elements */
|
||||||
|
thread = gst_element_factory_make ("thread", "thread");
|
||||||
|
g_assert (thread != NULL);
|
||||||
|
thread2 = gst_element_factory_make ("thread", "thread2");
|
||||||
|
g_assert (thread2 != NULL);
|
||||||
|
|
||||||
|
/* create a new bin to hold the elements */
|
||||||
|
bin = gst_bin_new ("bin");
|
||||||
|
g_assert (bin != 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);
|
||||||
|
|
||||||
|
queue = gst_element_factory_make ("queue", "queue");
|
||||||
|
queue2 = gst_element_factory_make ("queue", "queue2");
|
||||||
|
|
||||||
|
/* and an audio sink */
|
||||||
|
osssink = gst_element_factory_make ("osssink", "play_audio");
|
||||||
|
g_assert (osssink != NULL);
|
||||||
|
|
||||||
|
decode = gst_element_factory_make ("mad", "decode");
|
||||||
|
g_assert (decode != NULL);
|
||||||
|
|
||||||
|
/* add objects to the main bin */
|
||||||
|
gst_bin_add_many (GST_BIN (bin), filesrc, queue, NULL);
|
||||||
|
|
||||||
|
gst_bin_add_many (GST_BIN (thread), decode, queue2, NULL);
|
||||||
|
|
||||||
|
gst_bin_add (GST_BIN (thread2), osssink);
|
||||||
|
|
||||||
|
gst_element_link_many (filesrc, queue, decode, queue2, osssink, NULL);
|
||||||
|
|
||||||
|
gst_bin_add_many (GST_BIN (bin), thread, thread2, NULL);
|
||||||
|
|
||||||
|
/* write the bin to stdout */
|
||||||
|
gst_xml_write_file (GST_ELEMENT (bin), stdout);
|
||||||
|
|
||||||
|
/* write the bin to a file */
|
||||||
|
gst_xml_write_file (GST_ELEMENT (bin), fopen ("xmlTest.gst", "w"));
|
||||||
|
|
||||||
|
exit (0);
|
||||||
|
}
|
||||||
|
/* example-end xml-mp3.c */
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
The most important line is:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
gst_xml_write_file (GST_ELEMENT (bin), stdout);
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
gst_xml_write_file () will turn the given element into an xmlDocPtr that
|
||||||
|
is then formatted and saved to a file. To save to disk, pass the result
|
||||||
|
of a fopen(2) as the second argument.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The complete element hierarchy will be saved along with the inter element
|
||||||
|
pad links and the element parameters. Future <application>GStreamer</application>
|
||||||
|
versions will also allow you to store the signals in the XML file.
|
||||||
|
</para>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="section-xml-load">
|
||||||
|
<title>Loading a GstElement from an XML file</title>
|
||||||
|
<para>
|
||||||
|
Before an XML file can be loaded, you must create a GstXML object.
|
||||||
|
A saved XML file can then be loaded with the
|
||||||
|
gst_xml_parse_file (xml, filename, rootelement) method.
|
||||||
|
The root element can optionally left NULL. The following code example loads
|
||||||
|
the previously created XML file and runs it.
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
GstXML *xml;
|
||||||
|
GstElement *bin;
|
||||||
|
gboolean ret;
|
||||||
|
|
||||||
|
gst_init (&argc, &argv);
|
||||||
|
|
||||||
|
xml = gst_xml_new ();
|
||||||
|
|
||||||
|
ret = gst_xml_parse_file(xml, "xmlTest.gst", NULL);
|
||||||
|
g_assert (ret == TRUE);
|
||||||
|
|
||||||
|
bin = gst_xml_get_element (xml, "bin");
|
||||||
|
g_assert (bin != NULL);
|
||||||
|
|
||||||
|
gst_element_set_state (bin, GST_STATE_PLAYING);
|
||||||
|
|
||||||
|
while (gst_bin_iterate(GST_BIN(bin)));
|
||||||
|
|
||||||
|
gst_element_set_state (bin, GST_STATE_NULL);
|
||||||
|
|
||||||
|
exit (0);
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
gst_xml_get_element (xml, "name") can be used to get a specific element
|
||||||
|
from the XML file.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
gst_xml_get_topelements (xml) can be used to get a list of all toplevel elements
|
||||||
|
in the XML file.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
In addition to loading a file, you can also load a from a xmlDocPtr and
|
||||||
|
an in memory buffer using gst_xml_parse_doc and gst_xml_parse_memory
|
||||||
|
respectively. Both of these methods return a gboolean indicating
|
||||||
|
success or failure of the requested action.
|
||||||
|
</para>
|
||||||
|
</sect1>
|
||||||
|
<sect1 id="section-xml-custom">
|
||||||
|
<title>Adding custom XML tags into the core XML data</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
It is possible to add custom XML tags to the core XML created with
|
||||||
|
gst_xml_write. This feature can be used by an application to add more
|
||||||
|
information to the save plugins. The editor will for example insert
|
||||||
|
the position of the elements on the screen using the custom XML tags.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
It is strongly suggested to save and load the custom XML tags using
|
||||||
|
a namespace. This will solve the problem of having your XML tags
|
||||||
|
interfere with the core XML tags.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
To insert a hook into the element saving procedure you can link
|
||||||
|
a signal to the GstElement using the following piece of code:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
xmlNsPtr ns;
|
||||||
|
|
||||||
|
...
|
||||||
|
ns = xmlNewNs (NULL, "http://gstreamer.net/gst-test/1.0/", "test");
|
||||||
|
...
|
||||||
|
thread = gst_element_factory_make ("thread", "thread");
|
||||||
|
g_signal_connect (G_OBJECT (thread), "object_saved",
|
||||||
|
G_CALLBACK (object_saved), g_strdup ("decoder thread"));
|
||||||
|
...
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
When the thread is saved, the object_save method will be called. Our example
|
||||||
|
will insert a comment tag:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
static void
|
||||||
|
object_saved (GstObject *object, xmlNodePtr parent, gpointer data)
|
||||||
|
{
|
||||||
|
xmlNodePtr child;
|
||||||
|
|
||||||
|
child = xmlNewChild (parent, ns, "comment", NULL);
|
||||||
|
xmlNewChild (child, ns, "text", (gchar *)data);
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
Adding the custom tag code to the above example you will get an XML file
|
||||||
|
with the custom tags in it. Here's an excerpt:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
...
|
||||||
|
<gst:element>
|
||||||
|
<gst:name>thread</gst:name>
|
||||||
|
<gst:type>thread</gst:type>
|
||||||
|
<gst:version>0.1.0</gst:version>
|
||||||
|
...
|
||||||
|
</gst:children>
|
||||||
|
<test:comment>
|
||||||
|
<test:text>decoder thread</test:text>
|
||||||
|
</test:comment>
|
||||||
|
</gst:element>
|
||||||
|
...
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
To retrieve the custom XML again, you need to attach a signal to
|
||||||
|
the GstXML object used to load the XML data. You can then parse your
|
||||||
|
custom XML from the XML tree whenever an object is loaded.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
We can extend our previous example with the following piece of
|
||||||
|
code.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
xml = gst_xml_new ();
|
||||||
|
|
||||||
|
g_signal_connect (G_OBJECT (xml), "object_loaded",
|
||||||
|
G_CALLBACK (xml_loaded), xml);
|
||||||
|
|
||||||
|
ret = gst_xml_parse_file (xml, "xmlTest.gst", NULL);
|
||||||
|
g_assert (ret == TRUE);
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Whenever a new object has been loaded, the xml_loaded function will
|
||||||
|
be called. This function looks like:
|
||||||
|
</para>
|
||||||
|
<programlisting>
|
||||||
|
static void
|
||||||
|
xml_loaded (GstXML *xml, GstObject *object, xmlNodePtr self, gpointer data)
|
||||||
|
{
|
||||||
|
xmlNodePtr children = self->xmlChildrenNode;
|
||||||
|
|
||||||
|
while (children) {
|
||||||
|
if (!strcmp (children->name, "comment")) {
|
||||||
|
xmlNodePtr nodes = children->xmlChildrenNode;
|
||||||
|
|
||||||
|
while (nodes) {
|
||||||
|
if (!strcmp (nodes->name, "text")) {
|
||||||
|
gchar *name = g_strdup (xmlNodeGetContent (nodes));
|
||||||
|
g_print ("object %s loaded with comment '%s'\n",
|
||||||
|
gst_object_get_name (object), name);
|
||||||
|
}
|
||||||
|
nodes = nodes->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
children = children->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
<para>
|
||||||
|
As you can see, you'll get a handle to the GstXML object, the
|
||||||
|
newly loaded GstObject and the xmlNodePtr that was used to create
|
||||||
|
this object. In the above example we look for our special tag inside
|
||||||
|
the XML tree that was used to load the object and we print our
|
||||||
|
comment to the console.
|
||||||
|
</para>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
|
</chapter>
|
111
docs/manual/intro-motivation.xml
Normal file
111
docs/manual/intro-motivation.xml
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
<chapter id="chapter-motivation">
|
||||||
|
<title>Motivation</title>
|
||||||
|
<para>
|
||||||
|
Linux has historically lagged behind other operating systems in the multimedia
|
||||||
|
arena. Microsoft's <trademark>Windows</trademark> and Apple's <trademark>MacOS</trademark> both have strong support
|
||||||
|
for multimedia devices, multimedia content creation,
|
||||||
|
playback, and realtime processing. Linux, on the other hand, has a poorly integrated
|
||||||
|
collection of multimedia utilities and applications available, which can hardly compete
|
||||||
|
with the professional level of software available for MS Windows and MacOS.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<sect1 id="section-motivation-problems">
|
||||||
|
<title>Current problems</title>
|
||||||
|
<para>
|
||||||
|
We describe the typical problems in today's media handling on Linux.
|
||||||
|
</para>
|
||||||
|
<sect2 id="section-motivation-duplicate">
|
||||||
|
<title>Multitude of duplicate code</title>
|
||||||
|
<para>
|
||||||
|
The Linux user who wishes to hear a sound file must hunt through their collection of
|
||||||
|
sound file players in order to play the tens of sound file formats in wide use today.
|
||||||
|
Most of these players basically reimplement the same code over and over again.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The Linux developer who wishes to embed a video clip in their application must use
|
||||||
|
crude hacks to run an external video player. There is no library available that a
|
||||||
|
developer can use to create a custom media player.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</sect2>
|
||||||
|
<sect2 id="section-motivation-goal">
|
||||||
|
<title>'One goal' media players/libraries</title>
|
||||||
|
<para>
|
||||||
|
Your typical MPEG player was designed to play MPEG video and audio. Most of
|
||||||
|
these players have implemented a complete infrastructure focused on
|
||||||
|
achieving their only goal: playback. No provisions were made to add
|
||||||
|
filters or special effects to the video or audio data.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
If you want to convert an MPEG2 video stream into an AVI file, your best
|
||||||
|
option would be to take all of the MPEG2 decoding algorithms out
|
||||||
|
of the player and duplicate them into your own AVI encoder. These
|
||||||
|
algorithms cannot easily be shared across applications.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Attempts have been made to create libraries for handling various media types.
|
||||||
|
Because they focus on a very specific media type (avifile, libmpeg2, ...),
|
||||||
|
significant work is needed to integrate them due to a lack of a common API.
|
||||||
|
GStreamer allows you to wrap these libraries with a common API, which
|
||||||
|
significantly simplifies integration and reuse.
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2 id="section-motivation-plugin">
|
||||||
|
<title>Non unified plugin mechanisms</title>
|
||||||
|
<para>
|
||||||
|
Your typical media player might have a plugin for different media
|
||||||
|
types. Two media players will typically implement their own plugin
|
||||||
|
mechanism so that the codecs cannot be easily exchanged. The plugin system
|
||||||
|
of the typical media player is also very tailored to the specific needs
|
||||||
|
of the application.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The lack of a unified plugin mechanism also seriously hinders the
|
||||||
|
creation of binary only codecs. No company is willing to port their
|
||||||
|
code to all the different plugin mechanisms.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
While GStreamer also uses it own plugin system it offers a very rich
|
||||||
|
framework for the plugin developper and ensures the plugin can be used
|
||||||
|
in a wide range of applications, transparently interacting with other
|
||||||
|
plugins. The framework that GStreamer provides for the plugins is
|
||||||
|
flexible enough to host even the most demanding plugins.
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2 id="section-motivation-network">
|
||||||
|
<title>Provision for network transparency</title>
|
||||||
|
<para>
|
||||||
|
No infrastructure is present to allow network transparent media
|
||||||
|
handling. A distributed MPEG encoder will typically duplicate the
|
||||||
|
same encoder algorithms found in a non-distributed encoder.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
No provisions have been made for technologies such as
|
||||||
|
the <ulink url="http://developer.gnome.org/arch/component/bonobo.html"
|
||||||
|
type="http">GNOME object embedding using Bonobo</ulink>.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The GStreamer core does not use network transparent technologies at the
|
||||||
|
lowest level as it only adds overhead for the local case.
|
||||||
|
That said, it shouldn't be hard to create a wrapper around the
|
||||||
|
core components. There are tcp plugins now that implement a GStreamer
|
||||||
|
Data Protocol that allows pipelines to be slit over TCP. These are
|
||||||
|
located in the gst-plugins module directory gst/tcp.
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2 id="section-motivation-catchup">
|
||||||
|
<title>Catch up with the <trademark>Windows</trademark> world</title>
|
||||||
|
<para>
|
||||||
|
We need solid media handling if we want to see Linux succeed on
|
||||||
|
the desktop.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
We must clear the road for commercially backed codecs and multimedia
|
||||||
|
applications so that Linux can become an option for doing multimedia.
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
|
</sect1>
|
||||||
|
</chapter>
|
59
docs/manual/intro-preface.xml
Normal file
59
docs/manual/intro-preface.xml
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
<chapter id="chapter-intro">
|
||||||
|
<title>Introduction</title>
|
||||||
|
<para>
|
||||||
|
This chapter gives you an overview of the technologies described in this
|
||||||
|
book.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<sect1 id="section-intro-what">
|
||||||
|
<title>What is GStreamer?</title>
|
||||||
|
<para>
|
||||||
|
GStreamer is a framework for creating streaming media applications.
|
||||||
|
The fundamental design comes from the video pipeline at Oregon Graduate
|
||||||
|
Institute, as well as some ideas from DirectShow.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
GStreamer's development framework makes it possible to write any type of
|
||||||
|
streaming multimedia application. The GStreamer framework is designed
|
||||||
|
to make it easy to write applications that handle audio or video or both.
|
||||||
|
It isn't restricted to audio and video, and can process any kind of
|
||||||
|
data flow.
|
||||||
|
The pipeline design is made to have little overhead above what the
|
||||||
|
applied filters induce. This makes GStreamer a good framework for designing
|
||||||
|
even high-end audio applications which put high demands on latency.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
One of the the most obvious uses of GStreamer is using it to build
|
||||||
|
a media player. GStreamer already includes components for building a
|
||||||
|
media player that can support a very wide variety of formats, including
|
||||||
|
MP3, Ogg Vorbis, MPEG1, MPEG2, AVI, Quicktime, mod, and more. GStreamer,
|
||||||
|
however, is much more than just another media player. Its main advantages
|
||||||
|
are that the pluggable components can be mixed and matched into arbitrary
|
||||||
|
pipelines so that it's possible to write a full-fledged video or audio
|
||||||
|
editing application.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The framework is based on plugins that will provide the various codec
|
||||||
|
and other functionality. The plugins can be linked and arranged in
|
||||||
|
a pipeline. This pipeline defines the flow of the data. Pipelines can
|
||||||
|
also be edited with a GUI editor and saved as XML so that pipeline
|
||||||
|
libraries can be made with a minimum of effort.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The GStreamer core function is to provide a framework for plugins, data flow
|
||||||
|
and media type handling/negotiation.
|
||||||
|
It also provides an API to write applications using the various plugins.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This book is about GStreamer from a developer's point of view; it describes
|
||||||
|
how to write a GStreamer application using the GStreamer libraries and tools.
|
||||||
|
For an explanation about writing plugins, we suggest the Plugin Writers Guide.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</sect1>
|
||||||
|
</chapter>
|
|
@ -1,10 +1,6 @@
|
||||||
lib_LTLIBRARIES = libgstreamer-@GST_MAJORMINOR@.la
|
lib_LTLIBRARIES = libgstreamer-@GST_MAJORMINOR@.la
|
||||||
AS_LIBTOOL_LIB = libgstreamer-@GST_MAJORMINOR@
|
AS_LIBTOOL_LIB = libgstreamer-@GST_MAJORMINOR@
|
||||||
if GST_DISABLE_OMEGA_COTHREADS
|
|
||||||
noinst_LTLIBRARIES =
|
noinst_LTLIBRARIES =
|
||||||
else
|
|
||||||
noinst_LTLIBRARIES = libcothreads.la
|
|
||||||
endif
|
|
||||||
|
|
||||||
#GST_INSTRUMENT_FLAGS = -finstrument-functions -DGST_ENABLE_FUNC_INSTRUMENTATION
|
#GST_INSTRUMENT_FLAGS = -finstrument-functions -DGST_ENABLE_FUNC_INSTRUMENTATION
|
||||||
|
|
||||||
|
@ -66,8 +62,8 @@ else
|
||||||
GST_URI_SRC = gsturi.c
|
GST_URI_SRC = gsturi.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
SUBDIRS = $(GST_PARSE_DIRS) $(GST_REGISTRY_DIRS) . autoplug elements schedulers $(GST_INDEX_DIRS)
|
SUBDIRS = $(GST_PARSE_DIRS) $(GST_REGISTRY_DIRS) . elements schedulers $(GST_INDEX_DIRS)
|
||||||
DIST_SUBDIRS = autoplug elements parse registries schedulers indexers
|
DIST_SUBDIRS = elements parse registries schedulers indexers
|
||||||
|
|
||||||
# make variables for all generated source and header files to make the
|
# make variables for all generated source and header files to make the
|
||||||
# distinction clear
|
# distinction clear
|
||||||
|
@ -85,6 +81,7 @@ libgstreamer_@GST_MAJORMINOR@_la_SOURCES = \
|
||||||
gstatomic.c \
|
gstatomic.c \
|
||||||
gstbin.c \
|
gstbin.c \
|
||||||
gstbuffer.c \
|
gstbuffer.c \
|
||||||
|
gstbus.c \
|
||||||
gstcaps.c \
|
gstcaps.c \
|
||||||
gstclock.c \
|
gstclock.c \
|
||||||
gstcpu.c \
|
gstcpu.c \
|
||||||
|
@ -98,20 +95,22 @@ libgstreamer_@GST_MAJORMINOR@_la_SOURCES = \
|
||||||
$(GST_INDEX_SRC) \
|
$(GST_INDEX_SRC) \
|
||||||
gstinfo.c \
|
gstinfo.c \
|
||||||
gstinterface.c \
|
gstinterface.c \
|
||||||
|
gstiterator.c \
|
||||||
gstmemchunk.c \
|
gstmemchunk.c \
|
||||||
|
gstmessage.c \
|
||||||
gstpad.c \
|
gstpad.c \
|
||||||
gstpipeline.c \
|
gstpipeline.c \
|
||||||
gstplugin.c \
|
gstplugin.c \
|
||||||
gstpluginfeature.c \
|
gstpluginfeature.c \
|
||||||
gstprobe.c \
|
gstprobe.c \
|
||||||
gstqueue.c \
|
|
||||||
gstquery.c \
|
gstquery.c \
|
||||||
|
gstqueue.c \
|
||||||
gstscheduler.c \
|
gstscheduler.c \
|
||||||
gststructure.c \
|
gststructure.c \
|
||||||
gstsystemclock.c \
|
gstsystemclock.c \
|
||||||
gsttag.c \
|
gsttag.c \
|
||||||
gsttaginterface.c \
|
gsttaginterface.c \
|
||||||
gstthread.c \
|
gsttask.c \
|
||||||
$(GST_TRACE_SRC) \
|
$(GST_TRACE_SRC) \
|
||||||
gsttrashstack.c \
|
gsttrashstack.c \
|
||||||
gsttypefind.c \
|
gsttypefind.c \
|
||||||
|
@ -158,6 +157,7 @@ gst_headers = \
|
||||||
gstobject.h \
|
gstobject.h \
|
||||||
gstbin.h \
|
gstbin.h \
|
||||||
gstbuffer.h \
|
gstbuffer.h \
|
||||||
|
gstbus.h \
|
||||||
gstcaps.h \
|
gstcaps.h \
|
||||||
gstclock.h \
|
gstclock.h \
|
||||||
gstcompat.h \
|
gstcompat.h \
|
||||||
|
@ -171,21 +171,22 @@ gst_headers = \
|
||||||
gstindex.h \
|
gstindex.h \
|
||||||
gstinfo.h \
|
gstinfo.h \
|
||||||
gstinterface.h \
|
gstinterface.h \
|
||||||
|
gstiterator.h \
|
||||||
gstmacros.h \
|
gstmacros.h \
|
||||||
gstmemchunk.h \
|
gstmemchunk.h \
|
||||||
|
gstmessage.h \
|
||||||
gstpad.h \
|
gstpad.h \
|
||||||
gstpipeline.h \
|
gstpipeline.h \
|
||||||
gstplugin.h \
|
gstplugin.h \
|
||||||
gstpluginfeature.h \
|
gstpluginfeature.h \
|
||||||
gstprobe.h \
|
gstprobe.h \
|
||||||
gstqueue.h \
|
|
||||||
gstquery.h \
|
gstquery.h \
|
||||||
|
gstqueue.h \
|
||||||
gstscheduler.h \
|
gstscheduler.h \
|
||||||
gststructure.h \
|
gststructure.h \
|
||||||
gstsystemclock.h \
|
gstsystemclock.h \
|
||||||
gsttag.h \
|
gsttag.h \
|
||||||
gsttaginterface.h \
|
gsttaginterface.h \
|
||||||
gstthread.h \
|
|
||||||
gsttrace.h \
|
gsttrace.h \
|
||||||
gsttrashstack.h \
|
gsttrashstack.h \
|
||||||
gsttypefind.h \
|
gsttypefind.h \
|
||||||
|
|
|
@ -24,16 +24,17 @@ endif
|
||||||
|
|
||||||
libgstelements_la_DEPENDENCIES = ../libgstreamer-@GST_MAJORMINOR@.la
|
libgstelements_la_DEPENDENCIES = ../libgstreamer-@GST_MAJORMINOR@.la
|
||||||
libgstelements_la_SOURCES = \
|
libgstelements_la_SOURCES = \
|
||||||
gstaggregator.c \
|
|
||||||
gstbufferstore.c \
|
|
||||||
gstelements.c \
|
|
||||||
gstfakesink.c \
|
|
||||||
gstfakesrc.c \
|
gstfakesrc.c \
|
||||||
gstfilesink.c \
|
gstfakesink.c \
|
||||||
gstfilesrc.c \
|
gstfilesrc.c \
|
||||||
|
gstidentity.c \
|
||||||
|
gstelements.c \
|
||||||
|
#gstaggregator.c \
|
||||||
|
gstbufferstore.c \
|
||||||
|
gstfakesink.c \
|
||||||
|
gstfilesink.c \
|
||||||
gstfdsink.c \
|
gstfdsink.c \
|
||||||
gstfdsrc.c \
|
gstfdsrc.c \
|
||||||
gstidentity.c \
|
|
||||||
gstmd5sink.c \
|
gstmd5sink.c \
|
||||||
$(multifilesrc) \
|
$(multifilesrc) \
|
||||||
$(pipefilter) \
|
$(pipefilter) \
|
||||||
|
|
|
@ -55,24 +55,24 @@ extern GType gst_filesrc_get_type (void);
|
||||||
extern GstElementDetails gst_filesrc_details;
|
extern GstElementDetails gst_filesrc_details;
|
||||||
|
|
||||||
static struct _elements_entry _elements[] = {
|
static struct _elements_entry _elements[] = {
|
||||||
{"aggregator", GST_RANK_NONE, gst_aggregator_get_type},
|
// {"aggregator", GST_RANK_NONE, gst_aggregator_get_type},
|
||||||
{"fakesrc", GST_RANK_NONE, gst_fakesrc_get_type},
|
{"fakesrc", GST_RANK_NONE, gst_fakesrc_get_type},
|
||||||
{"fakesink", GST_RANK_NONE, gst_fakesink_get_type},
|
{"fakesink", GST_RANK_NONE, gst_fakesink_get_type},
|
||||||
{"fdsink", GST_RANK_NONE, gst_fdsink_get_type},
|
|
||||||
{"fdsrc", GST_RANK_NONE, gst_fdsrc_get_type},
|
|
||||||
{"filesrc", GST_RANK_NONE, gst_filesrc_get_type},
|
{"filesrc", GST_RANK_NONE, gst_filesrc_get_type},
|
||||||
{"filesink", GST_RANK_NONE, gst_filesink_get_type},
|
|
||||||
{"identity", GST_RANK_NONE, gst_identity_get_type},
|
{"identity", GST_RANK_NONE, gst_identity_get_type},
|
||||||
{"md5sink", GST_RANK_NONE, gst_md5sink_get_type},
|
// {"fdsink", GST_RANK_NONE, gst_fdsink_get_type},
|
||||||
|
// {"fdsrc", GST_RANK_NONE, gst_fdsrc_get_type},
|
||||||
|
// {"filesink", GST_RANK_NONE, gst_filesink_get_type},
|
||||||
|
// {"md5sink", GST_RANK_NONE, gst_md5sink_get_type},
|
||||||
#ifndef HAVE_WIN32
|
#ifndef HAVE_WIN32
|
||||||
{"multifilesrc", GST_RANK_NONE, gst_multifilesrc_get_type},
|
// {"multifilesrc", GST_RANK_NONE, gst_multifilesrc_get_type},
|
||||||
{"pipefilter", GST_RANK_NONE, gst_pipefilter_get_type},
|
// {"pipefilter", GST_RANK_NONE, gst_pipefilter_get_type},
|
||||||
#endif
|
#endif
|
||||||
{"shaper", GST_RANK_NONE, gst_shaper_get_type},
|
// {"shaper", GST_RANK_NONE, gst_shaper_get_type},
|
||||||
{"statistics", GST_RANK_NONE, gst_statistics_get_type},
|
// {"statistics", GST_RANK_NONE, gst_statistics_get_type},
|
||||||
{"tee", GST_RANK_NONE, gst_tee_get_type},
|
// {"tee", GST_RANK_NONE, gst_tee_get_type},
|
||||||
{"typefind", GST_RANK_NONE, gst_type_find_element_get_type},
|
// {"typefind", GST_RANK_NONE, gst_type_find_element_get_type},
|
||||||
{NULL, 0},
|
// {NULL, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
|
|
@ -113,7 +113,8 @@ static void gst_fakesink_get_property (GObject * object, guint prop_id,
|
||||||
|
|
||||||
static GstElementStateReturn gst_fakesink_change_state (GstElement * element);
|
static GstElementStateReturn gst_fakesink_change_state (GstElement * element);
|
||||||
|
|
||||||
static void gst_fakesink_chain (GstPad * pad, GstData * _data);
|
static GstFlowReturn gst_fakesink_chain (GstPad * pad, GstBuffer * buffer);
|
||||||
|
static gboolean gst_fakesink_event (GstPad * pad, GstEvent * event);
|
||||||
|
|
||||||
static guint gst_fakesink_signals[LAST_SIGNAL] = { 0 };
|
static guint gst_fakesink_signals[LAST_SIGNAL] = { 0 };
|
||||||
|
|
||||||
|
@ -138,6 +139,8 @@ gst_fakesink_class_init (GstFakeSinkClass * klass)
|
||||||
gobject_class = (GObjectClass *) klass;
|
gobject_class = (GObjectClass *) klass;
|
||||||
gstelement_class = (GstElementClass *) klass;
|
gstelement_class = (GstElementClass *) klass;
|
||||||
|
|
||||||
|
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesink_set_property);
|
||||||
|
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesink_get_property);
|
||||||
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_SINKS,
|
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_SINKS,
|
||||||
g_param_spec_int ("num_sinks", "Number of sinks",
|
g_param_spec_int ("num_sinks", "Number of sinks",
|
||||||
|
@ -169,9 +172,6 @@ gst_fakesink_class_init (GstFakeSinkClass * klass)
|
||||||
gst_marshal_VOID__BOXED_OBJECT, G_TYPE_NONE, 2,
|
gst_marshal_VOID__BOXED_OBJECT, G_TYPE_NONE, 2,
|
||||||
GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD);
|
GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD);
|
||||||
|
|
||||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesink_set_property);
|
|
||||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesink_get_property);
|
|
||||||
|
|
||||||
gstelement_class->request_new_pad =
|
gstelement_class->request_new_pad =
|
||||||
GST_DEBUG_FUNCPTR (gst_fakesink_request_new_pad);
|
GST_DEBUG_FUNCPTR (gst_fakesink_request_new_pad);
|
||||||
gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_fakesink_set_clock);
|
gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_fakesink_set_clock);
|
||||||
|
@ -189,6 +189,7 @@ gst_fakesink_init (GstFakeSink * fakesink)
|
||||||
"sink");
|
"sink");
|
||||||
gst_element_add_pad (GST_ELEMENT (fakesink), pad);
|
gst_element_add_pad (GST_ELEMENT (fakesink), pad);
|
||||||
gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_fakesink_chain));
|
gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_fakesink_chain));
|
||||||
|
gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_fakesink_event));
|
||||||
|
|
||||||
fakesink->silent = FALSE;
|
fakesink->silent = FALSE;
|
||||||
fakesink->dump = FALSE;
|
fakesink->dump = FALSE;
|
||||||
|
@ -196,8 +197,6 @@ gst_fakesink_init (GstFakeSink * fakesink)
|
||||||
fakesink->last_message = NULL;
|
fakesink->last_message = NULL;
|
||||||
fakesink->state_error = FAKESINK_STATE_ERROR_NONE;
|
fakesink->state_error = FAKESINK_STATE_ERROR_NONE;
|
||||||
fakesink->signal_handoffs = FALSE;
|
fakesink->signal_handoffs = FALSE;
|
||||||
|
|
||||||
GST_FLAG_SET (fakesink, GST_ELEMENT_EVENT_AWARE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -308,45 +307,72 @@ gst_fakesink_get_property (GObject * object, guint prop_id, GValue * value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static gboolean
|
||||||
gst_fakesink_chain (GstPad * pad, GstData * _data)
|
gst_fakesink_event (GstPad * pad, GstEvent * event)
|
||||||
{
|
{
|
||||||
GstBuffer *buf = GST_BUFFER (_data);
|
|
||||||
GstFakeSink *fakesink;
|
GstFakeSink *fakesink;
|
||||||
|
gboolean result = TRUE;
|
||||||
g_return_if_fail (pad != NULL);
|
|
||||||
g_return_if_fail (GST_IS_PAD (pad));
|
|
||||||
g_return_if_fail (buf != NULL);
|
|
||||||
|
|
||||||
fakesink = GST_FAKESINK (GST_OBJECT_PARENT (pad));
|
fakesink = GST_FAKESINK (GST_OBJECT_PARENT (pad));
|
||||||
|
|
||||||
if (GST_IS_EVENT (buf)) {
|
GST_STREAM_LOCK (pad);
|
||||||
GstEvent *event = GST_EVENT (buf);
|
|
||||||
|
|
||||||
if (!fakesink->silent) {
|
if (!fakesink->silent) {
|
||||||
g_free (fakesink->last_message);
|
g_free (fakesink->last_message);
|
||||||
|
|
||||||
fakesink->last_message =
|
fakesink->last_message =
|
||||||
g_strdup_printf ("chain ******* (%s:%s)E (type: %d) %p",
|
g_strdup_printf ("chain ******* (%s:%s)E (type: %d) %p",
|
||||||
GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event);
|
GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event);
|
||||||
|
|
||||||
g_object_notify (G_OBJECT (fakesink), "last_message");
|
g_object_notify (G_OBJECT (fakesink), "last_message");
|
||||||
}
|
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
|
||||||
case GST_EVENT_DISCONTINUOUS:
|
|
||||||
if (fakesink->sync && fakesink->clock) {
|
|
||||||
gint64 value = GST_EVENT_DISCONT_OFFSET (event, 0).value;
|
|
||||||
|
|
||||||
gst_element_set_time (GST_ELEMENT (fakesink), value);
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
gst_pad_event_default (pad, event);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_EOS:
|
||||||
|
{
|
||||||
|
gst_element_finish_preroll (GST_ELEMENT (fakesink),
|
||||||
|
GST_STREAM_GET_LOCK (pad));
|
||||||
|
gst_pipeline_post_message (GST_ELEMENT_MANAGER (fakesink),
|
||||||
|
gst_message_new_eos (GST_OBJECT (fakesink)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GST_EVENT_DISCONTINUOUS:
|
||||||
|
if (fakesink->sync && fakesink->clock) {
|
||||||
|
//gint64 value = GST_EVENT_DISCONT_OFFSET (event, 0).value;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
result = gst_pad_event_default (pad, event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
GST_STREAM_UNLOCK (pad);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_fakesink_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
|
{
|
||||||
|
GstBuffer *buf = GST_BUFFER (buffer);
|
||||||
|
GstFakeSink *fakesink;
|
||||||
|
GstFlowReturn result = GST_FLOW_OK;
|
||||||
|
GstCaps *caps;
|
||||||
|
|
||||||
|
fakesink = GST_FAKESINK (GST_OBJECT_PARENT (pad));
|
||||||
|
|
||||||
|
caps = gst_buffer_get_caps (buffer);
|
||||||
|
if (caps && caps != GST_PAD_CAPS (pad)) {
|
||||||
|
gst_pad_set_caps (pad, caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* grab streaming lock to synchronize with event method */
|
||||||
|
GST_STREAM_LOCK (pad);
|
||||||
|
|
||||||
|
result =
|
||||||
|
gst_element_finish_preroll (GST_ELEMENT (fakesink),
|
||||||
|
GST_STREAM_GET_LOCK (pad));
|
||||||
|
if (result != GST_FLOW_OK)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
if (fakesink->sync && fakesink->clock) {
|
if (fakesink->sync && fakesink->clock) {
|
||||||
gst_element_wait (GST_ELEMENT (fakesink), GST_BUFFER_TIMESTAMP (buf));
|
gst_element_wait (GST_ELEMENT (fakesink), GST_BUFFER_TIMESTAMP (buf));
|
||||||
}
|
}
|
||||||
|
@ -374,12 +400,17 @@ gst_fakesink_chain (GstPad * pad, GstData * _data)
|
||||||
gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
|
gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
GST_STREAM_UNLOCK (pad);
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstElementStateReturn
|
static GstElementStateReturn
|
||||||
gst_fakesink_change_state (GstElement * element)
|
gst_fakesink_change_state (GstElement * element)
|
||||||
{
|
{
|
||||||
|
GstElementStateReturn ret = GST_STATE_SUCCESS;
|
||||||
GstFakeSink *fakesink = GST_FAKESINK (element);
|
GstFakeSink *fakesink = GST_FAKESINK (element);
|
||||||
|
|
||||||
switch (GST_STATE_TRANSITION (element)) {
|
switch (GST_STATE_TRANSITION (element)) {
|
||||||
|
@ -390,6 +421,8 @@ gst_fakesink_change_state (GstElement * element)
|
||||||
case GST_STATE_READY_TO_PAUSED:
|
case GST_STATE_READY_TO_PAUSED:
|
||||||
if (fakesink->state_error == FAKESINK_STATE_ERROR_READY_PAUSED)
|
if (fakesink->state_error == FAKESINK_STATE_ERROR_READY_PAUSED)
|
||||||
goto error;
|
goto error;
|
||||||
|
/* need to complete preroll before this state change completes */
|
||||||
|
ret = GST_STATE_ASYNC;
|
||||||
break;
|
break;
|
||||||
case GST_STATE_PAUSED_TO_PLAYING:
|
case GST_STATE_PAUSED_TO_PLAYING:
|
||||||
if (fakesink->state_error == FAKESINK_STATE_ERROR_PAUSED_PLAYING)
|
if (fakesink->state_error == FAKESINK_STATE_ERROR_PAUSED_PLAYING)
|
||||||
|
@ -412,9 +445,9 @@ gst_fakesink_change_state (GstElement * element)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
||||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||||
|
|
||||||
return GST_STATE_SUCCESS;
|
return ret;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
GST_ELEMENT_ERROR (element, CORE, STATE_CHANGE, (NULL), (NULL));
|
GST_ELEMENT_ERROR (element, CORE, STATE_CHANGE, (NULL), (NULL));
|
||||||
|
|
|
@ -180,6 +180,7 @@ GST_BOILERPLATE_FULL (GstFakeSrc, gst_fakesrc, GstElement, GST_TYPE_ELEMENT,
|
||||||
static GstPad *gst_fakesrc_request_new_pad (GstElement * element,
|
static GstPad *gst_fakesrc_request_new_pad (GstElement * element,
|
||||||
GstPadTemplate * templ, const gchar * unused);
|
GstPadTemplate * templ, const gchar * unused);
|
||||||
static void gst_fakesrc_update_functions (GstFakeSrc * src);
|
static void gst_fakesrc_update_functions (GstFakeSrc * src);
|
||||||
|
static gboolean gst_fakesrc_activate (GstPad * pad, gboolean active);
|
||||||
static void gst_fakesrc_set_property (GObject * object, guint prop_id,
|
static void gst_fakesrc_set_property (GObject * object, guint prop_id,
|
||||||
const GValue * value, GParamSpec * pspec);
|
const GValue * value, GParamSpec * pspec);
|
||||||
static void gst_fakesrc_get_property (GObject * object, guint prop_id,
|
static void gst_fakesrc_get_property (GObject * object, guint prop_id,
|
||||||
|
@ -188,7 +189,7 @@ static void gst_fakesrc_set_clock (GstElement * element, GstClock * clock);
|
||||||
|
|
||||||
static GstElementStateReturn gst_fakesrc_change_state (GstElement * element);
|
static GstElementStateReturn gst_fakesrc_change_state (GstElement * element);
|
||||||
|
|
||||||
static GstData *gst_fakesrc_get (GstPad * pad);
|
static GstFlowReturn gst_fakesrc_get (GstPad * pad, GstBuffer ** buffer);
|
||||||
static void gst_fakesrc_loop (GstElement * element);
|
static void gst_fakesrc_loop (GstElement * element);
|
||||||
|
|
||||||
static guint gst_fakesrc_signals[LAST_SIGNAL] = { 0 };
|
static guint gst_fakesrc_signals[LAST_SIGNAL] = { 0 };
|
||||||
|
@ -214,6 +215,8 @@ gst_fakesrc_class_init (GstFakeSrcClass * klass)
|
||||||
gobject_class = (GObjectClass *) klass;
|
gobject_class = (GObjectClass *) klass;
|
||||||
gstelement_class = (GstElementClass *) klass;
|
gstelement_class = (GstElementClass *) klass;
|
||||||
|
|
||||||
|
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesrc_set_property);
|
||||||
|
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesrc_get_property);
|
||||||
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_SOURCES,
|
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_SOURCES,
|
||||||
g_param_spec_int ("num-sources", "num-sources", "Number of sources",
|
g_param_spec_int ("num-sources", "num-sources", "Number of sources",
|
||||||
|
@ -281,9 +284,6 @@ gst_fakesrc_class_init (GstFakeSrcClass * klass)
|
||||||
gst_marshal_VOID__BOXED_OBJECT, G_TYPE_NONE, 2,
|
gst_marshal_VOID__BOXED_OBJECT, G_TYPE_NONE, 2,
|
||||||
GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD);
|
GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD);
|
||||||
|
|
||||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesrc_set_property);
|
|
||||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesrc_get_property);
|
|
||||||
|
|
||||||
gstelement_class->request_new_pad =
|
gstelement_class->request_new_pad =
|
||||||
GST_DEBUG_FUNCPTR (gst_fakesrc_request_new_pad);
|
GST_DEBUG_FUNCPTR (gst_fakesrc_request_new_pad);
|
||||||
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_fakesrc_change_state);
|
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_fakesrc_change_state);
|
||||||
|
@ -434,7 +434,7 @@ gst_fakesrc_event_handler (GstPad * pad, GstEvent * event)
|
||||||
{
|
{
|
||||||
GstFakeSrc *src;
|
GstFakeSrc *src;
|
||||||
|
|
||||||
src = GST_FAKESRC (gst_pad_get_parent (pad));
|
src = GST_FAKESRC (gst_object_get_parent (GST_OBJECT (pad)));
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
case GST_EVENT_SEEK:
|
case GST_EVENT_SEEK:
|
||||||
|
@ -467,13 +467,6 @@ gst_fakesrc_update_functions (GstFakeSrc * src)
|
||||||
{
|
{
|
||||||
GList *pads;
|
GList *pads;
|
||||||
|
|
||||||
if (src->loop_based) {
|
|
||||||
gst_element_set_loop_function (GST_ELEMENT (src),
|
|
||||||
GST_DEBUG_FUNCPTR (gst_fakesrc_loop));
|
|
||||||
} else {
|
|
||||||
gst_element_set_loop_function (GST_ELEMENT (src), NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
pads = GST_ELEMENT (src)->pads;
|
pads = GST_ELEMENT (src)->pads;
|
||||||
while (pads) {
|
while (pads) {
|
||||||
GstPad *pad = GST_PAD (pads->data);
|
GstPad *pad = GST_PAD (pads->data);
|
||||||
|
@ -484,6 +477,7 @@ gst_fakesrc_update_functions (GstFakeSrc * src)
|
||||||
gst_pad_set_get_function (pad, GST_DEBUG_FUNCPTR (gst_fakesrc_get));
|
gst_pad_set_get_function (pad, GST_DEBUG_FUNCPTR (gst_fakesrc_get));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gst_pad_set_activate_function (pad, gst_fakesrc_activate);
|
||||||
gst_pad_set_event_function (pad, gst_fakesrc_event_handler);
|
gst_pad_set_event_function (pad, gst_fakesrc_event_handler);
|
||||||
gst_pad_set_event_mask_function (pad, gst_fakesrc_get_event_mask);
|
gst_pad_set_event_mask_function (pad, gst_fakesrc_get_event_mask);
|
||||||
gst_pad_set_query_function (pad, gst_fakesrc_query);
|
gst_pad_set_query_function (pad, gst_fakesrc_query);
|
||||||
|
@ -790,36 +784,40 @@ gst_fakesrc_create_buffer (GstFakeSrc * src)
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstData *
|
static GstFlowReturn
|
||||||
gst_fakesrc_get (GstPad * pad)
|
gst_fakesrc_get (GstPad * pad, GstBuffer ** buffer)
|
||||||
{
|
{
|
||||||
GstFakeSrc *src;
|
GstFakeSrc *src;
|
||||||
GstBuffer *buf;
|
GstBuffer *buf;
|
||||||
GstClockTime time;
|
GstClockTime time;
|
||||||
|
GstFlowReturn result = GST_FLOW_OK;
|
||||||
|
|
||||||
g_return_val_if_fail (pad != NULL, NULL);
|
g_return_val_if_fail (pad != NULL, GST_FLOW_ERROR);
|
||||||
|
|
||||||
src = GST_FAKESRC (GST_OBJECT_PARENT (pad));
|
src = GST_FAKESRC (GST_OBJECT_PARENT (pad));
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_FAKESRC (src), NULL);
|
g_return_val_if_fail (GST_IS_FAKESRC (src), GST_FLOW_ERROR);
|
||||||
|
|
||||||
|
GST_STREAM_LOCK (pad);
|
||||||
if (src->need_flush) {
|
if (src->need_flush) {
|
||||||
src->need_flush = FALSE;
|
src->need_flush = FALSE;
|
||||||
return GST_DATA (gst_event_new (GST_EVENT_FLUSH));
|
gst_pad_push_event (pad, gst_event_new (GST_EVENT_FLUSH));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src->buffer_count == src->segment_end) {
|
if (src->buffer_count == src->segment_end) {
|
||||||
if (src->segment_loop) {
|
if (src->segment_loop) {
|
||||||
return GST_DATA (gst_event_new (GST_EVENT_SEGMENT_DONE));
|
gst_pad_push_event (pad, gst_event_new (GST_EVENT_SEGMENT_DONE));
|
||||||
} else {
|
} else {
|
||||||
gst_element_set_eos (GST_ELEMENT (src));
|
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||||
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
result = GST_FLOW_UNEXPECTED;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src->rt_num_buffers == 0) {
|
if (src->rt_num_buffers == 0) {
|
||||||
gst_element_set_eos (GST_ELEMENT (src));
|
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||||
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
result = GST_FLOW_UNEXPECTED;
|
||||||
|
goto done;
|
||||||
} else {
|
} else {
|
||||||
if (src->rt_num_buffers > 0)
|
if (src->rt_num_buffers > 0)
|
||||||
src->rt_num_buffers--;
|
src->rt_num_buffers--;
|
||||||
|
@ -827,8 +825,9 @@ gst_fakesrc_get (GstPad * pad)
|
||||||
|
|
||||||
if (src->eos) {
|
if (src->eos) {
|
||||||
GST_INFO ("fakesrc is setting eos on pad");
|
GST_INFO ("fakesrc is setting eos on pad");
|
||||||
gst_element_set_eos (GST_ELEMENT (src));
|
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||||
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
result = GST_FLOW_UNEXPECTED;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = gst_fakesrc_create_buffer (src);
|
buf = gst_fakesrc_create_buffer (src);
|
||||||
|
@ -867,7 +866,12 @@ gst_fakesrc_get (GstPad * pad)
|
||||||
|
|
||||||
src->bytes_sent += GST_BUFFER_SIZE (buf);
|
src->bytes_sent += GST_BUFFER_SIZE (buf);
|
||||||
|
|
||||||
return GST_DATA (buf);
|
*buffer = buf;
|
||||||
|
|
||||||
|
done:
|
||||||
|
GST_STREAM_UNLOCK (pad);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -881,35 +885,82 @@ gst_fakesrc_loop (GstElement * element)
|
||||||
{
|
{
|
||||||
GstFakeSrc *src;
|
GstFakeSrc *src;
|
||||||
const GList *pads;
|
const GList *pads;
|
||||||
|
GstTask *task;
|
||||||
|
|
||||||
g_return_if_fail (element != NULL);
|
g_return_if_fail (element != NULL);
|
||||||
g_return_if_fail (GST_IS_FAKESRC (element));
|
g_return_if_fail (GST_IS_FAKESRC (element));
|
||||||
|
|
||||||
src = GST_FAKESRC (element);
|
src = GST_FAKESRC (element);
|
||||||
|
task = src->task;
|
||||||
|
|
||||||
pads = gst_element_get_pad_list (element);
|
pads = element->pads;
|
||||||
|
|
||||||
while (pads) {
|
while (pads) {
|
||||||
GstPad *pad = GST_PAD (pads->data);
|
GstPad *pad = GST_PAD (pads->data);
|
||||||
GstData *data;
|
GstBuffer *buffer;
|
||||||
|
GstFlowReturn ret;
|
||||||
|
|
||||||
data = gst_fakesrc_get (pad);
|
ret = gst_fakesrc_get (pad, &buffer);
|
||||||
gst_pad_push (pad, data);
|
if (ret != GST_FLOW_OK) {
|
||||||
|
gst_task_stop (task);
|
||||||
if (src->eos) {
|
return;
|
||||||
|
}
|
||||||
|
ret = gst_pad_push (pad, buffer);
|
||||||
|
if (ret != GST_FLOW_OK) {
|
||||||
|
gst_task_stop (task);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (src->eos) {
|
||||||
|
gst_task_stop (task);
|
||||||
|
return;
|
||||||
|
}
|
||||||
pads = g_list_next (pads);
|
pads = g_list_next (pads);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_fakesrc_activate (GstPad * pad, gboolean active)
|
||||||
|
{
|
||||||
|
gboolean result = FALSE;
|
||||||
|
GstFakeSrc *fakesrc;
|
||||||
|
|
||||||
|
fakesrc = GST_FAKESRC (GST_OBJECT_PARENT (pad));
|
||||||
|
|
||||||
|
if (active) {
|
||||||
|
/* if we have a scheduler we can start the task */
|
||||||
|
if (GST_ELEMENT_MANAGER (fakesrc)) {
|
||||||
|
GST_STREAM_LOCK (pad);
|
||||||
|
fakesrc->task =
|
||||||
|
gst_scheduler_create_task (GST_ELEMENT_MANAGER (fakesrc)->scheduler,
|
||||||
|
(GstTaskFunction) gst_fakesrc_loop, fakesrc);
|
||||||
|
|
||||||
|
gst_task_start (fakesrc->task);
|
||||||
|
GST_STREAM_UNLOCK (pad);
|
||||||
|
result = TRUE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* step 1, unblock clock sync (if any) */
|
||||||
|
|
||||||
|
/* step 2, make sure streaming finishes */
|
||||||
|
GST_STREAM_LOCK (pad);
|
||||||
|
/* step 3, stop the task */
|
||||||
|
gst_task_stop (fakesrc->task);
|
||||||
|
gst_object_unref (GST_OBJECT (fakesrc->task));
|
||||||
|
GST_STREAM_UNLOCK (pad);
|
||||||
|
|
||||||
|
result = TRUE;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static GstElementStateReturn
|
static GstElementStateReturn
|
||||||
gst_fakesrc_change_state (GstElement * element)
|
gst_fakesrc_change_state (GstElement * element)
|
||||||
{
|
{
|
||||||
GstFakeSrc *fakesrc;
|
GstFakeSrc *fakesrc;
|
||||||
|
GstElementStateReturn result = GST_STATE_FAILURE;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_FAKESRC (element), GST_STATE_FAILURE);
|
g_return_val_if_fail (GST_IS_FAKESRC (element), result);
|
||||||
|
|
||||||
fakesrc = GST_FAKESRC (element);
|
fakesrc = GST_FAKESRC (element);
|
||||||
|
|
||||||
|
@ -917,6 +968,7 @@ gst_fakesrc_change_state (GstElement * element)
|
||||||
case GST_STATE_NULL_TO_READY:
|
case GST_STATE_NULL_TO_READY:
|
||||||
break;
|
break;
|
||||||
case GST_STATE_READY_TO_PAUSED:
|
case GST_STATE_READY_TO_PAUSED:
|
||||||
|
{
|
||||||
fakesrc->buffer_count = 0;
|
fakesrc->buffer_count = 0;
|
||||||
fakesrc->pattern_byte = 0x00;
|
fakesrc->pattern_byte = 0x00;
|
||||||
fakesrc->need_flush = FALSE;
|
fakesrc->need_flush = FALSE;
|
||||||
|
@ -924,7 +976,14 @@ gst_fakesrc_change_state (GstElement * element)
|
||||||
fakesrc->bytes_sent = 0;
|
fakesrc->bytes_sent = 0;
|
||||||
fakesrc->rt_num_buffers = fakesrc->num_buffers;
|
fakesrc->rt_num_buffers = fakesrc->num_buffers;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case GST_STATE_PAUSED_TO_PLAYING:
|
case GST_STATE_PAUSED_TO_PLAYING:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||||
|
|
||||||
|
switch (GST_STATE_TRANSITION (element)) {
|
||||||
case GST_STATE_PLAYING_TO_PAUSED:
|
case GST_STATE_PLAYING_TO_PAUSED:
|
||||||
break;
|
break;
|
||||||
case GST_STATE_PAUSED_TO_READY:
|
case GST_STATE_PAUSED_TO_READY:
|
||||||
|
@ -941,8 +1000,5 @@ gst_fakesrc_change_state (GstElement * element)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
return result;
|
||||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
|
||||||
|
|
||||||
return GST_STATE_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,8 @@ struct _GstFakeSrc {
|
||||||
gboolean loop_based;
|
gboolean loop_based;
|
||||||
gboolean eos;
|
gboolean eos;
|
||||||
|
|
||||||
|
GstTask *task;
|
||||||
|
|
||||||
GstFakeSrcOutputType output;
|
GstFakeSrcOutputType output;
|
||||||
GstFakeSrcDataType data;
|
GstFakeSrcDataType data;
|
||||||
GstFakeSrcSizeType sizetype;
|
GstFakeSrcSizeType sizetype;
|
||||||
|
|
|
@ -170,11 +170,12 @@ static void gst_filesrc_get_property (GObject * object, guint prop_id,
|
||||||
GValue * value, GParamSpec * pspec);
|
GValue * value, GParamSpec * pspec);
|
||||||
|
|
||||||
static gboolean gst_filesrc_check_filesize (GstFileSrc * src);
|
static gboolean gst_filesrc_check_filesize (GstFileSrc * src);
|
||||||
static GstData *gst_filesrc_get (GstPad * pad);
|
static GstFlowReturn gst_filesrc_get (GstPad * pad, GstBuffer ** buffer);
|
||||||
static gboolean gst_filesrc_srcpad_event (GstPad * pad, GstEvent * event);
|
static gboolean gst_filesrc_srcpad_event (GstPad * pad, GstEvent * event);
|
||||||
static gboolean gst_filesrc_srcpad_query (GstPad * pad, GstQueryType type,
|
static gboolean gst_filesrc_srcpad_query (GstPad * pad, GstQueryType type,
|
||||||
GstFormat * format, gint64 * value);
|
GstFormat * format, gint64 * value);
|
||||||
|
|
||||||
|
static gboolean gst_filesrc_activate (GstPad * pad, gboolean active);
|
||||||
static GstElementStateReturn gst_filesrc_change_state (GstElement * element);
|
static GstElementStateReturn gst_filesrc_change_state (GstElement * element);
|
||||||
|
|
||||||
static void gst_filesrc_uri_handler_init (gpointer g_iface,
|
static void gst_filesrc_uri_handler_init (gpointer g_iface,
|
||||||
|
@ -214,6 +215,8 @@ gst_filesrc_class_init (GstFileSrcClass * klass)
|
||||||
|
|
||||||
gobject_class = (GObjectClass *) klass;
|
gobject_class = (GObjectClass *) klass;
|
||||||
|
|
||||||
|
gobject_class->set_property = gst_filesrc_set_property;
|
||||||
|
gobject_class->get_property = gst_filesrc_get_property;
|
||||||
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FD,
|
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FD,
|
||||||
g_param_spec_int ("fd", "File-descriptor",
|
g_param_spec_int ("fd", "File-descriptor",
|
||||||
|
@ -235,8 +238,6 @@ gst_filesrc_class_init (GstFileSrcClass * klass)
|
||||||
"Touch data to force disk read", FALSE, G_PARAM_READWRITE));
|
"Touch data to force disk read", FALSE, G_PARAM_READWRITE));
|
||||||
|
|
||||||
gobject_class->dispose = gst_filesrc_dispose;
|
gobject_class->dispose = gst_filesrc_dispose;
|
||||||
gobject_class->set_property = gst_filesrc_set_property;
|
|
||||||
gobject_class->get_property = gst_filesrc_get_property;
|
|
||||||
|
|
||||||
gstelement_class->change_state = gst_filesrc_change_state;
|
gstelement_class->change_state = gst_filesrc_change_state;
|
||||||
}
|
}
|
||||||
|
@ -248,6 +249,7 @@ gst_filesrc_init (GstFileSrc * src)
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
|
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
|
||||||
"src");
|
"src");
|
||||||
gst_pad_set_get_function (src->srcpad, gst_filesrc_get);
|
gst_pad_set_get_function (src->srcpad, gst_filesrc_get);
|
||||||
|
gst_pad_set_activate_function (src->srcpad, gst_filesrc_activate);
|
||||||
gst_pad_set_event_function (src->srcpad, gst_filesrc_srcpad_event);
|
gst_pad_set_event_function (src->srcpad, gst_filesrc_srcpad_event);
|
||||||
gst_pad_set_event_mask_function (src->srcpad, gst_filesrc_get_event_mask);
|
gst_pad_set_event_mask_function (src->srcpad, gst_filesrc_get_event_mask);
|
||||||
gst_pad_set_query_function (src->srcpad, gst_filesrc_srcpad_query);
|
gst_pad_set_query_function (src->srcpad, gst_filesrc_srcpad_query);
|
||||||
|
@ -672,7 +674,7 @@ gst_filesrc_get_read (GstFileSrc * src)
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
GST_DEBUG ("non-regular file hits EOS");
|
GST_DEBUG ("non-regular file hits EOS");
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
gst_element_set_eos (GST_ELEMENT (src));
|
//gst_element_set_eos (GST_ELEMENT (src));
|
||||||
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
||||||
}
|
}
|
||||||
readsize = ret;
|
readsize = ret;
|
||||||
|
@ -686,20 +688,22 @@ gst_filesrc_get_read (GstFileSrc * src)
|
||||||
return GST_DATA (buf);
|
return GST_DATA (buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstData *
|
static GstFlowReturn
|
||||||
gst_filesrc_get (GstPad * pad)
|
gst_filesrc_get (GstPad * pad, GstBuffer ** buffer)
|
||||||
{
|
{
|
||||||
GstFileSrc *src;
|
GstFileSrc *src;
|
||||||
|
GstData *data;
|
||||||
|
|
||||||
g_return_val_if_fail (pad != NULL, NULL);
|
|
||||||
src = GST_FILESRC (gst_pad_get_parent (pad));
|
src = GST_FILESRC (gst_pad_get_parent (pad));
|
||||||
g_return_val_if_fail (GST_FLAG_IS_SET (src, GST_FILESRC_OPEN), NULL);
|
|
||||||
|
g_return_val_if_fail (GST_FLAG_IS_SET (src, GST_FILESRC_OPEN),
|
||||||
|
GST_FLOW_WRONG_STATE);
|
||||||
|
|
||||||
/* check for flush */
|
/* check for flush */
|
||||||
if (src->need_flush) {
|
if (src->need_flush) {
|
||||||
src->need_flush = FALSE;
|
src->need_flush = FALSE;
|
||||||
GST_DEBUG_OBJECT (src, "sending flush");
|
GST_DEBUG_OBJECT (src, "sending flush");
|
||||||
return GST_DATA (gst_event_new_flush ());
|
gst_pad_push_event (pad, gst_event_new_flush ());
|
||||||
}
|
}
|
||||||
/* check for seek */
|
/* check for seek */
|
||||||
if (src->need_discont) {
|
if (src->need_discont) {
|
||||||
|
@ -710,7 +714,7 @@ gst_filesrc_get (GstPad * pad)
|
||||||
gst_event_new_discontinuous (src->need_discont > 1, GST_FORMAT_BYTES,
|
gst_event_new_discontinuous (src->need_discont > 1, GST_FORMAT_BYTES,
|
||||||
(guint64) src->curoffset, GST_FORMAT_UNDEFINED);
|
(guint64) src->curoffset, GST_FORMAT_UNDEFINED);
|
||||||
src->need_discont = 0;
|
src->need_discont = 0;
|
||||||
return GST_DATA (event);
|
gst_pad_push_event (pad, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check for EOF if it's a regular file */
|
/* check for EOF if it's a regular file */
|
||||||
|
@ -721,20 +725,31 @@ gst_filesrc_get (GstPad * pad)
|
||||||
GST_DEBUG_OBJECT (src, "eos %" G_GINT64_FORMAT " %" G_GINT64_FORMAT,
|
GST_DEBUG_OBJECT (src, "eos %" G_GINT64_FORMAT " %" G_GINT64_FORMAT,
|
||||||
src->curoffset, src->filelen);
|
src->curoffset, src->filelen);
|
||||||
}
|
}
|
||||||
gst_element_set_eos (GST_ELEMENT (src));
|
//gst_element_set_eos (GST_ELEMENT (src));
|
||||||
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||||
|
return GST_FLOW_WRONG_STATE;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef HAVE_MMAP
|
#ifdef HAVE_MMAP
|
||||||
if (src->using_mmap) {
|
if (src->using_mmap) {
|
||||||
return gst_filesrc_get_mmap (src);
|
data = gst_filesrc_get_mmap (src);
|
||||||
} else {
|
} else {
|
||||||
return gst_filesrc_get_read (src);
|
data = gst_filesrc_get_read (src);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
return gst_filesrc_get_read (src);
|
data = gst_filesrc_get_read (src);
|
||||||
#endif
|
#endif
|
||||||
|
if (data == NULL)
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
|
||||||
|
if (GST_IS_EVENT (data)) {
|
||||||
|
gst_pad_push_event (pad, GST_EVENT (data));
|
||||||
|
} else {
|
||||||
|
*buffer = GST_BUFFER (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TRUE if the filesize of the file was updated */
|
/* TRUE if the filesize of the file was updated */
|
||||||
|
@ -848,10 +863,69 @@ gst_filesrc_close_file (GstFileSrc * src)
|
||||||
GST_FLAG_UNSET (src, GST_FILESRC_OPEN);
|
GST_FLAG_UNSET (src, GST_FILESRC_OPEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_filesrc_loop (GstElement * element)
|
||||||
|
{
|
||||||
|
GstFileSrc *filesrc;
|
||||||
|
GstFlowReturn result;
|
||||||
|
GstBuffer *buffer;
|
||||||
|
|
||||||
|
filesrc = GST_FILESRC (element);
|
||||||
|
|
||||||
|
result = gst_filesrc_get (filesrc->srcpad, &buffer);
|
||||||
|
if (result != GST_FLOW_OK) {
|
||||||
|
gst_task_stop (filesrc->task);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
result = gst_pad_push (filesrc->srcpad, buffer);
|
||||||
|
if (result != GST_FLOW_OK) {
|
||||||
|
gst_task_stop (filesrc->task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_filesrc_activate (GstPad * pad, gboolean active)
|
||||||
|
{
|
||||||
|
gboolean result = FALSE;
|
||||||
|
GstFileSrc *filesrc;
|
||||||
|
|
||||||
|
filesrc = GST_FILESRC (GST_OBJECT_PARENT (pad));
|
||||||
|
|
||||||
|
if (active) {
|
||||||
|
/* try to start the task */
|
||||||
|
GST_STREAM_LOCK (pad);
|
||||||
|
filesrc->task = gst_element_create_task (GST_ELEMENT (filesrc),
|
||||||
|
(GstTaskFunction) gst_filesrc_loop, filesrc);
|
||||||
|
|
||||||
|
if (filesrc->task) {
|
||||||
|
gst_task_start (filesrc->task);
|
||||||
|
result = TRUE;
|
||||||
|
} else {
|
||||||
|
result = FALSE;
|
||||||
|
}
|
||||||
|
GST_STREAM_UNLOCK (pad);
|
||||||
|
} else {
|
||||||
|
/* step 1, unblock clock sync (if any) */
|
||||||
|
|
||||||
|
/* step 2, make sure streaming finishes */
|
||||||
|
GST_STREAM_LOCK (pad);
|
||||||
|
/* step 3, stop the task */
|
||||||
|
gst_task_stop (filesrc->task);
|
||||||
|
gst_object_unref (GST_OBJECT (filesrc->task));
|
||||||
|
GST_STREAM_UNLOCK (pad);
|
||||||
|
|
||||||
|
result = TRUE;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static GstElementStateReturn
|
static GstElementStateReturn
|
||||||
gst_filesrc_change_state (GstElement * element)
|
gst_filesrc_change_state (GstElement * element)
|
||||||
{
|
{
|
||||||
|
GstElementStateReturn result = GST_STATE_SUCCESS;
|
||||||
|
|
||||||
GstFileSrc *src = GST_FILESRC (element);
|
GstFileSrc *src = GST_FILESRC (element);
|
||||||
|
|
||||||
switch (GST_STATE_TRANSITION (element)) {
|
switch (GST_STATE_TRANSITION (element)) {
|
||||||
|
@ -865,6 +939,16 @@ gst_filesrc_change_state (GstElement * element)
|
||||||
return GST_STATE_FAILURE;
|
return GST_STATE_FAILURE;
|
||||||
}
|
}
|
||||||
src->need_discont = 2;
|
src->need_discont = 2;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case GST_STATE_PAUSED_TO_PLAYING:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||||
|
|
||||||
|
switch (GST_STATE_TRANSITION (element)) {
|
||||||
|
case GST_STATE_PLAYING_TO_PAUSED:
|
||||||
break;
|
break;
|
||||||
case GST_STATE_PAUSED_TO_READY:
|
case GST_STATE_PAUSED_TO_READY:
|
||||||
if (GST_FLAG_IS_SET (element, GST_FILESRC_OPEN))
|
if (GST_FLAG_IS_SET (element, GST_FILESRC_OPEN))
|
||||||
|
@ -874,10 +958,7 @@ gst_filesrc_change_state (GstElement * element)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
return result;
|
||||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
|
||||||
|
|
||||||
return GST_STATE_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
|
|
@ -69,6 +69,8 @@ struct _GstFileSrc {
|
||||||
gboolean is_regular; /* whether it's (symlink to)
|
gboolean is_regular; /* whether it's (symlink to)
|
||||||
a regular file */
|
a regular file */
|
||||||
|
|
||||||
|
GstTask *task;
|
||||||
|
|
||||||
GstBuffer *mapbuf;
|
GstBuffer *mapbuf;
|
||||||
size_t mapsize;
|
size_t mapsize;
|
||||||
|
|
||||||
|
|
|
@ -99,7 +99,8 @@ static void gst_identity_get_property (GObject * object, guint prop_id,
|
||||||
GValue * value, GParamSpec * pspec);
|
GValue * value, GParamSpec * pspec);
|
||||||
static GstElementStateReturn gst_identity_change_state (GstElement * element);
|
static GstElementStateReturn gst_identity_change_state (GstElement * element);
|
||||||
|
|
||||||
static void gst_identity_chain (GstPad * pad, GstData * _data);
|
static gboolean gst_identity_event (GstPad * pad, GstEvent * event);
|
||||||
|
static GstFlowReturn gst_identity_chain (GstPad * pad, GstBuffer * buffer);
|
||||||
static void gst_identity_set_clock (GstElement * element, GstClock * clock);
|
static void gst_identity_set_clock (GstElement * element, GstClock * clock);
|
||||||
|
|
||||||
|
|
||||||
|
@ -138,6 +139,9 @@ gst_identity_class_init (GstIdentityClass * klass)
|
||||||
gobject_class = G_OBJECT_CLASS (klass);
|
gobject_class = G_OBJECT_CLASS (klass);
|
||||||
gstelement_class = GST_ELEMENT_CLASS (klass);
|
gstelement_class = GST_ELEMENT_CLASS (klass);
|
||||||
|
|
||||||
|
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_identity_set_property);
|
||||||
|
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_identity_get_property);
|
||||||
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOOP_BASED,
|
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOOP_BASED,
|
||||||
g_param_spec_boolean ("loop-based", "Loop-based",
|
g_param_spec_boolean ("loop-based", "Loop-based",
|
||||||
"Set to TRUE to use loop-based rather than chain-based scheduling",
|
"Set to TRUE to use loop-based rather than chain-based scheduling",
|
||||||
|
@ -185,8 +189,6 @@ gst_identity_class_init (GstIdentityClass * klass)
|
||||||
GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE);
|
GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE);
|
||||||
|
|
||||||
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_identity_finalize);
|
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_identity_finalize);
|
||||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_identity_set_property);
|
|
||||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_identity_get_property);
|
|
||||||
|
|
||||||
gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_identity_set_clock);
|
gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_identity_set_clock);
|
||||||
gstelement_class->change_state =
|
gstelement_class->change_state =
|
||||||
|
@ -203,15 +205,13 @@ gst_identity_init (GstIdentity * identity)
|
||||||
gst_element_add_pad (GST_ELEMENT (identity), identity->sinkpad);
|
gst_element_add_pad (GST_ELEMENT (identity), identity->sinkpad);
|
||||||
gst_pad_set_chain_function (identity->sinkpad,
|
gst_pad_set_chain_function (identity->sinkpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_identity_chain));
|
GST_DEBUG_FUNCPTR (gst_identity_chain));
|
||||||
gst_pad_set_link_function (identity->sinkpad, gst_pad_proxy_pad_link);
|
gst_pad_set_event_function (identity->sinkpad,
|
||||||
gst_pad_set_getcaps_function (identity->sinkpad, gst_pad_proxy_getcaps);
|
GST_DEBUG_FUNCPTR (gst_identity_event));
|
||||||
|
|
||||||
identity->srcpad =
|
identity->srcpad =
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
|
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
|
||||||
"src");
|
"src");
|
||||||
gst_element_add_pad (GST_ELEMENT (identity), identity->srcpad);
|
gst_element_add_pad (GST_ELEMENT (identity), identity->srcpad);
|
||||||
gst_pad_set_link_function (identity->srcpad, gst_pad_proxy_pad_link);
|
|
||||||
gst_pad_set_getcaps_function (identity->srcpad, gst_pad_proxy_getcaps);
|
|
||||||
|
|
||||||
identity->loop_based = DEFAULT_LOOP_BASED;
|
identity->loop_based = DEFAULT_LOOP_BASED;
|
||||||
identity->sleep_time = DEFAULT_SLEEP_TIME;
|
identity->sleep_time = DEFAULT_SLEEP_TIME;
|
||||||
|
@ -225,8 +225,6 @@ gst_identity_init (GstIdentity * identity)
|
||||||
identity->dump = DEFAULT_DUMP;
|
identity->dump = DEFAULT_DUMP;
|
||||||
identity->last_message = NULL;
|
identity->last_message = NULL;
|
||||||
identity->srccaps = NULL;
|
identity->srccaps = NULL;
|
||||||
|
|
||||||
GST_FLAG_SET (identity, GST_ELEMENT_EVENT_AWARE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -237,35 +235,37 @@ gst_identity_set_clock (GstElement * element, GstClock * clock)
|
||||||
gst_object_replace ((GstObject **) & identity->clock, (GstObject *) clock);
|
gst_object_replace ((GstObject **) & identity->clock, (GstObject *) clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
static void
|
gst_identity_event (GstPad * pad, GstEvent * event)
|
||||||
gst_identity_chain (GstPad * pad, GstData * _data)
|
|
||||||
{
|
{
|
||||||
GstBuffer *buf = GST_BUFFER (_data);
|
|
||||||
GstIdentity *identity;
|
GstIdentity *identity;
|
||||||
guint i;
|
|
||||||
|
|
||||||
g_return_if_fail (pad != NULL);
|
|
||||||
g_return_if_fail (GST_IS_PAD (pad));
|
|
||||||
g_return_if_fail (buf != NULL);
|
|
||||||
|
|
||||||
identity = GST_IDENTITY (gst_pad_get_parent (pad));
|
identity = GST_IDENTITY (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
if (GST_IS_EVENT (buf)) {
|
if (!identity->silent) {
|
||||||
GstEvent *event = GST_EVENT (buf);
|
g_free (identity->last_message);
|
||||||
|
|
||||||
if (!identity->silent) {
|
identity->last_message =
|
||||||
g_free (identity->last_message);
|
g_strdup_printf ("chain ******* (%s:%s)E (type: %d) %p",
|
||||||
|
GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event);
|
||||||
|
|
||||||
identity->last_message =
|
g_object_notify (G_OBJECT (identity), "last_message");
|
||||||
g_strdup_printf ("chain ******* (%s:%s)E (type: %d) %p",
|
|
||||||
GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event);
|
|
||||||
|
|
||||||
g_object_notify (G_OBJECT (identity), "last_message");
|
|
||||||
}
|
|
||||||
gst_pad_event_default (pad, event);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
return gst_pad_push_event (identity->srcpad, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_identity_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
|
{
|
||||||
|
GstBuffer *buf = GST_BUFFER (buffer);
|
||||||
|
GstIdentity *identity;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
g_return_val_if_fail (pad != NULL, GST_FLOW_ERROR);
|
||||||
|
g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR);
|
||||||
|
g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
|
||||||
|
|
||||||
|
identity = GST_IDENTITY (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
/* see if we need to do perfect stream checking */
|
/* see if we need to do perfect stream checking */
|
||||||
/* invalid timestamp drops us out of check. FIXME: maybe warn ? */
|
/* invalid timestamp drops us out of check. FIXME: maybe warn ? */
|
||||||
|
@ -302,7 +302,7 @@ gst_identity_chain (GstPad * pad, GstData * _data)
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
GST_ELEMENT_ERROR (identity, CORE, FAILED,
|
GST_ELEMENT_ERROR (identity, CORE, FAILED,
|
||||||
(_("Failed after iterations as requested.")), (NULL));
|
(_("Failed after iterations as requested.")), (NULL));
|
||||||
return;
|
return GST_FLOW_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,7 +319,7 @@ gst_identity_chain (GstPad * pad, GstData * _data)
|
||||||
GST_BUFFER_OFFSET_END (buf), GST_BUFFER_FLAGS (buf), buf);
|
GST_BUFFER_OFFSET_END (buf), GST_BUFFER_FLAGS (buf), buf);
|
||||||
g_object_notify (G_OBJECT (identity), "last-message");
|
g_object_notify (G_OBJECT (identity), "last-message");
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
return;
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (identity->dump) {
|
if (identity->dump) {
|
||||||
|
@ -365,37 +365,33 @@ gst_identity_chain (GstPad * pad, GstData * _data)
|
||||||
}
|
}
|
||||||
|
|
||||||
identity->bytes_handled += GST_BUFFER_SIZE (buf);
|
identity->bytes_handled += GST_BUFFER_SIZE (buf);
|
||||||
gst_pad_push (identity->srcpad, GST_DATA (buf));
|
gst_pad_push (identity->srcpad, buf);
|
||||||
|
|
||||||
if (identity->sleep_time)
|
if (identity->sleep_time)
|
||||||
g_usleep (identity->sleep_time);
|
g_usleep (identity->sleep_time);
|
||||||
}
|
}
|
||||||
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
static void
|
static void
|
||||||
gst_identity_loop (GstElement * element)
|
gst_identity_loop (GstElement * element)
|
||||||
{
|
{
|
||||||
GstIdentity *identity;
|
GstIdentity *identity;
|
||||||
GstBuffer *buf;
|
GstBuffer *buf;
|
||||||
|
GstFlowReturn ret;
|
||||||
|
|
||||||
g_return_if_fail (element != NULL);
|
g_return_if_fail (element != NULL);
|
||||||
g_return_if_fail (GST_IS_IDENTITY (element));
|
g_return_if_fail (GST_IS_IDENTITY (element));
|
||||||
|
|
||||||
identity = GST_IDENTITY (element);
|
identity = GST_IDENTITY (element);
|
||||||
|
|
||||||
buf = GST_BUFFER (gst_pad_pull (identity->sinkpad));
|
ret = gst_pad_pull (identity->sinkpad, &buf);
|
||||||
if (GST_IS_EVENT (buf)) {
|
if (ret == GST_FLOW_OK) {
|
||||||
GstEvent *event = GST_EVENT (buf);
|
gst_identity_chain (identity->sinkpad, buf);
|
||||||
|
|
||||||
if (GST_EVENT_IS_INTERRUPT (event)) {
|
|
||||||
gst_event_unref (event);
|
|
||||||
} else {
|
|
||||||
gst_pad_event_default (identity->sinkpad, event);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
gst_identity_chain (identity->sinkpad, GST_DATA (buf));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_identity_set_property (GObject * object, guint prop_id,
|
gst_identity_set_property (GObject * object, guint prop_id,
|
||||||
|
@ -412,12 +408,9 @@ gst_identity_set_property (GObject * object, guint prop_id,
|
||||||
case ARG_LOOP_BASED:
|
case ARG_LOOP_BASED:
|
||||||
identity->loop_based = g_value_get_boolean (value);
|
identity->loop_based = g_value_get_boolean (value);
|
||||||
if (identity->loop_based) {
|
if (identity->loop_based) {
|
||||||
gst_element_set_loop_function (GST_ELEMENT (identity),
|
|
||||||
gst_identity_loop);
|
|
||||||
gst_pad_set_chain_function (identity->sinkpad, NULL);
|
gst_pad_set_chain_function (identity->sinkpad, NULL);
|
||||||
} else {
|
} else {
|
||||||
gst_pad_set_chain_function (identity->sinkpad, gst_identity_chain);
|
gst_pad_set_chain_function (identity->sinkpad, gst_identity_chain);
|
||||||
gst_element_set_loop_function (GST_ELEMENT (identity), NULL);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ARG_SLEEP_TIME:
|
case ARG_SLEEP_TIME:
|
||||||
|
|
50
gst/gst.c
50
gst/gst.c
|
@ -535,9 +535,8 @@ gst_register_core_elements (GstPlugin * plugin)
|
||||||
GST_TYPE_BIN) ||
|
GST_TYPE_BIN) ||
|
||||||
!gst_element_register (plugin, "pipeline", GST_RANK_PRIMARY,
|
!gst_element_register (plugin, "pipeline", GST_RANK_PRIMARY,
|
||||||
GST_TYPE_PIPELINE) ||
|
GST_TYPE_PIPELINE) ||
|
||||||
!gst_element_register (plugin, "thread", GST_RANK_PRIMARY,
|
!gst_element_register (plugin, "queue", GST_RANK_NONE, GST_TYPE_QUEUE)
|
||||||
GST_TYPE_THREAD) ||
|
)
|
||||||
!gst_element_register (plugin, "queue", GST_RANK_NONE, GST_TYPE_QUEUE))
|
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -616,6 +615,7 @@ init_post (void)
|
||||||
_gst_plugin_initialize ();
|
_gst_plugin_initialize ();
|
||||||
_gst_event_initialize ();
|
_gst_event_initialize ();
|
||||||
_gst_buffer_initialize ();
|
_gst_buffer_initialize ();
|
||||||
|
_gst_message_initialize ();
|
||||||
_gst_tag_initialize ();
|
_gst_tag_initialize ();
|
||||||
|
|
||||||
#ifndef GST_DISABLE_REGISTRY
|
#ifndef GST_DISABLE_REGISTRY
|
||||||
|
@ -840,50 +840,6 @@ gst_has_threads (void)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static GSList *mainloops = NULL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_main:
|
|
||||||
*
|
|
||||||
* Enters the main GStreamer processing loop.
|
|
||||||
*
|
|
||||||
* This function duplicates functionality in glib, and will be removed
|
|
||||||
* during the 0.9 development series.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
gst_main (void)
|
|
||||||
{
|
|
||||||
GMainLoop *loop;
|
|
||||||
|
|
||||||
loop = g_main_loop_new (NULL, FALSE);
|
|
||||||
mainloops = g_slist_prepend (mainloops, loop);
|
|
||||||
|
|
||||||
g_main_loop_run (loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_main_quit:
|
|
||||||
*
|
|
||||||
* Exits the main GStreamer processing loop.
|
|
||||||
*
|
|
||||||
* This function duplicates functionality in glib, and will be removed
|
|
||||||
* during the 0.9 development series.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
gst_main_quit (void)
|
|
||||||
{
|
|
||||||
if (!mainloops)
|
|
||||||
g_error ("Quit more loops than there are");
|
|
||||||
else {
|
|
||||||
GMainLoop *loop = mainloops->data;
|
|
||||||
|
|
||||||
mainloops = g_slist_delete_link (mainloops, mainloops);
|
|
||||||
g_main_loop_quit (loop);
|
|
||||||
g_main_loop_unref (loop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_version:
|
* gst_version:
|
||||||
* @major: pointer to a guint to store the major version number
|
* @major: pointer to a guint to store the major version number
|
||||||
|
|
|
@ -42,7 +42,9 @@
|
||||||
#include <gst/gstindex.h>
|
#include <gst/gstindex.h>
|
||||||
#include <gst/gstinfo.h>
|
#include <gst/gstinfo.h>
|
||||||
#include <gst/gstinterface.h>
|
#include <gst/gstinterface.h>
|
||||||
|
#include <gst/gstiterator.h>
|
||||||
#include <gst/gstmarshal.h>
|
#include <gst/gstmarshal.h>
|
||||||
|
#include <gst/gstmessage.h>
|
||||||
#include <gst/gstobject.h>
|
#include <gst/gstobject.h>
|
||||||
#include <gst/gstpad.h>
|
#include <gst/gstpad.h>
|
||||||
#include <gst/gstpipeline.h>
|
#include <gst/gstpipeline.h>
|
||||||
|
@ -52,7 +54,7 @@
|
||||||
#include <gst/gstsystemclock.h>
|
#include <gst/gstsystemclock.h>
|
||||||
#include <gst/gsttag.h>
|
#include <gst/gsttag.h>
|
||||||
#include <gst/gsttaginterface.h>
|
#include <gst/gsttaginterface.h>
|
||||||
#include <gst/gstthread.h>
|
#include <gst/gsttask.h>
|
||||||
#include <gst/gsttrace.h>
|
#include <gst/gsttrace.h>
|
||||||
#include <gst/gsttypefind.h>
|
#include <gst/gsttypefind.h>
|
||||||
#include <gst/gsturi.h>
|
#include <gst/gsturi.h>
|
||||||
|
|
|
@ -69,6 +69,7 @@ extern GstDebugCategory *GST_CAT_NEGOTIATION;
|
||||||
extern GstDebugCategory *GST_CAT_REFCOUNTING;
|
extern GstDebugCategory *GST_CAT_REFCOUNTING;
|
||||||
extern GstDebugCategory *GST_CAT_ERROR_SYSTEM;
|
extern GstDebugCategory *GST_CAT_ERROR_SYSTEM;
|
||||||
extern GstDebugCategory *GST_CAT_EVENT;
|
extern GstDebugCategory *GST_CAT_EVENT;
|
||||||
|
extern GstDebugCategory *GST_CAT_MESSAGE;
|
||||||
extern GstDebugCategory *GST_CAT_PARAMS;
|
extern GstDebugCategory *GST_CAT_PARAMS;
|
||||||
extern GstDebugCategory *GST_CAT_CALL_TRACE;
|
extern GstDebugCategory *GST_CAT_CALL_TRACE;
|
||||||
|
|
||||||
|
@ -99,6 +100,7 @@ extern GstDebugCategory *GST_CAT_CALL_TRACE;
|
||||||
#define GST_CAT_REFCOUNTING NULL
|
#define GST_CAT_REFCOUNTING NULL
|
||||||
#define GST_CAT_ERROR_SYSTEM NULL
|
#define GST_CAT_ERROR_SYSTEM NULL
|
||||||
#define GST_CAT_EVENT NULL
|
#define GST_CAT_EVENT NULL
|
||||||
|
#define GST_CAT_MESSAGE NULL
|
||||||
#define GST_CAT_PARAMS NULL
|
#define GST_CAT_PARAMS NULL
|
||||||
#define GST_CAT_CALL_TRACE NULL
|
#define GST_CAT_CALL_TRACE NULL
|
||||||
|
|
||||||
|
|
1085
gst/gstbin.c
1085
gst/gstbin.c
File diff suppressed because it is too large
Load diff
48
gst/gstbin.h
48
gst/gstbin.h
|
@ -25,6 +25,7 @@
|
||||||
#define __GST_BIN_H__
|
#define __GST_BIN_H__
|
||||||
|
|
||||||
#include <gst/gstelement.h>
|
#include <gst/gstelement.h>
|
||||||
|
#include <gst/gstiterator.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
@ -38,15 +39,6 @@ GST_EXPORT GType _gst_bin_type;
|
||||||
#define GST_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_BIN, GstBinClass))
|
#define GST_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_BIN, GstBinClass))
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/* this bin is a manager of child elements, i.e. a pipeline or thread */
|
|
||||||
GST_BIN_FLAG_MANAGER = GST_ELEMENT_FLAG_LAST,
|
|
||||||
|
|
||||||
/* this bin iterates itself */
|
|
||||||
GST_BIN_SELF_SCHEDULABLE,
|
|
||||||
|
|
||||||
/* we prefer to have cothreads when its an option, over chain-based */
|
|
||||||
GST_BIN_FLAG_PREFER_COTHREADS,
|
|
||||||
|
|
||||||
GST_BIN_FLAG_FIXED_CLOCK,
|
GST_BIN_FLAG_FIXED_CLOCK,
|
||||||
|
|
||||||
/* padding */
|
/* padding */
|
||||||
|
@ -62,8 +54,7 @@ struct _GstBin {
|
||||||
/* our children */
|
/* our children */
|
||||||
gint numchildren;
|
gint numchildren;
|
||||||
GList *children;
|
GList *children;
|
||||||
|
guint32 children_cookie;
|
||||||
GstElementState child_states[GST_NUM_STATES];
|
|
||||||
|
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
gpointer _gst_reserved[GST_PADDING];
|
||||||
};
|
};
|
||||||
|
@ -74,11 +65,7 @@ struct _GstBinClass {
|
||||||
/* vtable */
|
/* vtable */
|
||||||
void (*add_element) (GstBin *bin, GstElement *element);
|
void (*add_element) (GstBin *bin, GstElement *element);
|
||||||
void (*remove_element) (GstBin *bin, GstElement *element);
|
void (*remove_element) (GstBin *bin, GstElement *element);
|
||||||
void (*child_state_change) (GstBin *bin, GstElementState oldstate,
|
GstIterator* (*iterate_elements) (GstBin *bin);
|
||||||
GstElementState newstate, GstElement *element);
|
|
||||||
|
|
||||||
/* run a full iteration of operation */
|
|
||||||
gboolean (*iterate) (GstBin *bin);
|
|
||||||
|
|
||||||
/* signals */
|
/* signals */
|
||||||
void (*element_added) (GstBin *bin, GstElement *child);
|
void (*element_added) (GstBin *bin, GstElement *child);
|
||||||
|
@ -92,30 +79,17 @@ GstElement* gst_bin_new (const gchar *name);
|
||||||
|
|
||||||
/* add and remove elements from the bin */
|
/* add and remove elements from the bin */
|
||||||
void gst_bin_add (GstBin *bin, GstElement *element);
|
void gst_bin_add (GstBin *bin, GstElement *element);
|
||||||
void gst_bin_add_many (GstBin *bin, GstElement *element_1, ...);
|
|
||||||
void gst_bin_remove (GstBin *bin, GstElement *element);
|
void gst_bin_remove (GstBin *bin, GstElement *element);
|
||||||
void gst_bin_remove_many (GstBin *bin, GstElement *element_1, ...);
|
|
||||||
|
|
||||||
/* retrieve a single element or the list of children */
|
/* retrieve a single child */
|
||||||
GstElement* gst_bin_get_by_name (GstBin *bin, const gchar *name);
|
GstElement* gst_bin_get_by_name (GstBin *bin, const gchar *name);
|
||||||
GstElement* gst_bin_get_by_name_recurse_up (GstBin *bin, const gchar *name);
|
GstElement* gst_bin_get_by_name_recurse_up (GstBin *bin, const gchar *name);
|
||||||
G_CONST_RETURN GList*
|
GstElement* gst_bin_get_by_interface (GstBin *bin, GType interface);
|
||||||
gst_bin_get_list (GstBin *bin);
|
|
||||||
GstElement* gst_bin_get_by_interface (GstBin *bin, GType interface);
|
|
||||||
GList * gst_bin_get_all_by_interface (GstBin *bin, GType interface);
|
|
||||||
|
|
||||||
gboolean gst_bin_iterate (GstBin *bin);
|
/* retrieve multiple children */
|
||||||
|
GstIterator* gst_bin_iterate_elements (GstBin *bin);
|
||||||
void gst_bin_use_clock (GstBin *bin, GstClock *clock);
|
GstIterator* gst_bin_iterate_sinks (GstBin *bin);
|
||||||
GstClock* gst_bin_get_clock (GstBin *bin);
|
GstIterator* gst_bin_iterate_all_by_interface (GstBin *bin, GType interface);
|
||||||
void gst_bin_auto_clock (GstBin *bin);
|
|
||||||
|
|
||||||
GstElementStateReturn gst_bin_sync_children_state (GstBin *bin);
|
|
||||||
|
|
||||||
/* internal */
|
|
||||||
/* one of our childs signaled a state change */
|
|
||||||
void gst_bin_child_state_change (GstBin *bin, GstElementState oldstate,
|
|
||||||
GstElementState newstate, GstElement *child);
|
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
|
117
gst/gstbuffer.c
117
gst/gstbuffer.c
|
@ -74,6 +74,8 @@ _gst_buffer_sub_free (GstBuffer * buffer)
|
||||||
|
|
||||||
GST_BUFFER_DATA (buffer) = NULL;
|
GST_BUFFER_DATA (buffer) = NULL;
|
||||||
GST_BUFFER_SIZE (buffer) = 0;
|
GST_BUFFER_SIZE (buffer) = 0;
|
||||||
|
if (GST_BUFFER_CAPS (buffer))
|
||||||
|
gst_caps_unref (GST_BUFFER_CAPS (buffer));
|
||||||
|
|
||||||
_GST_DATA_DISPOSE (GST_DATA (buffer));
|
_GST_DATA_DISPOSE (GST_DATA (buffer));
|
||||||
|
|
||||||
|
@ -102,37 +104,21 @@ gst_buffer_default_free (GstBuffer * buffer)
|
||||||
/* set to safe values */
|
/* set to safe values */
|
||||||
GST_BUFFER_DATA (buffer) = NULL;
|
GST_BUFFER_DATA (buffer) = NULL;
|
||||||
GST_BUFFER_SIZE (buffer) = 0;
|
GST_BUFFER_SIZE (buffer) = 0;
|
||||||
|
if (GST_BUFFER_CAPS (buffer))
|
||||||
|
gst_caps_unref (GST_BUFFER_CAPS (buffer));
|
||||||
|
|
||||||
_GST_DATA_DISPOSE (GST_DATA (buffer));
|
_GST_DATA_DISPOSE (GST_DATA (buffer));
|
||||||
|
|
||||||
gst_buffer_free_chunk (buffer);
|
gst_buffer_free_chunk (buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_buffer_stamp:
|
|
||||||
* @dest: buffer to stamp
|
|
||||||
* @src: buffer to stamp from
|
|
||||||
*
|
|
||||||
* Copies additional information (timestamps and offsets) from one buffer to
|
|
||||||
* the other.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
gst_buffer_stamp (GstBuffer * dest, const GstBuffer * src)
|
|
||||||
{
|
|
||||||
g_return_if_fail (dest != NULL);
|
|
||||||
g_return_if_fail (src != NULL);
|
|
||||||
|
|
||||||
GST_BUFFER_TIMESTAMP (dest) = GST_BUFFER_TIMESTAMP (src);
|
|
||||||
GST_BUFFER_DURATION (dest) = GST_BUFFER_DURATION (src);
|
|
||||||
GST_BUFFER_OFFSET (dest) = GST_BUFFER_OFFSET (src);
|
|
||||||
GST_BUFFER_OFFSET_END (dest) = GST_BUFFER_OFFSET_END (src);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_buffer_default_copy:
|
* gst_buffer_default_copy:
|
||||||
* @buffer: a #GstBuffer to make a copy of.
|
* @buffer: a #GstBuffer to make a copy of.
|
||||||
*
|
*
|
||||||
* Make a full newly allocated copy of the given buffer, data and all.
|
* Make a full newly allocated copy of the given buffer, data and all.
|
||||||
|
* Note that the caps on the buffer are not copied but their refcount
|
||||||
|
* is increased.
|
||||||
*
|
*
|
||||||
* Returns: the new #GstBuffer.
|
* Returns: the new #GstBuffer.
|
||||||
*/
|
*/
|
||||||
|
@ -147,6 +133,8 @@ gst_buffer_default_copy (GstBuffer * buffer)
|
||||||
/* create a fresh new buffer */
|
/* create a fresh new buffer */
|
||||||
copy = gst_buffer_alloc_chunk ();
|
copy = gst_buffer_alloc_chunk ();
|
||||||
|
|
||||||
|
GST_CAT_LOG (GST_CAT_BUFFER, "copy %p to %p", buffer, copy);
|
||||||
|
|
||||||
/* copy relevant flags */
|
/* copy relevant flags */
|
||||||
flags = GST_DATA_FLAG_SHIFT (GST_BUFFER_KEY_UNIT) |
|
flags = GST_DATA_FLAG_SHIFT (GST_BUFFER_KEY_UNIT) |
|
||||||
GST_DATA_FLAG_SHIFT (GST_BUFFER_IN_CAPS) |
|
GST_DATA_FLAG_SHIFT (GST_BUFFER_IN_CAPS) |
|
||||||
|
@ -165,9 +153,15 @@ gst_buffer_default_copy (GstBuffer * buffer)
|
||||||
GST_BUFFER_SIZE (copy) = GST_BUFFER_SIZE (buffer);
|
GST_BUFFER_SIZE (copy) = GST_BUFFER_SIZE (buffer);
|
||||||
GST_BUFFER_MAXSIZE (copy) = GST_BUFFER_SIZE (buffer);
|
GST_BUFFER_MAXSIZE (copy) = GST_BUFFER_SIZE (buffer);
|
||||||
|
|
||||||
gst_buffer_stamp (copy, buffer);
|
GST_BUFFER_TIMESTAMP (copy) = GST_BUFFER_TIMESTAMP (buffer);
|
||||||
|
GST_BUFFER_DURATION (copy) = GST_BUFFER_DURATION (buffer);
|
||||||
|
GST_BUFFER_OFFSET (copy) = GST_BUFFER_OFFSET (buffer);
|
||||||
|
GST_BUFFER_OFFSET_END (copy) = GST_BUFFER_OFFSET_END (buffer);
|
||||||
|
|
||||||
GST_BUFFER_FREE_DATA_FUNC (copy) = NULL;
|
GST_BUFFER_FREE_DATA_FUNC (copy) = NULL;
|
||||||
GST_BUFFER_PRIVATE (copy) = NULL;
|
GST_BUFFER_PRIVATE (copy) = NULL;
|
||||||
|
if (GST_BUFFER_CAPS (buffer))
|
||||||
|
GST_BUFFER_CAPS (copy) = gst_caps_ref (GST_BUFFER_CAPS (buffer));
|
||||||
|
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
@ -225,6 +219,7 @@ gst_buffer_new (void)
|
||||||
GST_BUFFER_OFFSET_END (newbuf) = GST_BUFFER_OFFSET_NONE;
|
GST_BUFFER_OFFSET_END (newbuf) = GST_BUFFER_OFFSET_NONE;
|
||||||
GST_BUFFER_FREE_DATA_FUNC (newbuf) = NULL;
|
GST_BUFFER_FREE_DATA_FUNC (newbuf) = NULL;
|
||||||
GST_BUFFER_PRIVATE (newbuf) = NULL;
|
GST_BUFFER_PRIVATE (newbuf) = NULL;
|
||||||
|
GST_BUFFER_CAPS (newbuf) = NULL;
|
||||||
|
|
||||||
return newbuf;
|
return newbuf;
|
||||||
}
|
}
|
||||||
|
@ -251,6 +246,52 @@ gst_buffer_new_and_alloc (guint size)
|
||||||
return newbuf;
|
return newbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_buffer_get_caps:
|
||||||
|
* @buffer: a #GstBuffer to get the caps of.
|
||||||
|
*
|
||||||
|
* Gets the media type of the buffer. This can be NULL if there
|
||||||
|
* is not media type attached to this buffer or when the media
|
||||||
|
* type is the same as the previous received buffer.
|
||||||
|
*
|
||||||
|
* Returns: the #GstCaps, or NULL if there was an error or there
|
||||||
|
* were no caps on this buffer.
|
||||||
|
*/
|
||||||
|
GstCaps *
|
||||||
|
gst_buffer_get_caps (GstBuffer * buffer)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (buffer != NULL, NULL);
|
||||||
|
|
||||||
|
return GST_BUFFER_CAPS (buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_buffer_set_caps:
|
||||||
|
* @buffer: a #GstBuffer to set the caps of.
|
||||||
|
* @caps: a #GstCaps to set.
|
||||||
|
*
|
||||||
|
* Sets the media type on the buffer. The caps' refcount will
|
||||||
|
* be increased and any previous caps on the buffer will be
|
||||||
|
* unreffed.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_buffer_set_caps (GstBuffer * buffer, GstCaps * caps)
|
||||||
|
{
|
||||||
|
g_return_if_fail (buffer != NULL);
|
||||||
|
|
||||||
|
/* unref old caps if any */
|
||||||
|
if (GST_BUFFER_CAPS (buffer)) {
|
||||||
|
gst_caps_unref (GST_BUFFER_CAPS (buffer));
|
||||||
|
}
|
||||||
|
/* ref new caps if any */
|
||||||
|
if (caps)
|
||||||
|
caps = gst_caps_ref (caps);
|
||||||
|
|
||||||
|
/* set caps */
|
||||||
|
GST_BUFFER_CAPS (buffer) = caps;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_buffer_create_sub:
|
* gst_buffer_create_sub:
|
||||||
* @parent: a parent #GstBuffer to create a subbuffer from.
|
* @parent: a parent #GstBuffer to create a subbuffer from.
|
||||||
|
@ -318,12 +359,10 @@ gst_buffer_create_sub (GstBuffer * parent, guint offset, guint size)
|
||||||
GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
|
GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
|
||||||
GST_BUFFER_OFFSET_END (buffer) = GST_BUFFER_OFFSET_NONE;
|
GST_BUFFER_OFFSET_END (buffer) = GST_BUFFER_OFFSET_NONE;
|
||||||
|
|
||||||
if (GST_BUFFER_FLAG_IS_SET (parent, GST_BUFFER_DONTKEEP)) {
|
|
||||||
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_DONTKEEP);
|
|
||||||
}
|
|
||||||
if (GST_BUFFER_FLAG_IS_SET (parent, GST_BUFFER_READONLY)) {
|
if (GST_BUFFER_FLAG_IS_SET (parent, GST_BUFFER_READONLY)) {
|
||||||
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_READONLY);
|
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_READONLY);
|
||||||
}
|
}
|
||||||
|
GST_BUFFER_CAPS (buffer) = NULL;
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
@ -338,9 +377,6 @@ gst_buffer_create_sub (GstBuffer * parent, guint offset, guint size)
|
||||||
* buffers. The original source buffers will not be modified or
|
* buffers. The original source buffers will not be modified or
|
||||||
* unref'd.
|
* unref'd.
|
||||||
*
|
*
|
||||||
* WARNING: Incorrect use of this function can lead to memory leaks.
|
|
||||||
* It is recommended to use gst_buffer_join() instead of this function.
|
|
||||||
*
|
|
||||||
* If the buffers point to contiguous areas of memory, the buffer
|
* If the buffers point to contiguous areas of memory, the buffer
|
||||||
* is created without copying the data.
|
* is created without copying the data.
|
||||||
*
|
*
|
||||||
|
@ -357,33 +393,6 @@ gst_buffer_merge (GstBuffer * buf1, GstBuffer * buf2)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_buffer_join:
|
|
||||||
* @buf1: a first source #GstBuffer to merge.
|
|
||||||
* @buf2: the second source #GstBuffer to merge.
|
|
||||||
*
|
|
||||||
* Create a new buffer that is the concatenation of the two source
|
|
||||||
* buffers. The original buffers are unreferenced.
|
|
||||||
*
|
|
||||||
* If the buffers point to contiguous areas of memory, the buffer
|
|
||||||
* is created without copying the data.
|
|
||||||
*
|
|
||||||
* Returns: the new #GstBuffer that's the concatenation of the source buffers.
|
|
||||||
*/
|
|
||||||
GstBuffer *
|
|
||||||
gst_buffer_join (GstBuffer * buf1, GstBuffer * buf2)
|
|
||||||
{
|
|
||||||
GstBuffer *result;
|
|
||||||
|
|
||||||
/* we're just a specific case of the more general gst_buffer_span() */
|
|
||||||
result = gst_buffer_span (buf1, 0, buf2, buf1->size + buf2->size);
|
|
||||||
|
|
||||||
gst_buffer_unref (buf1);
|
|
||||||
gst_buffer_unref (buf2);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_buffer_is_span_fast:
|
* gst_buffer_is_span_fast:
|
||||||
* @buf1: a first source #GstBuffer.
|
* @buf1: a first source #GstBuffer.
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include <gst/gstdata.h>
|
#include <gst/gstdata.h>
|
||||||
#include <gst/gstclock.h>
|
#include <gst/gstclock.h>
|
||||||
|
#include <gst/gstcaps.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
@ -44,10 +45,8 @@ extern GType _gst_buffer_type;
|
||||||
|
|
||||||
#define GST_BUFFER_REFCOUNT(buf) GST_DATA_REFCOUNT(buf)
|
#define GST_BUFFER_REFCOUNT(buf) GST_DATA_REFCOUNT(buf)
|
||||||
#define GST_BUFFER_REFCOUNT_VALUE(buf) GST_DATA_REFCOUNT_VALUE(buf)
|
#define GST_BUFFER_REFCOUNT_VALUE(buf) GST_DATA_REFCOUNT_VALUE(buf)
|
||||||
#ifndef GST_DISABLE_DEPRECATED
|
|
||||||
#define GST_BUFFER_COPY_FUNC(buf) GST_DATA_COPY_FUNC(buf)
|
#define GST_BUFFER_COPY_FUNC(buf) GST_DATA_COPY_FUNC(buf)
|
||||||
#define GST_BUFFER_FREE_FUNC(buf) GST_DATA_FREE_FUNC(buf)
|
#define GST_BUFFER_FREE_FUNC(buf) GST_DATA_FREE_FUNC(buf)
|
||||||
#endif
|
|
||||||
|
|
||||||
#define GST_BUFFER_FLAGS(buf) GST_DATA_FLAGS(buf)
|
#define GST_BUFFER_FLAGS(buf) GST_DATA_FLAGS(buf)
|
||||||
#define GST_BUFFER_FLAG_IS_SET(buf,flag) GST_DATA_FLAG_IS_SET (buf, flag)
|
#define GST_BUFFER_FLAG_IS_SET(buf,flag) GST_DATA_FLAG_IS_SET (buf, flag)
|
||||||
|
@ -59,6 +58,7 @@ extern GType _gst_buffer_type;
|
||||||
#define GST_BUFFER_MAXSIZE(buf) (GST_BUFFER(buf)->maxsize)
|
#define GST_BUFFER_MAXSIZE(buf) (GST_BUFFER(buf)->maxsize)
|
||||||
#define GST_BUFFER_TIMESTAMP(buf) (GST_BUFFER(buf)->timestamp)
|
#define GST_BUFFER_TIMESTAMP(buf) (GST_BUFFER(buf)->timestamp)
|
||||||
#define GST_BUFFER_DURATION(buf) (GST_BUFFER(buf)->duration)
|
#define GST_BUFFER_DURATION(buf) (GST_BUFFER(buf)->duration)
|
||||||
|
#define GST_BUFFER_CAPS(buf) (GST_BUFFER(buf)->caps)
|
||||||
#define GST_BUFFER_OFFSET(buf) (GST_BUFFER(buf)->offset)
|
#define GST_BUFFER_OFFSET(buf) (GST_BUFFER(buf)->offset)
|
||||||
#define GST_BUFFER_OFFSET_END(buf) (GST_BUFFER(buf)->offset_end)
|
#define GST_BUFFER_OFFSET_END(buf) (GST_BUFFER(buf)->offset_end)
|
||||||
#define GST_BUFFER_FREE_DATA_FUNC(buf) (GST_BUFFER(buf)->free_data)
|
#define GST_BUFFER_FREE_DATA_FUNC(buf) (GST_BUFFER(buf)->free_data)
|
||||||
|
@ -95,13 +95,14 @@ extern GType _gst_buffer_type;
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GST_BUFFER_READONLY = GST_DATA_READONLY,
|
GST_BUFFER_READONLY = GST_DATA_READONLY,
|
||||||
GST_BUFFER_SUBBUFFER = GST_DATA_FLAG_LAST,
|
GST_BUFFER_SUBBUFFER = GST_DATA_FLAG_LAST,
|
||||||
GST_BUFFER_ORIGINAL,
|
GST_BUFFER_ORIGINAL, /* original data, not copied, not currently used */
|
||||||
GST_BUFFER_DONTFREE,
|
GST_BUFFER_DONTFREE, /* buffer data is managed by somebody else and cannot be freeed */
|
||||||
GST_BUFFER_KEY_UNIT, /* deprecated, use reverse DELTA_UNIT */
|
GST_BUFFER_KEY_UNIT, /* sync point in the stream, DEPRECATED, use DELTA_UNIT for non-KEY_UNIT buffers */
|
||||||
GST_BUFFER_DONTKEEP,
|
GST_BUFFER_DISCONT, /* buffer is first after discontinuity in the stream */
|
||||||
GST_BUFFER_IN_CAPS,
|
GST_BUFFER_IN_CAPS, /* buffer is also part of caps */
|
||||||
GST_BUFFER_DELTA_UNIT, /* this unit depends on a previous unit */
|
GST_BUFFER_GAP, /* buffer has been created to fill a gap in the stream */
|
||||||
GST_BUFFER_FLAG_LAST = GST_DATA_FLAG_LAST + 8
|
GST_BUFFER_DELTA_UNIT, /* can't be used as sync point in stream */
|
||||||
|
GST_BUFFER_FLAG_LAST = GST_DATA_FLAG_LAST + 8
|
||||||
} GstBufferFlag;
|
} GstBufferFlag;
|
||||||
|
|
||||||
struct _GstBuffer {
|
struct _GstBuffer {
|
||||||
|
@ -116,6 +117,9 @@ struct _GstBuffer {
|
||||||
GstClockTime timestamp;
|
GstClockTime timestamp;
|
||||||
GstClockTime duration;
|
GstClockTime duration;
|
||||||
|
|
||||||
|
/* the media type of this buffer */
|
||||||
|
GstCaps *caps;
|
||||||
|
|
||||||
/* media specific offset
|
/* media specific offset
|
||||||
* for video frames, this could be the number of frames,
|
* for video frames, this could be the number of frames,
|
||||||
* for audio data, this could be the number of audio samples,
|
* for audio data, this could be the number of audio samples,
|
||||||
|
@ -148,17 +152,18 @@ G_STMT_START { \
|
||||||
#define gst_buffer_ref_by_count(buf,c) GST_BUFFER (gst_data_ref_by_count (GST_DATA (buf), c))
|
#define gst_buffer_ref_by_count(buf,c) GST_BUFFER (gst_data_ref_by_count (GST_DATA (buf), c))
|
||||||
#define gst_buffer_unref(buf) gst_data_unref (GST_DATA (buf))
|
#define gst_buffer_unref(buf) gst_data_unref (GST_DATA (buf))
|
||||||
/* copy buffer */
|
/* copy buffer */
|
||||||
void gst_buffer_stamp (GstBuffer *dest, const GstBuffer *src);
|
|
||||||
#define gst_buffer_copy(buf) GST_BUFFER (gst_data_copy (GST_DATA (buf)))
|
#define gst_buffer_copy(buf) GST_BUFFER (gst_data_copy (GST_DATA (buf)))
|
||||||
#define gst_buffer_is_writable(buf) gst_data_is_writable (GST_DATA (buf))
|
#define gst_buffer_is_writable(buf) gst_data_is_writable (GST_DATA (buf))
|
||||||
#define gst_buffer_copy_on_write(buf) GST_BUFFER (gst_data_copy_on_write (GST_DATA (buf)))
|
#define gst_buffer_copy_on_write(buf) GST_BUFFER (gst_data_copy_on_write (GST_DATA (buf)))
|
||||||
|
|
||||||
|
GstCaps* gst_buffer_get_caps (GstBuffer *buffer);
|
||||||
|
void gst_buffer_set_caps (GstBuffer *buffer, GstCaps *caps);
|
||||||
|
|
||||||
/* creating a subbuffer */
|
/* creating a subbuffer */
|
||||||
GstBuffer* gst_buffer_create_sub (GstBuffer *parent, guint offset, guint size);
|
GstBuffer* gst_buffer_create_sub (GstBuffer *parent, guint offset, guint size);
|
||||||
|
|
||||||
/* merge, span, or append two buffers, intelligently */
|
/* merge, span, or append two buffers, intelligently */
|
||||||
GstBuffer* gst_buffer_merge (GstBuffer *buf1, GstBuffer *buf2);
|
GstBuffer* gst_buffer_merge (GstBuffer *buf1, GstBuffer *buf2);
|
||||||
GstBuffer* gst_buffer_join (GstBuffer *buf1, GstBuffer *buf2);
|
|
||||||
gboolean gst_buffer_is_span_fast (GstBuffer *buf1, GstBuffer *buf2);
|
gboolean gst_buffer_is_span_fast (GstBuffer *buf1, GstBuffer *buf2);
|
||||||
GstBuffer* gst_buffer_span (GstBuffer *buf1, guint32 offset, GstBuffer *buf2, guint32 len);
|
GstBuffer* gst_buffer_span (GstBuffer *buf1, guint32 offset, GstBuffer *buf2, guint32 len);
|
||||||
|
|
||||||
|
|
149
gst/gstcaps.c
149
gst/gstcaps.c
|
@ -26,10 +26,12 @@
|
||||||
#include "gst_private.h"
|
#include "gst_private.h"
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
#define DEBUG_REFCOUNT
|
||||||
|
|
||||||
#define CAPS_POISON(caps) G_STMT_START{ \
|
#define CAPS_POISON(caps) G_STMT_START{ \
|
||||||
if (caps) { \
|
if (caps) { \
|
||||||
GstCaps *_newcaps = gst_caps_copy (caps); \
|
GstCaps *_newcaps = gst_caps_copy (caps); \
|
||||||
gst_caps_free(caps); \
|
gst_caps_unref(caps); \
|
||||||
caps = _newcaps; \
|
caps = _newcaps; \
|
||||||
} \
|
} \
|
||||||
} G_STMT_END
|
} G_STMT_END
|
||||||
|
@ -56,7 +58,7 @@ gst_caps_get_type (void)
|
||||||
if (!gst_caps_type) {
|
if (!gst_caps_type) {
|
||||||
gst_caps_type = g_boxed_type_register_static ("GstCaps",
|
gst_caps_type = g_boxed_type_register_static ("GstCaps",
|
||||||
(GBoxedCopyFunc) gst_caps_copy_conditional,
|
(GBoxedCopyFunc) gst_caps_copy_conditional,
|
||||||
(GBoxedFreeFunc) gst_caps_free);
|
(GBoxedFreeFunc) gst_caps_unref);
|
||||||
|
|
||||||
g_value_register_transform_func (gst_caps_type,
|
g_value_register_transform_func (gst_caps_type,
|
||||||
G_TYPE_STRING, gst_caps_transform_to_string);
|
G_TYPE_STRING, gst_caps_transform_to_string);
|
||||||
|
@ -80,9 +82,14 @@ gst_caps_new_empty (void)
|
||||||
{
|
{
|
||||||
GstCaps *caps = g_new0 (GstCaps, 1);
|
GstCaps *caps = g_new0 (GstCaps, 1);
|
||||||
|
|
||||||
|
gst_atomic_int_init (&(caps)->refcount, 1);
|
||||||
caps->type = GST_TYPE_CAPS;
|
caps->type = GST_TYPE_CAPS;
|
||||||
caps->structs = g_ptr_array_new ();
|
caps->structs = g_ptr_array_new ();
|
||||||
|
|
||||||
|
#ifdef DEBUG_REFCOUNT
|
||||||
|
GST_CAT_LOG (GST_CAT_CAPS, "created caps %p", caps);
|
||||||
|
#endif
|
||||||
|
|
||||||
return caps;
|
return caps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,15 +220,8 @@ gst_caps_copy (const GstCaps * caps)
|
||||||
return newcaps;
|
return newcaps;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void
|
||||||
* gst_caps_free:
|
_gst_caps_free (GstCaps * caps)
|
||||||
* @caps: the #GstCaps to free
|
|
||||||
*
|
|
||||||
* Frees a #GstCaps and all its structures and the structures'
|
|
||||||
* values.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
gst_caps_free (GstCaps * caps)
|
|
||||||
{
|
{
|
||||||
GstStructure *structure;
|
GstStructure *structure;
|
||||||
int i;
|
int i;
|
||||||
|
@ -236,9 +236,82 @@ gst_caps_free (GstCaps * caps)
|
||||||
#ifdef USE_POISONING
|
#ifdef USE_POISONING
|
||||||
memset (caps, 0xff, sizeof (GstCaps));
|
memset (caps, 0xff, sizeof (GstCaps));
|
||||||
#endif
|
#endif
|
||||||
|
gst_atomic_int_destroy (&(caps)->refcount);
|
||||||
g_free (caps);
|
g_free (caps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GstCaps *
|
||||||
|
gst_caps_copy_on_write (GstCaps * caps)
|
||||||
|
{
|
||||||
|
GstCaps *copy;
|
||||||
|
|
||||||
|
g_return_val_if_fail (caps != NULL, NULL);
|
||||||
|
|
||||||
|
/* we are the only instance reffing this caps */
|
||||||
|
if (gst_atomic_int_read (&caps->refcount) == 1)
|
||||||
|
return caps;
|
||||||
|
|
||||||
|
/* else copy */
|
||||||
|
copy = gst_caps_copy (caps);
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
GstCaps *
|
||||||
|
gst_caps_ref (GstCaps * caps)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (caps != NULL, NULL);
|
||||||
|
|
||||||
|
#ifdef DEBUG_REFCOUNT
|
||||||
|
GST_CAT_LOG (GST_CAT_CAPS, "%p %d->%d", caps,
|
||||||
|
GST_CAPS_REFCOUNT_VALUE (caps), GST_CAPS_REFCOUNT_VALUE (caps) + 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gst_atomic_int_inc (&caps->refcount);
|
||||||
|
|
||||||
|
return caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
GstCaps *
|
||||||
|
gst_caps_ref_by_count (GstCaps * caps, gint count)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (caps != NULL, NULL);
|
||||||
|
|
||||||
|
#ifdef DEBUG_REFCOUNT
|
||||||
|
GST_CAT_LOG (GST_CAT_CAPS, "%p %d->%d", caps,
|
||||||
|
GST_CAPS_REFCOUNT_VALUE (caps), GST_CAPS_REFCOUNT_VALUE (caps) + count);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gst_atomic_int_add (&caps->refcount, count);
|
||||||
|
|
||||||
|
return caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_caps_unref:
|
||||||
|
* @caps: the #GstCaps to unref
|
||||||
|
*
|
||||||
|
* Unref a #GstCaps and and free all its structures and the
|
||||||
|
* structures' values when the refcount reaches 0.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_caps_unref (GstCaps * caps)
|
||||||
|
{
|
||||||
|
g_return_if_fail (caps != NULL);
|
||||||
|
g_return_if_fail (GST_CAPS_REFCOUNT_VALUE (caps) > 0);
|
||||||
|
|
||||||
|
#ifdef DEBUG_REFCOUNT
|
||||||
|
GST_CAT_LOG (GST_CAT_CAPS, "%p %d->%d", caps,
|
||||||
|
GST_CAPS_REFCOUNT_VALUE (caps), GST_CAPS_REFCOUNT_VALUE (caps) - 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* if we ended up with the refcount at zero, free the caps */
|
||||||
|
if (gst_atomic_int_dec_and_test (&caps->refcount)) {
|
||||||
|
_gst_caps_free (caps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_static_caps_get:
|
* gst_static_caps_get:
|
||||||
* @static_caps: the #GstStaticCaps to convert
|
* @static_caps: the #GstStaticCaps to convert
|
||||||
|
@ -531,25 +604,6 @@ gst_caps_is_empty (const GstCaps * caps)
|
||||||
return (caps->structs == NULL) || (caps->structs->len == 0);
|
return (caps->structs == NULL) || (caps->structs->len == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_caps_is_chained:
|
|
||||||
* @caps: the @GstCaps to test
|
|
||||||
*
|
|
||||||
* Determines if @caps contains multiple #GstStructures.
|
|
||||||
*
|
|
||||||
* This function is deprecated, and should not be used in new code.
|
|
||||||
* Use #gst_caps_is_simple() instead.
|
|
||||||
*
|
|
||||||
* Returns: TRUE if @caps contains more than one structure
|
|
||||||
*/
|
|
||||||
gboolean
|
|
||||||
gst_caps_is_chained (const GstCaps * caps)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
|
|
||||||
|
|
||||||
return (caps->structs->len > 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_caps_is_fixed_foreach (GQuark field_id, GValue * value, gpointer unused)
|
gst_caps_is_fixed_foreach (GQuark field_id, GValue * value, gpointer unused)
|
||||||
{
|
{
|
||||||
|
@ -675,7 +729,7 @@ gst_caps_is_subset (const GstCaps * subset, const GstCaps * superset)
|
||||||
|
|
||||||
caps = gst_caps_subtract (subset, superset);
|
caps = gst_caps_subtract (subset, superset);
|
||||||
ret = gst_caps_is_empty (caps);
|
ret = gst_caps_is_empty (caps);
|
||||||
gst_caps_free (caps);
|
gst_caps_unref (caps);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -835,6 +889,29 @@ gst_caps_intersect (const GstCaps * caps1, const GstCaps * caps2)
|
||||||
return gst_caps_copy (caps1);
|
return gst_caps_copy (caps1);
|
||||||
|
|
||||||
dest = gst_caps_new_empty ();
|
dest = gst_caps_new_empty ();
|
||||||
|
/* run zigzag on top line first
|
||||||
|
*
|
||||||
|
* 1 2 4 ..
|
||||||
|
* 3 5 ..
|
||||||
|
* 6 ..
|
||||||
|
* ..
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
for (i = 0; i < caps1->structs->len; i++) {
|
||||||
|
struct1 = gst_caps_get_structure (caps1, i);
|
||||||
|
for (j = 0; j < caps2->structs->len; j++) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/* run zigzag on right line
|
||||||
|
*
|
||||||
|
* .. 1
|
||||||
|
* .. 2 4
|
||||||
|
* .. 3 5 6
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* FIXME use loop that preserves the order better */
|
||||||
for (i = 0; i < caps1->structs->len; i++) {
|
for (i = 0; i < caps1->structs->len; i++) {
|
||||||
struct1 = gst_caps_get_structure (caps1, i);
|
struct1 = gst_caps_get_structure (caps1, i);
|
||||||
for (j = 0; j < caps2->structs->len; j++) {
|
for (j = 0; j < caps2->structs->len; j++) {
|
||||||
|
@ -951,7 +1028,7 @@ gst_caps_subtract (const GstCaps * minuend, const GstCaps * subtrahend)
|
||||||
for (i = 0; i < subtrahend->structs->len; i++) {
|
for (i = 0; i < subtrahend->structs->len; i++) {
|
||||||
sub = gst_caps_get_structure (subtrahend, i);
|
sub = gst_caps_get_structure (subtrahend, i);
|
||||||
if (dest) {
|
if (dest) {
|
||||||
gst_caps_free (src);
|
gst_caps_unref (src);
|
||||||
src = dest;
|
src = dest;
|
||||||
}
|
}
|
||||||
dest = gst_caps_new_empty ();
|
dest = gst_caps_new_empty ();
|
||||||
|
@ -975,12 +1052,12 @@ gst_caps_subtract (const GstCaps * minuend, const GstCaps * subtrahend)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (gst_caps_is_empty (dest)) {
|
if (gst_caps_is_empty (dest)) {
|
||||||
gst_caps_free (src);
|
gst_caps_unref (src);
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_caps_free (src);
|
gst_caps_unref (src);
|
||||||
gst_caps_do_simplify (dest);
|
gst_caps_do_simplify (dest);
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
@ -1340,7 +1417,7 @@ gst_caps_replace (GstCaps ** caps, GstCaps * newcaps)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
if (*caps)
|
if (*caps)
|
||||||
gst_caps_free (*caps);
|
gst_caps_unref (*caps);
|
||||||
*caps = newcaps;
|
*caps = newcaps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1454,7 +1531,7 @@ gst_caps_from_string (const gchar * string)
|
||||||
if (gst_caps_from_string_inplace (caps, string)) {
|
if (gst_caps_from_string_inplace (caps, string)) {
|
||||||
return caps;
|
return caps;
|
||||||
} else {
|
} else {
|
||||||
gst_caps_free (caps);
|
gst_caps_unref (caps);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,10 +40,8 @@ G_BEGIN_DECLS
|
||||||
#define GST_CAPS_IS_SIMPLE(caps) (gst_caps_get_size(caps) == 1)
|
#define GST_CAPS_IS_SIMPLE(caps) (gst_caps_get_size(caps) == 1)
|
||||||
#define gst_caps_is_simple(caps) GST_CAPS_IS_SIMPLE(caps)
|
#define gst_caps_is_simple(caps) GST_CAPS_IS_SIMPLE(caps)
|
||||||
|
|
||||||
#ifndef GST_DISABLE_DEPRECATED
|
|
||||||
#define GST_DEBUG_CAPS(string, caps) \
|
#define GST_DEBUG_CAPS(string, caps) \
|
||||||
GST_DEBUG ( string "%s: " GST_PTR_FORMAT, caps)
|
GST_DEBUG ( string "%s: " GST_PTR_FORMAT, caps)
|
||||||
#endif
|
|
||||||
|
|
||||||
#define GST_STATIC_CAPS(string) \
|
#define GST_STATIC_CAPS(string) \
|
||||||
{ \
|
{ \
|
||||||
|
@ -54,9 +52,16 @@ G_BEGIN_DECLS
|
||||||
typedef struct _GstCaps GstCaps;
|
typedef struct _GstCaps GstCaps;
|
||||||
typedef struct _GstStaticCaps GstStaticCaps;
|
typedef struct _GstStaticCaps GstStaticCaps;
|
||||||
|
|
||||||
|
/* refcount */
|
||||||
|
#define GST_CAPS_REFCOUNT(caps) ((GST_CAPS(caps))->refcount)
|
||||||
|
#define GST_CAPS_REFCOUNT_VALUE(caps) (gst_atomic_int_read (&(GST_CAPS(caps))->refcount))
|
||||||
|
|
||||||
struct _GstCaps {
|
struct _GstCaps {
|
||||||
GType type;
|
GType type;
|
||||||
|
|
||||||
|
/* refcounting */
|
||||||
|
GstAtomicInt refcount;
|
||||||
|
|
||||||
guint16 flags;
|
guint16 flags;
|
||||||
GPtrArray *structs;
|
GPtrArray *structs;
|
||||||
|
|
||||||
|
@ -80,7 +85,14 @@ GstCaps * gst_caps_new_full (GstStru
|
||||||
GstCaps * gst_caps_new_full_valist (GstStructure *structure,
|
GstCaps * gst_caps_new_full_valist (GstStructure *structure,
|
||||||
va_list var_args);
|
va_list var_args);
|
||||||
GstCaps * gst_caps_copy (const GstCaps *caps);
|
GstCaps * gst_caps_copy (const GstCaps *caps);
|
||||||
void gst_caps_free (GstCaps *caps);
|
GstCaps * gst_caps_copy_1 (const GstCaps *caps);
|
||||||
|
|
||||||
|
/* reference counting */
|
||||||
|
GstCaps * gst_caps_copy_on_write (GstCaps *caps);
|
||||||
|
GstCaps * gst_caps_ref (GstCaps* caps);
|
||||||
|
GstCaps * gst_caps_ref_by_count (GstCaps* caps, gint count);
|
||||||
|
void gst_caps_unref (GstCaps* caps);
|
||||||
|
|
||||||
G_CONST_RETURN GstCaps * gst_static_caps_get (GstStaticCaps *static_caps);
|
G_CONST_RETURN GstCaps * gst_static_caps_get (GstStaticCaps *static_caps);
|
||||||
|
|
||||||
/* manipulation */
|
/* manipulation */
|
||||||
|
@ -91,10 +103,6 @@ void gst_caps_append_structure (GstCaps
|
||||||
int gst_caps_get_size (const GstCaps *caps);
|
int gst_caps_get_size (const GstCaps *caps);
|
||||||
GstStructure * gst_caps_get_structure (const GstCaps *caps,
|
GstStructure * gst_caps_get_structure (const GstCaps *caps,
|
||||||
int index);
|
int index);
|
||||||
#ifndef GST_DISABLE_DEPRECATED
|
|
||||||
GstCaps * gst_caps_split_one (GstCaps *caps);
|
|
||||||
GstCaps * gst_caps_copy_1 (const GstCaps *caps);
|
|
||||||
#endif
|
|
||||||
void gst_caps_set_simple (GstCaps *caps,
|
void gst_caps_set_simple (GstCaps *caps,
|
||||||
char *field, ...);
|
char *field, ...);
|
||||||
void gst_caps_set_simple_valist (GstCaps *caps,
|
void gst_caps_set_simple_valist (GstCaps *caps,
|
||||||
|
@ -104,11 +112,6 @@ void gst_caps_set_simple_valist (GstCaps
|
||||||
/* tests */
|
/* tests */
|
||||||
gboolean gst_caps_is_any (const GstCaps *caps);
|
gboolean gst_caps_is_any (const GstCaps *caps);
|
||||||
gboolean gst_caps_is_empty (const GstCaps *caps);
|
gboolean gst_caps_is_empty (const GstCaps *caps);
|
||||||
#ifndef GST_DISABLE_DEPRECATED
|
|
||||||
gboolean gst_caps_is_chained (const GstCaps *caps);
|
|
||||||
gboolean gst_caps_is_equal_fixed (const GstCaps *caps1,
|
|
||||||
const GstCaps *caps2);
|
|
||||||
#endif
|
|
||||||
gboolean gst_caps_is_fixed (const GstCaps *caps);
|
gboolean gst_caps_is_fixed (const GstCaps *caps);
|
||||||
gboolean gst_caps_is_always_compatible (const GstCaps *caps1,
|
gboolean gst_caps_is_always_compatible (const GstCaps *caps1,
|
||||||
const GstCaps *caps2);
|
const GstCaps *caps2);
|
||||||
|
@ -125,9 +128,6 @@ GstCaps * gst_caps_subtract (const GstCaps *minuend,
|
||||||
GstCaps * gst_caps_union (const GstCaps *caps1,
|
GstCaps * gst_caps_union (const GstCaps *caps1,
|
||||||
const GstCaps *caps2);
|
const GstCaps *caps2);
|
||||||
GstCaps * gst_caps_normalize (const GstCaps *caps);
|
GstCaps * gst_caps_normalize (const GstCaps *caps);
|
||||||
#ifndef GST_DISABLE_DEPRECATED
|
|
||||||
GstCaps * gst_caps_simplify (const GstCaps *caps);
|
|
||||||
#endif
|
|
||||||
gboolean gst_caps_do_simplify (GstCaps *caps);
|
gboolean gst_caps_do_simplify (GstCaps *caps);
|
||||||
|
|
||||||
#ifndef GST_DISABLE_LOADSAVE
|
#ifndef GST_DISABLE_LOADSAVE
|
||||||
|
|
|
@ -396,8 +396,6 @@ gst_clock_class_init (GstClockClass * klass)
|
||||||
static void
|
static void
|
||||||
gst_clock_init (GstClock * clock)
|
gst_clock_init (GstClock * clock)
|
||||||
{
|
{
|
||||||
clock->max_diff = DEFAULT_MAX_DIFF;
|
|
||||||
|
|
||||||
clock->start_time = 0;
|
clock->start_time = 0;
|
||||||
clock->last_time = 0;
|
clock->last_time = 0;
|
||||||
clock->entries = NULL;
|
clock->entries = NULL;
|
||||||
|
@ -570,25 +568,6 @@ gst_clock_reset (GstClock * clock)
|
||||||
GST_UNLOCK (clock);
|
GST_UNLOCK (clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_clock_handle_discont
|
|
||||||
* @clock: a #GstClock to notify of the discontinuity
|
|
||||||
* @time: The new time
|
|
||||||
*
|
|
||||||
* Notifies the clock of a discontinuity in time.
|
|
||||||
*
|
|
||||||
* Returns: TRUE if the clock was updated. It is possible that
|
|
||||||
* the clock was not updated by this call because only the first
|
|
||||||
* discontinuitity in the pipeline is honoured.
|
|
||||||
*/
|
|
||||||
gboolean
|
|
||||||
gst_clock_handle_discont (GstClock * clock, guint64 time)
|
|
||||||
{
|
|
||||||
GST_ERROR_OBJECT (clock, "called deprecated function.");
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_clock_get_time
|
* gst_clock_get_time
|
||||||
* @clock: a #GstClock to query
|
* @clock: a #GstClock to query
|
||||||
|
@ -621,61 +600,6 @@ gst_clock_get_time (GstClock * clock)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_clock_get_event_time:
|
|
||||||
* @clock: clock to query
|
|
||||||
*
|
|
||||||
* Gets the "event time" of a given clock. An event on the clock happens
|
|
||||||
* whenever this function is called. This ensures that multiple events that
|
|
||||||
* happen shortly after each other are treated as if they happened at the same
|
|
||||||
* time. GStreamer uses to keep state changes of multiple elements in sync.
|
|
||||||
*
|
|
||||||
* Returns: the time of the event
|
|
||||||
*/
|
|
||||||
GstClockTime
|
|
||||||
gst_clock_get_event_time (GstClock * clock)
|
|
||||||
{
|
|
||||||
return gst_clock_get_event_time_delay (clock, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_clock_get_event_time_delay:
|
|
||||||
* @clock: clock to query
|
|
||||||
* @delay: time before the event actually occurs
|
|
||||||
*
|
|
||||||
* Gets the "event time" of a given clock. An event on the clock happens
|
|
||||||
* whenever this function is called. This ensures that multiple events that
|
|
||||||
* happen shortly after each other are treated as if they happened at the same
|
|
||||||
* time. GStreamer uses to keep state changes of multiple elements in sync.
|
|
||||||
*
|
|
||||||
* When calling this function, the specified delay will be added to the current
|
|
||||||
* time to produce the event time. This can be used for events that are
|
|
||||||
* scheduled to happen at some point in the future.
|
|
||||||
*
|
|
||||||
* Returns: the time of the event
|
|
||||||
*/
|
|
||||||
GstClockTime
|
|
||||||
gst_clock_get_event_time_delay (GstClock * clock, GstClockTime delay)
|
|
||||||
{
|
|
||||||
GstClockTime time;
|
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_TIME_NONE);
|
|
||||||
|
|
||||||
time = gst_clock_get_time (clock);
|
|
||||||
|
|
||||||
if (ABS (GST_CLOCK_DIFF (clock->last_event, time + delay)) <
|
|
||||||
clock->max_event_diff) {
|
|
||||||
GST_LOG_OBJECT (clock, "reporting last event time %" G_GUINT64_FORMAT,
|
|
||||||
clock->last_event);
|
|
||||||
} else {
|
|
||||||
clock->last_event = time + delay;
|
|
||||||
GST_LOG_OBJECT (clock, "reporting new event time %" G_GUINT64_FORMAT,
|
|
||||||
clock->last_event);
|
|
||||||
}
|
|
||||||
|
|
||||||
return clock->last_event;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_clock_get_next_id
|
* gst_clock_get_next_id
|
||||||
* @clock: The clock to query
|
* @clock: The clock to query
|
||||||
|
@ -718,12 +642,8 @@ gst_clock_set_property (GObject * object, guint prop_id,
|
||||||
g_object_notify (object, "stats");
|
g_object_notify (object, "stats");
|
||||||
break;
|
break;
|
||||||
case ARG_MAX_DIFF:
|
case ARG_MAX_DIFF:
|
||||||
clock->max_diff = g_value_get_int64 (value);
|
|
||||||
g_object_notify (object, "max-diff");
|
|
||||||
break;
|
break;
|
||||||
case ARG_EVENT_DIFF:
|
case ARG_EVENT_DIFF:
|
||||||
clock->max_event_diff = g_value_get_uint64 (value);
|
|
||||||
g_object_notify (object, "event-diff");
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
@ -744,10 +664,8 @@ gst_clock_get_property (GObject * object, guint prop_id,
|
||||||
g_value_set_boolean (value, clock->stats);
|
g_value_set_boolean (value, clock->stats);
|
||||||
break;
|
break;
|
||||||
case ARG_MAX_DIFF:
|
case ARG_MAX_DIFF:
|
||||||
g_value_set_int64 (value, clock->max_diff);
|
|
||||||
break;
|
break;
|
||||||
case ARG_EVENT_DIFF:
|
case ARG_EVENT_DIFF:
|
||||||
g_value_set_uint64 (value, clock->max_event_diff);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
|
|
@ -55,6 +55,13 @@ G_STMT_START { \
|
||||||
(tv).tv_usec = ((t) - (tv).tv_sec * GST_SECOND) / GST_USECOND; \
|
(tv).tv_usec = ((t) - (tv).tv_sec * GST_SECOND) / GST_USECOND; \
|
||||||
} G_STMT_END
|
} G_STMT_END
|
||||||
|
|
||||||
|
#define GST_TIMESPEC_TO_TIME(ts) ((ts).tv_sec * GST_SECOND + (ts).tv_nsec * GST_NSECOND)
|
||||||
|
#define GST_TIME_TO_TIMESPEC(t,ts) \
|
||||||
|
G_STMT_START { \
|
||||||
|
(ts).tv_sec = (t) / GST_SECOND; \
|
||||||
|
(ts).tv_usec = ((t) - (ts).tv_sec * GST_SECOND) / GST_NSECOND; \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
#define GST_CLOCK_ENTRY_TRACE_NAME "GstClockEntry"
|
#define GST_CLOCK_ENTRY_TRACE_NAME "GstClockEntry"
|
||||||
|
|
||||||
typedef struct _GstClockEntry GstClockEntry;
|
typedef struct _GstClockEntry GstClockEntry;
|
||||||
|
@ -102,7 +109,8 @@ typedef enum
|
||||||
GST_CLOCK_TIMEOUT = 1,
|
GST_CLOCK_TIMEOUT = 1,
|
||||||
GST_CLOCK_EARLY = 2,
|
GST_CLOCK_EARLY = 2,
|
||||||
GST_CLOCK_ERROR = 3,
|
GST_CLOCK_ERROR = 3,
|
||||||
GST_CLOCK_UNSUPPORTED = 4
|
GST_CLOCK_UNSUPPORTED = 4,
|
||||||
|
GST_CLOCK_OK = 5
|
||||||
} GstClockReturn;
|
} GstClockReturn;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
|
@ -125,7 +133,6 @@ struct _GstClock {
|
||||||
/* --- protected --- */
|
/* --- protected --- */
|
||||||
GstClockTime start_time;
|
GstClockTime start_time;
|
||||||
GstClockTime last_time;
|
GstClockTime last_time;
|
||||||
gint64 max_diff;
|
|
||||||
|
|
||||||
/* --- private --- */
|
/* --- private --- */
|
||||||
guint64 resolution;
|
guint64 resolution;
|
||||||
|
@ -134,9 +141,6 @@ struct _GstClock {
|
||||||
GCond *active_cond;
|
GCond *active_cond;
|
||||||
gboolean stats;
|
gboolean stats;
|
||||||
|
|
||||||
GstClockTime last_event;
|
|
||||||
GstClockTime max_event_diff;
|
|
||||||
|
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
gpointer _gst_reserved[GST_PADDING];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -175,9 +179,6 @@ void gst_clock_reset (GstClock *clock);
|
||||||
gboolean gst_clock_handle_discont (GstClock *clock, guint64 time);
|
gboolean gst_clock_handle_discont (GstClock *clock, guint64 time);
|
||||||
|
|
||||||
GstClockTime gst_clock_get_time (GstClock *clock);
|
GstClockTime gst_clock_get_time (GstClock *clock);
|
||||||
GstClockTime gst_clock_get_event_time (GstClock *clock);
|
|
||||||
GstClockTime gst_clock_get_event_time_delay (GstClock *clock, GstClockTime delay);
|
|
||||||
|
|
||||||
|
|
||||||
GstClockID gst_clock_get_next_id (GstClock *clock);
|
GstClockID gst_clock_get_next_id (GstClock *clock);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* GStreamer
|
/* GStreamer
|
||||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||||
* 2000 Wim Taymans <wtay@chello.be>
|
* 2000 Wim Taymans <wim@fluendo.com>
|
||||||
*
|
*
|
||||||
* gstdata.c: Data operations
|
* gstdata.c: Data operations
|
||||||
*
|
*
|
||||||
|
|
2530
gst/gstelement.c
2530
gst/gstelement.c
File diff suppressed because it is too large
Load diff
236
gst/gstelement.h
236
gst/gstelement.h
|
@ -32,6 +32,8 @@
|
||||||
#include <gst/gstplugin.h>
|
#include <gst/gstplugin.h>
|
||||||
#include <gst/gstpluginfeature.h>
|
#include <gst/gstpluginfeature.h>
|
||||||
#include <gst/gstindex.h>
|
#include <gst/gstindex.h>
|
||||||
|
#include <gst/gstiterator.h>
|
||||||
|
#include <gst/gsttask.h>
|
||||||
#include <gst/gsttag.h>
|
#include <gst/gsttag.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
@ -80,7 +82,6 @@ GST_EXPORT GType _gst_element_type;
|
||||||
#define GST_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_ELEMENT, GstElementClass))
|
#define GST_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_ELEMENT, GstElementClass))
|
||||||
|
|
||||||
/* convenience functions */
|
/* convenience functions */
|
||||||
#ifndef GST_DISABLE_DEPRECATED
|
|
||||||
#ifdef G_HAVE_ISO_VARARGS
|
#ifdef G_HAVE_ISO_VARARGS
|
||||||
#define GST_ELEMENT_QUERY_TYPE_FUNCTION(functionname, ...) \
|
#define GST_ELEMENT_QUERY_TYPE_FUNCTION(functionname, ...) \
|
||||||
GST_QUERY_TYPE_FUNCTION (GstElement*, functionname, __VA_ARGS__);
|
GST_QUERY_TYPE_FUNCTION (GstElement*, functionname, __VA_ARGS__);
|
||||||
|
@ -96,26 +97,8 @@ GST_EXPORT GType _gst_element_type;
|
||||||
#define GST_ELEMENT_EVENT_MASK_FUNCTION(functionname, a...) \
|
#define GST_ELEMENT_EVENT_MASK_FUNCTION(functionname, a...) \
|
||||||
GST_EVENT_MASK_FUNCTION (GstElement*, functionname, a);
|
GST_EVENT_MASK_FUNCTION (GstElement*, functionname, a);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/* element is complex (for some def.) and generally require a cothread */
|
|
||||||
GST_ELEMENT_COMPLEX = GST_OBJECT_FLAG_LAST,
|
|
||||||
/* input and output pads aren't directly coupled to each other
|
|
||||||
examples: queues, multi-output async readers, etc. */
|
|
||||||
GST_ELEMENT_DECOUPLED,
|
|
||||||
/* this element should be placed in a thread if at all possible */
|
|
||||||
GST_ELEMENT_THREAD_SUGGESTED,
|
|
||||||
/* this element, for some reason, has a loop function that performs
|
|
||||||
* an infinite loop without calls to gst_element_yield () */
|
|
||||||
GST_ELEMENT_INFINITE_LOOP,
|
|
||||||
/* there is a new loopfunction ready for placement */
|
|
||||||
GST_ELEMENT_NEW_LOOPFUNC,
|
|
||||||
/* if this element can handle events */
|
|
||||||
GST_ELEMENT_EVENT_AWARE,
|
|
||||||
/* use threadsafe property get/set implementation */
|
|
||||||
GST_ELEMENT_USE_THREADSAFE_PROPERTIES,
|
|
||||||
|
|
||||||
/* private flags that can be used by the scheduler */
|
/* private flags that can be used by the scheduler */
|
||||||
GST_ELEMENT_SCHEDULER_PRIVATE1,
|
GST_ELEMENT_SCHEDULER_PRIVATE1,
|
||||||
GST_ELEMENT_SCHEDULER_PRIVATE2,
|
GST_ELEMENT_SCHEDULER_PRIVATE2,
|
||||||
|
@ -123,20 +106,13 @@ typedef enum {
|
||||||
/* ignore state changes from parent */
|
/* ignore state changes from parent */
|
||||||
GST_ELEMENT_LOCKED_STATE,
|
GST_ELEMENT_LOCKED_STATE,
|
||||||
|
|
||||||
/* element is in error */
|
|
||||||
GST_ELEMENT_IN_ERROR,
|
|
||||||
|
|
||||||
/* use some padding for future expansion */
|
/* use some padding for future expansion */
|
||||||
GST_ELEMENT_FLAG_LAST = GST_OBJECT_FLAG_LAST + 16
|
GST_ELEMENT_FLAG_LAST = GST_OBJECT_FLAG_LAST + 16
|
||||||
} GstElementFlags;
|
} GstElementFlags;
|
||||||
|
|
||||||
#define GST_ELEMENT_IS_THREAD_SUGGESTED(obj) (GST_FLAG_IS_SET(obj,GST_ELEMENT_THREAD_SUGGESTED))
|
|
||||||
#define GST_ELEMENT_IS_EVENT_AWARE(obj) (GST_FLAG_IS_SET(obj,GST_ELEMENT_EVENT_AWARE))
|
|
||||||
#define GST_ELEMENT_IS_DECOUPLED(obj) (GST_FLAG_IS_SET(obj,GST_ELEMENT_DECOUPLED))
|
|
||||||
|
|
||||||
#define GST_ELEMENT_NAME(obj) (GST_OBJECT_NAME(obj))
|
#define GST_ELEMENT_NAME(obj) (GST_OBJECT_NAME(obj))
|
||||||
#define GST_ELEMENT_PARENT(obj) (GST_OBJECT_PARENT(obj))
|
#define GST_ELEMENT_PARENT(obj) (GST_OBJECT_PARENT(obj))
|
||||||
#define GST_ELEMENT_SCHED(obj) (((GstElement*)(obj))->sched)
|
#define GST_ELEMENT_MANAGER(obj) (((GstElement*)(obj))->manager)
|
||||||
#define GST_ELEMENT_CLOCK(obj) (((GstElement*)(obj))->clock)
|
#define GST_ELEMENT_CLOCK(obj) (((GstElement*)(obj))->clock)
|
||||||
#define GST_ELEMENT_PADS(obj) ((obj)->pads)
|
#define GST_ELEMENT_PADS(obj) ((obj)->pads)
|
||||||
|
|
||||||
|
@ -146,47 +122,52 @@ typedef enum {
|
||||||
if (__msg) \
|
if (__msg) \
|
||||||
GST_ERROR_OBJECT (el, "%s", __msg); \
|
GST_ERROR_OBJECT (el, "%s", __msg); \
|
||||||
if (__dbg) \
|
if (__dbg) \
|
||||||
GST_ERROR_OBJECT (el, "%s", __dbg); \
|
GST_ERROR_OBJECT (el, "%s", __dbg); \
|
||||||
gst_element_error_full (GST_ELEMENT(el), \
|
gst_element_error_full (GST_ELEMENT(el), \
|
||||||
GST_ ## domain ## _ERROR, GST_ ## domain ## _ERROR_ ## code, \
|
GST_ ## domain ## _ERROR, GST_ ## domain ## _ERROR_ ## code, \
|
||||||
__msg, __dbg, __FILE__, GST_FUNCTION, __LINE__); \
|
__msg, __dbg, __FILE__, GST_FUNCTION, __LINE__); \
|
||||||
} G_STMT_END
|
} G_STMT_END
|
||||||
|
|
||||||
|
/* the state change mutexes and conds */
|
||||||
|
#define GST_STATE_GET_LOCK(elem) (((GstElement *)(elem))->state_lock)
|
||||||
|
#define GST_STATE_LOCK(elem) g_mutex_lock(GST_STATE_GET_LOCK(elem))
|
||||||
|
#define GST_STATE_TRYLOCK(elem) g_mutex_trylock(GST_STATE_GET_LOCK(elem))
|
||||||
|
#define GST_STATE_UNLOCK(elem) g_mutex_unlock(GST_STATE_GET_LOCK(elem))
|
||||||
|
#define GST_STATE_GET_COND(elem) (((GstElement *)(elem))->state_cond)
|
||||||
|
#define GST_STATE_WAIT(elem) g_cond_wait (GST_STATE_GET_COND (elem), GST_STATE_GET_LOCK (elem))
|
||||||
|
#define GST_STATE_TIMED_WAIT(elem, timeval) g_cond_timed_wait (GST_STATE_GET_COND (elem), GST_STATE_GET_LOCK (elem),\
|
||||||
|
timeval)
|
||||||
|
|
||||||
typedef struct _GstElementFactory GstElementFactory;
|
typedef struct _GstElementFactory GstElementFactory;
|
||||||
typedef struct _GstElementFactoryClass GstElementFactoryClass;
|
typedef struct _GstElementFactoryClass GstElementFactoryClass;
|
||||||
|
|
||||||
typedef void (*GstElementLoopFunction) (GstElement *element);
|
|
||||||
typedef void (*GstElementPreRunFunction) (GstElement *element);
|
|
||||||
typedef void (*GstElementPostRunFunction) (GstElement *element);
|
|
||||||
|
|
||||||
struct _GstElement {
|
struct _GstElement {
|
||||||
GstObject object;
|
GstObject object;
|
||||||
|
|
||||||
/* element state and scheduling */
|
/* element state */
|
||||||
|
GMutex *state_lock;
|
||||||
|
GCond *state_cond;
|
||||||
guint8 current_state;
|
guint8 current_state;
|
||||||
guint8 pending_state;
|
guint8 pending_state;
|
||||||
GstElementLoopFunction loopfunc;
|
|
||||||
|
|
||||||
GstScheduler *sched;
|
/* element manager */
|
||||||
|
GstPipeline *manager;
|
||||||
|
/* private pointer for the scheduler */
|
||||||
gpointer sched_private;
|
gpointer sched_private;
|
||||||
|
|
||||||
/* allocated clock */
|
/* allocated clock */
|
||||||
GstClock *clock;
|
GstClock *clock;
|
||||||
GstClockTimeDiff base_time; /* NULL/READY: 0 - PAUSED: current time - PLAYING: difference to clock */
|
GstClockTimeDiff base_time; /* NULL/READY: 0 - PAUSED: current time - PLAYING: difference to clock */
|
||||||
|
|
||||||
/* element pads */
|
/* element pads, these lists can only be iterated while holding
|
||||||
|
* the element lock or checking the cookie after each lock. */
|
||||||
guint16 numpads;
|
guint16 numpads;
|
||||||
guint16 numsrcpads;
|
|
||||||
guint16 numsinkpads;
|
|
||||||
GList *pads;
|
GList *pads;
|
||||||
|
guint16 numsrcpads;
|
||||||
GMutex *state_mutex;
|
GList *srcpads;
|
||||||
GCond *state_cond;
|
guint16 numsinkpads;
|
||||||
|
GList *sinkpads;
|
||||||
GstElementPreRunFunction pre_run_func;
|
guint32 pads_cookie;
|
||||||
GstElementPostRunFunction post_run_func;
|
|
||||||
GAsyncQueue *prop_value_queue;
|
|
||||||
GMutex *property_mutex;
|
|
||||||
|
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
gpointer _gst_reserved[GST_PADDING];
|
||||||
};
|
};
|
||||||
|
@ -203,21 +184,35 @@ struct _GstElementClass {
|
||||||
/* templates for our pads */
|
/* templates for our pads */
|
||||||
GList *padtemplates;
|
GList *padtemplates;
|
||||||
gint numpadtemplates;
|
gint numpadtemplates;
|
||||||
|
guint32 pad_templ_cookie;
|
||||||
|
|
||||||
/* signal callbacks */
|
/* signal callbacks */
|
||||||
void (*state_change) (GstElement *element, GstElementState old, GstElementState state);
|
void (*state_change) (GstElement *element, GstElementState old, GstElementState state);
|
||||||
void (*new_pad) (GstElement *element, GstPad *pad);
|
void (*new_pad) (GstElement *element, GstPad *pad);
|
||||||
void (*pad_removed) (GstElement *element, GstPad *pad);
|
void (*pad_removed) (GstElement *element, GstPad *pad);
|
||||||
void (*error) (GstElement *element, GstElement *source, GError *error, gchar *debug);
|
void (*no_more_pads) (GstElement *element);
|
||||||
void (*eos) (GstElement *element);
|
|
||||||
void (*found_tag) (GstElement *element, GstElement *source, const GstTagList *tag_list);
|
|
||||||
|
|
||||||
/* local pointers for get/set */
|
/* vtable */
|
||||||
void (*set_property) (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
|
|
||||||
void (*get_property) (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
|
|
||||||
|
|
||||||
/* vtable*/
|
/* request/release pads */
|
||||||
gboolean (*release_locks) (GstElement *element);
|
GstPad* (*request_new_pad) (GstElement *element, GstPadTemplate *templ, const gchar* name);
|
||||||
|
void (*release_pad) (GstElement *element, GstPad *pad);
|
||||||
|
|
||||||
|
/* state changes */
|
||||||
|
gboolean (*get_state) (GstElement *element, GstElementState *state,
|
||||||
|
GstElementState *pending, GTimeVal *timeout);
|
||||||
|
GstElementStateReturn (*change_state) (GstElement *element);
|
||||||
|
|
||||||
|
/* manager */
|
||||||
|
void (*set_manager) (GstElement *element, GstPipeline *pipeline);
|
||||||
|
|
||||||
|
/* set/get clocks */
|
||||||
|
GstClock* (*get_clock) (GstElement *element);
|
||||||
|
void (*set_clock) (GstElement *element, GstClock *clock);
|
||||||
|
|
||||||
|
/* index */
|
||||||
|
GstIndex* (*get_index) (GstElement *element);
|
||||||
|
void (*set_index) (GstElement *element, GstIndex *index);
|
||||||
|
|
||||||
/* query/convert/events functions */
|
/* query/convert/events functions */
|
||||||
const GstEventMask* (*get_event_masks) (GstElement *element);
|
const GstEventMask* (*get_event_masks) (GstElement *element);
|
||||||
|
@ -230,133 +225,64 @@ struct _GstElementClass {
|
||||||
gboolean (*query) (GstElement *element, GstQueryType type,
|
gboolean (*query) (GstElement *element, GstQueryType type,
|
||||||
GstFormat *format, gint64 *value);
|
GstFormat *format, gint64 *value);
|
||||||
|
|
||||||
/* change the element state */
|
|
||||||
GstElementStateReturn (*change_state) (GstElement *element);
|
|
||||||
|
|
||||||
/* request/release pads */
|
|
||||||
GstPad* (*request_new_pad) (GstElement *element, GstPadTemplate *templ, const gchar* name);
|
|
||||||
void (*release_pad) (GstElement *element, GstPad *pad);
|
|
||||||
|
|
||||||
/* set/get clocks */
|
|
||||||
GstClock* (*get_clock) (GstElement *element);
|
|
||||||
void (*set_clock) (GstElement *element, GstClock *clock);
|
|
||||||
|
|
||||||
/* index */
|
|
||||||
GstIndex* (*get_index) (GstElement *element);
|
|
||||||
void (*set_index) (GstElement *element, GstIndex *index);
|
|
||||||
|
|
||||||
GstElementStateReturn (*set_state) (GstElement *element, GstElementState state);
|
|
||||||
|
|
||||||
/* FIXME 0.9: move up to signals */
|
|
||||||
void (*no_more_pads) (GstElement *element);
|
|
||||||
|
|
||||||
gpointer _gst_reserved[GST_PADDING - 1];
|
gpointer _gst_reserved[GST_PADDING - 1];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* class stuff */
|
||||||
void gst_element_class_add_pad_template (GstElementClass *klass, GstPadTemplate *templ);
|
void gst_element_class_add_pad_template (GstElementClass *klass, GstPadTemplate *templ);
|
||||||
void gst_element_class_install_std_props (GstElementClass *klass,
|
void gst_element_class_install_std_props (GstElementClass *klass,
|
||||||
const gchar *first_name, ...);
|
const gchar *first_name, ...);
|
||||||
void gst_element_class_set_details (GstElementClass *klass,
|
void gst_element_class_set_details (GstElementClass *klass,
|
||||||
const GstElementDetails *details);
|
const GstElementDetails *details);
|
||||||
|
GstPadTemplate* gst_element_class_get_pad_template (GstElementClass *element_class, const gchar *name);
|
||||||
|
GList* gst_element_class_get_pad_template_list (GstElementClass *element_class);
|
||||||
|
|
||||||
#define gst_element_default_deep_notify gst_object_default_deep_notify
|
/* element instance */
|
||||||
|
|
||||||
void gst_element_default_error (GObject *object, GstObject *orig, GError *error, gchar *debug);
|
|
||||||
|
|
||||||
GType gst_element_get_type (void);
|
GType gst_element_get_type (void);
|
||||||
void gst_element_set_loop_function (GstElement *element,
|
|
||||||
GstElementLoopFunction loop);
|
|
||||||
|
|
||||||
#define gst_element_get_name(elem) gst_object_get_name(GST_OBJECT(elem))
|
#define gst_element_get_name(elem) gst_object_get_name(GST_OBJECT(elem))
|
||||||
#define gst_element_set_name(elem,name) gst_object_set_name(GST_OBJECT(elem),name)
|
#define gst_element_set_name(elem,name) gst_object_set_name(GST_OBJECT(elem),name)
|
||||||
#define gst_element_get_parent(elem) gst_object_get_parent(GST_OBJECT(elem))
|
#define gst_element_get_parent(elem) gst_object_get_parent(GST_OBJECT(elem))
|
||||||
#define gst_element_set_parent(elem,parent) gst_object_set_parent(GST_OBJECT(elem),parent)
|
#define gst_element_set_parent(elem,parent) gst_object_set_parent(GST_OBJECT(elem),parent)
|
||||||
|
|
||||||
/* threadsafe versions of their g_object_* counterparts */
|
|
||||||
void gst_element_set (GstElement *element, const gchar *first_property_name, ...);
|
|
||||||
void gst_element_get (GstElement *element, const gchar *first_property_name, ...);
|
|
||||||
void gst_element_set_valist (GstElement *element, const gchar *first_property_name,
|
|
||||||
va_list var_args);
|
|
||||||
void gst_element_get_valist (GstElement *element, const gchar *first_property_name,
|
|
||||||
va_list var_args);
|
|
||||||
void gst_element_set_property (GstElement *element, const gchar *property_name,
|
|
||||||
const GValue *value);
|
|
||||||
void gst_element_get_property (GstElement *element, const gchar *property_name,
|
|
||||||
GValue *value);
|
|
||||||
|
|
||||||
void gst_element_enable_threadsafe_properties (GstElement *element);
|
|
||||||
void gst_element_disable_threadsafe_properties (GstElement *element);
|
|
||||||
void gst_element_set_pending_properties (GstElement *element);
|
|
||||||
|
|
||||||
/* clocking */
|
/* clocking */
|
||||||
gboolean gst_element_requires_clock (GstElement *element);
|
gboolean gst_element_requires_clock (GstElement *element);
|
||||||
gboolean gst_element_provides_clock (GstElement *element);
|
gboolean gst_element_provides_clock (GstElement *element);
|
||||||
GstClock* gst_element_get_clock (GstElement *element);
|
GstClock* gst_element_get_clock (GstElement *element);
|
||||||
void gst_element_set_clock (GstElement *element, GstClock *clock);
|
void gst_element_set_clock (GstElement *element, GstClock *clock);
|
||||||
|
|
||||||
GstClockReturn gst_element_clock_wait (GstElement *element,
|
GstClockReturn gst_element_clock_wait (GstElement *element,
|
||||||
GstClockID id, GstClockTimeDiff *jitter);
|
GstClockID id, GstClockTimeDiff *jitter);
|
||||||
GstClockTime gst_element_get_time (GstElement *element);
|
GstClockTime gst_element_get_time (GstElement *element);
|
||||||
gboolean gst_element_wait (GstElement *element, GstClockTime timestamp);
|
gboolean gst_element_wait (GstElement *element, GstClockTime timestamp);
|
||||||
void gst_element_set_time (GstElement *element, GstClockTime time);
|
|
||||||
void gst_element_set_time_delay (GstElement *element, GstClockTime time, GstClockTime delay);
|
|
||||||
|
|
||||||
void gst_element_adjust_time (GstElement *element, GstClockTimeDiff diff);
|
/* indexes */
|
||||||
|
|
||||||
/* indexs */
|
|
||||||
gboolean gst_element_is_indexable (GstElement *element);
|
gboolean gst_element_is_indexable (GstElement *element);
|
||||||
void gst_element_set_index (GstElement *element, GstIndex *index);
|
void gst_element_set_index (GstElement *element, GstIndex *index);
|
||||||
GstIndex* gst_element_get_index (GstElement *element);
|
GstIndex* gst_element_get_index (GstElement *element);
|
||||||
|
|
||||||
|
/* manager and tasks */
|
||||||
|
void gst_element_set_manager (GstElement *element, GstPipeline *pipeline);
|
||||||
|
GstPipeline* gst_element_get_manager (GstElement *element);
|
||||||
|
GstTask* gst_element_create_task (GstElement *element, GstTaskFunction func, gpointer data);
|
||||||
|
|
||||||
gboolean gst_element_release_locks (GstElement *element);
|
/* pad management */
|
||||||
|
gboolean gst_element_add_pad (GstElement *element, GstPad *pad);
|
||||||
void gst_element_yield (GstElement *element);
|
|
||||||
gboolean gst_element_interrupt (GstElement *element);
|
|
||||||
void gst_element_set_scheduler (GstElement *element, GstScheduler *sched);
|
|
||||||
GstScheduler* gst_element_get_scheduler (GstElement *element);
|
|
||||||
|
|
||||||
void gst_element_add_pad (GstElement *element, GstPad *pad);
|
|
||||||
void gst_element_remove_pad (GstElement *element, GstPad *pad);
|
void gst_element_remove_pad (GstElement *element, GstPad *pad);
|
||||||
GstPad * gst_element_add_ghost_pad (GstElement *element, GstPad *pad, const gchar *name);
|
GstPad * gst_element_add_ghost_pad (GstElement *element, GstPad *pad, const gchar *name);
|
||||||
#ifndef GST_DISABLE_DEPRECATED
|
|
||||||
void gst_element_remove_ghost_pad (GstElement *element, GstPad *pad);
|
|
||||||
#endif
|
|
||||||
void gst_element_no_more_pads (GstElement *element);
|
void gst_element_no_more_pads (GstElement *element);
|
||||||
|
|
||||||
GstPad* gst_element_get_pad (GstElement *element, const gchar *name);
|
GstPad* gst_element_get_pad (GstElement *element, const gchar *name);
|
||||||
GstPad* gst_element_get_static_pad (GstElement *element, const gchar *name);
|
GstPad* gst_element_get_static_pad (GstElement *element, const gchar *name);
|
||||||
GstPad* gst_element_get_request_pad (GstElement *element, const gchar *name);
|
GstPad* gst_element_get_request_pad (GstElement *element, const gchar *name);
|
||||||
void gst_element_release_request_pad (GstElement *element, GstPad *pad);
|
void gst_element_release_request_pad (GstElement *element, GstPad *pad);
|
||||||
|
|
||||||
G_CONST_RETURN GList*
|
G_CONST_RETURN GList*
|
||||||
gst_element_get_pad_list (GstElement *element);
|
gst_element_get_pad_list (GstElement *element);
|
||||||
GstPad* gst_element_get_compatible_pad (GstElement *element, GstPad *pad);
|
GstIterator* gst_element_iterate_pads (GstElement *element);
|
||||||
GstPad* gst_element_get_compatible_pad_filtered (GstElement *element, GstPad *pad,
|
|
||||||
const GstCaps *filtercaps);
|
|
||||||
|
|
||||||
GstPadTemplate* gst_element_class_get_pad_template (GstElementClass *element_class, const gchar *name);
|
|
||||||
GList* gst_element_class_get_pad_template_list (GstElementClass *element_class);
|
|
||||||
GstPadTemplate* gst_element_get_pad_template (GstElement *element, const gchar *name);
|
|
||||||
GList* gst_element_get_pad_template_list (GstElement *element);
|
|
||||||
GstPadTemplate* gst_element_get_compatible_pad_template (GstElement *element, GstPadTemplate *compattempl);
|
|
||||||
|
|
||||||
gboolean gst_element_link (GstElement *src, GstElement *dest);
|
|
||||||
gboolean gst_element_link_many (GstElement *element_1,
|
|
||||||
GstElement *element_2, ...);
|
|
||||||
gboolean gst_element_link_filtered (GstElement *src, GstElement *dest,
|
|
||||||
const GstCaps *filtercaps);
|
|
||||||
void gst_element_unlink (GstElement *src, GstElement *dest);
|
|
||||||
void gst_element_unlink_many (GstElement *element_1,
|
|
||||||
GstElement *element_2, ...);
|
|
||||||
|
|
||||||
gboolean gst_element_link_pads (GstElement *src, const gchar *srcpadname,
|
|
||||||
GstElement *dest, const gchar *destpadname);
|
|
||||||
gboolean gst_element_link_pads_filtered (GstElement *src, const gchar *srcpadname,
|
|
||||||
GstElement *dest, const gchar *destpadname,
|
|
||||||
const GstCaps *filtercaps);
|
|
||||||
void gst_element_unlink_pads (GstElement *src, const gchar *srcpadname,
|
|
||||||
GstElement *dest, const gchar *destpadname);
|
|
||||||
|
|
||||||
|
/* event/query/format stuff */
|
||||||
G_CONST_RETURN GstEventMask*
|
G_CONST_RETURN GstEventMask*
|
||||||
gst_element_get_event_masks (GstElement *element);
|
gst_element_get_event_masks (GstElement *element);
|
||||||
gboolean gst_element_send_event (GstElement *element, GstEvent *event);
|
gboolean gst_element_send_event (GstElement *element, GstEvent *event);
|
||||||
|
@ -372,33 +298,31 @@ gboolean gst_element_convert (GstElement *element,
|
||||||
GstFormat src_format, gint64 src_value,
|
GstFormat src_format, gint64 src_value,
|
||||||
GstFormat *dest_format, gint64 *dest_value);
|
GstFormat *dest_format, gint64 *dest_value);
|
||||||
|
|
||||||
void gst_element_found_tags (GstElement *element, const GstTagList *tag_list);
|
/* messages */
|
||||||
void gst_element_found_tags_for_pad (GstElement *element, GstPad *pad, GstClockTime timestamp,
|
gboolean gst_element_post_message (GstElement *element, GstMessage *message);
|
||||||
GstTagList *list);
|
|
||||||
|
|
||||||
void gst_element_set_eos (GstElement *element);
|
|
||||||
|
|
||||||
|
/* error handling */
|
||||||
gchar * _gst_element_error_printf (const gchar *format, ...);
|
gchar * _gst_element_error_printf (const gchar *format, ...);
|
||||||
void gst_element_error_full (GstElement *element, GQuark domain, gint code,
|
void gst_element_error_full (GstElement *element, GQuark domain, gint code,
|
||||||
gchar *message, gchar *debug,
|
gchar *message, gchar *debug,
|
||||||
const gchar *file, const gchar *function, gint line);
|
const gchar *file, const gchar *function, gint line);
|
||||||
|
|
||||||
|
/* state management */
|
||||||
gboolean gst_element_is_locked_state (GstElement *element);
|
gboolean gst_element_is_locked_state (GstElement *element);
|
||||||
void gst_element_set_locked_state (GstElement *element, gboolean locked_state);
|
void gst_element_set_locked_state (GstElement *element, gboolean locked_state);
|
||||||
gboolean gst_element_sync_state_with_parent (GstElement *element);
|
gboolean gst_element_sync_state_with_parent (GstElement *element);
|
||||||
|
|
||||||
GstElementState gst_element_get_state (GstElement *element);
|
gboolean gst_element_get_state (GstElement *element, GstElementState *state,
|
||||||
|
GstElementState *pending, GTimeVal *timeout);
|
||||||
GstElementStateReturn gst_element_set_state (GstElement *element, GstElementState state);
|
GstElementStateReturn gst_element_set_state (GstElement *element, GstElementState state);
|
||||||
|
|
||||||
void gst_element_wait_state_change (GstElement *element);
|
void gst_element_abort_state (GstElement *element);
|
||||||
|
void gst_element_commit_state (GstElement *element);
|
||||||
G_CONST_RETURN gchar* gst_element_state_get_name (GstElementState state);
|
|
||||||
|
|
||||||
|
/* factory management */
|
||||||
GstElementFactory* gst_element_get_factory (GstElement *element);
|
GstElementFactory* gst_element_get_factory (GstElement *element);
|
||||||
|
|
||||||
GstBin* gst_element_get_managing_bin (GstElement *element);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* factories stuff
|
* factories stuff
|
||||||
|
@ -460,19 +384,7 @@ GstElement* gst_element_factory_create (GstElementFactory *factory,
|
||||||
const gchar *name);
|
const gchar *name);
|
||||||
GstElement* gst_element_factory_make (const gchar *factoryname, const gchar *name);
|
GstElement* gst_element_factory_make (const gchar *factoryname, const gchar *name);
|
||||||
|
|
||||||
gboolean gst_element_factory_can_src_caps (GstElementFactory *factory,
|
|
||||||
const GstCaps *caps);
|
|
||||||
gboolean gst_element_factory_can_sink_caps (GstElementFactory *factory,
|
|
||||||
const GstCaps *caps);
|
|
||||||
|
|
||||||
void __gst_element_factory_add_pad_template (GstElementFactory *elementfactory,
|
|
||||||
GstPadTemplate *templ);
|
|
||||||
void __gst_element_factory_add_interface (GstElementFactory *elementfactory,
|
|
||||||
const gchar *interfacename);
|
|
||||||
|
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
|
||||||
#endif /* __GST_ELEMENT_H__ */
|
#endif /* __GST_ELEMENT_H__ */
|
||||||
|
|
||||||
|
|
|
@ -252,7 +252,7 @@ gst_element_register (GstPlugin * plugin, const gchar * name, guint rank,
|
||||||
|
|
||||||
interfaces = g_type_interfaces (type, &n_interfaces);
|
interfaces = g_type_interfaces (type, &n_interfaces);
|
||||||
for (i = 0; i < n_interfaces; i++) {
|
for (i = 0; i < n_interfaces; i++) {
|
||||||
__gst_element_factory_add_interface (factory, g_type_name (interfaces[i]));
|
//__gst_element_factory_add_interface (factory, g_type_name (interfaces[i]));
|
||||||
}
|
}
|
||||||
g_free (interfaces);
|
g_free (interfaces);
|
||||||
|
|
||||||
|
|
|
@ -38,22 +38,17 @@ typedef enum {
|
||||||
GST_EVENT_UNKNOWN = 0,
|
GST_EVENT_UNKNOWN = 0,
|
||||||
GST_EVENT_EOS = 1,
|
GST_EVENT_EOS = 1,
|
||||||
GST_EVENT_FLUSH = 2,
|
GST_EVENT_FLUSH = 2,
|
||||||
GST_EVENT_EMPTY = 3,
|
GST_EVENT_CAPS = 3,
|
||||||
GST_EVENT_DISCONTINUOUS = 4,
|
GST_EVENT_DISCONTINUOUS = 4,
|
||||||
/*GST_EVENT_NEW_MEDIA = 5, <- removed */
|
GST_EVENT_QOS = 5,
|
||||||
GST_EVENT_QOS = 6,
|
GST_EVENT_SEEK = 6,
|
||||||
GST_EVENT_SEEK = 7,
|
GST_EVENT_SEEK_SEGMENT = 7,
|
||||||
GST_EVENT_SEEK_SEGMENT = 8,
|
GST_EVENT_SEGMENT_DONE = 8,
|
||||||
GST_EVENT_SEGMENT_DONE = 9,
|
GST_EVENT_SIZE = 9,
|
||||||
GST_EVENT_SIZE = 10,
|
GST_EVENT_RATE = 10,
|
||||||
GST_EVENT_RATE = 11,
|
GST_EVENT_NAVIGATION = 11,
|
||||||
GST_EVENT_FILLER = 12,
|
GST_EVENT_TAG = 12
|
||||||
GST_EVENT_TS_OFFSET = 13,
|
|
||||||
GST_EVENT_INTERRUPT = 14,
|
|
||||||
GST_EVENT_NAVIGATION = 15,
|
|
||||||
GST_EVENT_TAG = 16
|
|
||||||
} GstEventType;
|
} GstEventType;
|
||||||
#define GST_EVENT_ANY GST_EVENT_NAVIGATION
|
|
||||||
|
|
||||||
#define GST_EVENT_TRACE_NAME "GstEvent"
|
#define GST_EVENT_TRACE_NAME "GstEvent"
|
||||||
|
|
||||||
|
@ -87,7 +82,6 @@ typedef struct
|
||||||
GstEventFlag flags;
|
GstEventFlag flags;
|
||||||
} GstEventMask;
|
} GstEventMask;
|
||||||
|
|
||||||
#ifndef GST_DISABLE_DEPRECATED
|
|
||||||
#ifdef G_HAVE_ISO_VARARGS
|
#ifdef G_HAVE_ISO_VARARGS
|
||||||
#define GST_EVENT_MASK_FUNCTION(type,functionname, ...) \
|
#define GST_EVENT_MASK_FUNCTION(type,functionname, ...) \
|
||||||
static const GstEventMask* \
|
static const GstEventMask* \
|
||||||
|
@ -111,7 +105,6 @@ functionname (type pad) \
|
||||||
return masks; \
|
return masks; \
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
/* seek events, extends GstEventFlag */
|
/* seek events, extends GstEventFlag */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
|
@ -515,7 +515,8 @@ gst_index_gtype_resolver (GstIndex * index, GstObject * writer,
|
||||||
gchar ** writer_string, gpointer data)
|
gchar ** writer_string, gpointer data)
|
||||||
{
|
{
|
||||||
if (GST_IS_PAD (writer)) {
|
if (GST_IS_PAD (writer)) {
|
||||||
GstElement *element = gst_pad_get_parent (GST_PAD (writer));
|
GstElement *element =
|
||||||
|
(GstElement *) gst_object_get_parent (GST_OBJECT (writer));
|
||||||
|
|
||||||
*writer_string = g_strdup_printf ("%s.%s",
|
*writer_string = g_strdup_printf ("%s.%s",
|
||||||
g_type_name (G_OBJECT_TYPE (element)), gst_object_get_name (writer));
|
g_type_name (G_OBJECT_TYPE (element)), gst_object_get_name (writer));
|
||||||
|
|
|
@ -153,6 +153,7 @@ GstDebugCategory *GST_CAT_NEGOTIATION = NULL;
|
||||||
GstDebugCategory *GST_CAT_REFCOUNTING = NULL;
|
GstDebugCategory *GST_CAT_REFCOUNTING = NULL;
|
||||||
GstDebugCategory *GST_CAT_ERROR_SYSTEM = NULL;
|
GstDebugCategory *GST_CAT_ERROR_SYSTEM = NULL;
|
||||||
GstDebugCategory *GST_CAT_EVENT = NULL;
|
GstDebugCategory *GST_CAT_EVENT = NULL;
|
||||||
|
GstDebugCategory *GST_CAT_MESSAGE = NULL;
|
||||||
GstDebugCategory *GST_CAT_PARAMS = NULL;
|
GstDebugCategory *GST_CAT_PARAMS = NULL;
|
||||||
GstDebugCategory *GST_CAT_CALL_TRACE = NULL;
|
GstDebugCategory *GST_CAT_CALL_TRACE = NULL;
|
||||||
GstDebugCategory *GST_CAT_SEEK = NULL;
|
GstDebugCategory *GST_CAT_SEEK = NULL;
|
||||||
|
@ -272,6 +273,8 @@ _gst_debug_init (void)
|
||||||
|
|
||||||
GST_CAT_EVENT = _gst_debug_category_new ("GST_EVENT",
|
GST_CAT_EVENT = _gst_debug_category_new ("GST_EVENT",
|
||||||
GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED, NULL);
|
GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED, NULL);
|
||||||
|
GST_CAT_MESSAGE = _gst_debug_category_new ("GST_MESSAGE",
|
||||||
|
GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED, NULL);
|
||||||
GST_CAT_PARAMS = _gst_debug_category_new ("GST_PARAMS",
|
GST_CAT_PARAMS = _gst_debug_category_new ("GST_PARAMS",
|
||||||
GST_DEBUG_BOLD | GST_DEBUG_FG_BLACK | GST_DEBUG_BG_YELLOW, NULL);
|
GST_DEBUG_BOLD | GST_DEBUG_FG_BLACK | GST_DEBUG_BG_YELLOW, NULL);
|
||||||
GST_CAT_CALL_TRACE = _gst_debug_category_new ("GST_CALL_TRACE",
|
GST_CAT_CALL_TRACE = _gst_debug_category_new ("GST_CALL_TRACE",
|
||||||
|
|
|
@ -179,7 +179,10 @@ gst_object_class_init (GstObjectClass * klass)
|
||||||
static void
|
static void
|
||||||
gst_object_init (GstObject * object)
|
gst_object_init (GstObject * object)
|
||||||
{
|
{
|
||||||
|
//object->lock = g_new0(GStaticRecMutex, 1);
|
||||||
|
//g_static_rec_mutex_init (object->lock);
|
||||||
object->lock = g_mutex_new ();
|
object->lock = g_mutex_new ();
|
||||||
|
|
||||||
object->parent = NULL;
|
object->parent = NULL;
|
||||||
object->name = NULL;
|
object->name = NULL;
|
||||||
|
|
||||||
|
@ -225,6 +228,7 @@ gst_object_ref (GstObject * object)
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "ref %d->%d",
|
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "ref %d->%d",
|
||||||
G_OBJECT (object)->ref_count, G_OBJECT (object)->ref_count + 1);
|
G_OBJECT (object)->ref_count, G_OBJECT (object)->ref_count + 1);
|
||||||
|
|
||||||
|
/* FIXME, not threadsafe */
|
||||||
g_object_ref (G_OBJECT (object));
|
g_object_ref (G_OBJECT (object));
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
@ -245,6 +249,7 @@ gst_object_unref (GstObject * object)
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "unref %d->%d",
|
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "unref %d->%d",
|
||||||
G_OBJECT (object)->ref_count, G_OBJECT (object)->ref_count - 1);
|
G_OBJECT (object)->ref_count, G_OBJECT (object)->ref_count - 1);
|
||||||
|
|
||||||
|
/* FIXME, not threadsafe */
|
||||||
g_object_unref (G_OBJECT (object));
|
g_object_unref (G_OBJECT (object));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,7 +330,9 @@ gst_object_finalize (GObject * object)
|
||||||
|
|
||||||
g_free (gstobject->name);
|
g_free (gstobject->name);
|
||||||
|
|
||||||
|
//g_static_rec_mutex_free (gstobject->lock);
|
||||||
g_mutex_free (gstobject->lock);
|
g_mutex_free (gstobject->lock);
|
||||||
|
g_free (gstobject->lock);
|
||||||
|
|
||||||
#ifndef GST_DISABLE_TRACE
|
#ifndef GST_DISABLE_TRACE
|
||||||
{
|
{
|
||||||
|
@ -342,6 +349,8 @@ gst_object_finalize (GObject * object)
|
||||||
parent_class->finalize (object);
|
parent_class->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GStaticRecMutex dispatch_mutex = G_STATIC_REC_MUTEX_INIT;
|
||||||
|
|
||||||
/* Changing a GObject property of a GstObject will result in "deep_notify"
|
/* Changing a GObject property of a GstObject will result in "deep_notify"
|
||||||
* signals being emitted by the object itself, as well as in each parent
|
* signals being emitted by the object itself, as well as in each parent
|
||||||
* object. This is so that an application can connect a listener to the
|
* object. This is so that an application can connect a listener to the
|
||||||
|
@ -354,6 +363,7 @@ gst_object_dispatch_properties_changed (GObject * object,
|
||||||
GstObject *gst_object;
|
GstObject *gst_object;
|
||||||
guint i;
|
guint i;
|
||||||
|
|
||||||
|
g_static_rec_mutex_lock (&dispatch_mutex);
|
||||||
/* do the standard dispatching */
|
/* do the standard dispatching */
|
||||||
G_OBJECT_CLASS (parent_class)->dispatch_properties_changed (object, n_pspecs,
|
G_OBJECT_CLASS (parent_class)->dispatch_properties_changed (object, n_pspecs,
|
||||||
pspecs);
|
pspecs);
|
||||||
|
@ -367,6 +377,7 @@ gst_object_dispatch_properties_changed (GObject * object,
|
||||||
GST_OBJECT_NAME (object) ? GST_OBJECT_NAME (object) : "(null)",
|
GST_OBJECT_NAME (object) ? GST_OBJECT_NAME (object) : "(null)",
|
||||||
GST_OBJECT_NAME (gst_object) ? GST_OBJECT_NAME (gst_object) :
|
GST_OBJECT_NAME (gst_object) ? GST_OBJECT_NAME (gst_object) :
|
||||||
"(null)", pspecs[i]->name);
|
"(null)", pspecs[i]->name);
|
||||||
|
/* FIXME, not thread safe */
|
||||||
g_signal_emit (gst_object, gst_object_signals[DEEP_NOTIFY],
|
g_signal_emit (gst_object, gst_object_signals[DEEP_NOTIFY],
|
||||||
g_quark_from_string (pspecs[i]->name), (GstObject *) object,
|
g_quark_from_string (pspecs[i]->name), (GstObject *) object,
|
||||||
pspecs[i]);
|
pspecs[i]);
|
||||||
|
@ -374,6 +385,7 @@ gst_object_dispatch_properties_changed (GObject * object,
|
||||||
|
|
||||||
gst_object = GST_OBJECT_PARENT (gst_object);
|
gst_object = GST_OBJECT_PARENT (gst_object);
|
||||||
}
|
}
|
||||||
|
g_static_rec_mutex_unlock (&dispatch_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -481,13 +493,19 @@ gst_object_set_name (GstObject * object, const gchar * name)
|
||||||
g_return_if_fail (object != NULL);
|
g_return_if_fail (object != NULL);
|
||||||
g_return_if_fail (GST_IS_OBJECT (object));
|
g_return_if_fail (GST_IS_OBJECT (object));
|
||||||
|
|
||||||
|
GST_LOCK (object);
|
||||||
if (object->name != NULL)
|
if (object->name != NULL)
|
||||||
g_free (object->name);
|
g_free (object->name);
|
||||||
|
|
||||||
if (name != NULL)
|
if (name != NULL)
|
||||||
object->name = g_strdup (name);
|
object->name = g_strdup (name);
|
||||||
else
|
else {
|
||||||
|
GST_UNLOCK (object);
|
||||||
gst_object_set_name_default (object);
|
gst_object_set_name_default (object);
|
||||||
|
GST_LOCK (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_UNLOCK (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -501,9 +519,15 @@ gst_object_set_name (GstObject * object, const gchar * name)
|
||||||
const gchar *
|
const gchar *
|
||||||
gst_object_get_name (GstObject * object)
|
gst_object_get_name (GstObject * object)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
|
const gchar *result = NULL;
|
||||||
|
|
||||||
return object->name;
|
g_return_val_if_fail (GST_IS_OBJECT (object), result);
|
||||||
|
|
||||||
|
GST_LOCK (object);
|
||||||
|
result = object->name;
|
||||||
|
GST_UNLOCK (object);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -519,17 +543,18 @@ gst_object_get_name (GstObject * object)
|
||||||
void
|
void
|
||||||
gst_object_set_parent (GstObject * object, GstObject * parent)
|
gst_object_set_parent (GstObject * object, GstObject * parent)
|
||||||
{
|
{
|
||||||
g_return_if_fail (object != NULL);
|
|
||||||
g_return_if_fail (GST_IS_OBJECT (object));
|
g_return_if_fail (GST_IS_OBJECT (object));
|
||||||
g_return_if_fail (parent != NULL);
|
|
||||||
g_return_if_fail (GST_IS_OBJECT (parent));
|
g_return_if_fail (GST_IS_OBJECT (parent));
|
||||||
g_return_if_fail (object != parent);
|
g_return_if_fail (object != parent);
|
||||||
g_return_if_fail (object->parent == NULL);
|
g_return_if_fail (object->parent == NULL);
|
||||||
|
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "set parent (ref and sink)");
|
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "set parent (ref and sink)");
|
||||||
|
|
||||||
|
GST_LOCK (object);
|
||||||
gst_object_ref (object);
|
gst_object_ref (object);
|
||||||
gst_object_sink (object);
|
gst_object_sink (object);
|
||||||
object->parent = parent;
|
object->parent = parent;
|
||||||
|
GST_UNLOCK (object);
|
||||||
|
|
||||||
g_signal_emit (G_OBJECT (object), gst_object_signals[PARENT_SET], 0, parent);
|
g_signal_emit (G_OBJECT (object), gst_object_signals[PARENT_SET], 0, parent);
|
||||||
}
|
}
|
||||||
|
@ -545,10 +570,15 @@ gst_object_set_parent (GstObject * object, GstObject * parent)
|
||||||
GstObject *
|
GstObject *
|
||||||
gst_object_get_parent (GstObject * object)
|
gst_object_get_parent (GstObject * object)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (object != NULL, NULL);
|
GstObject *result = NULL;
|
||||||
g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
|
|
||||||
|
|
||||||
return object->parent;
|
g_return_val_if_fail (GST_IS_OBJECT (object), result);
|
||||||
|
|
||||||
|
GST_LOCK (object);
|
||||||
|
result = object->parent;
|
||||||
|
GST_UNLOCK (object);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -560,17 +590,24 @@ gst_object_get_parent (GstObject * object)
|
||||||
void
|
void
|
||||||
gst_object_unparent (GstObject * object)
|
gst_object_unparent (GstObject * object)
|
||||||
{
|
{
|
||||||
g_return_if_fail (object != NULL);
|
GstObject *parent;
|
||||||
g_return_if_fail (GST_IS_OBJECT (object));
|
|
||||||
if (object->parent == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
|
g_return_if_fail (GST_IS_OBJECT (object));
|
||||||
|
|
||||||
|
GST_LOCK (object);
|
||||||
|
parent = object->parent;
|
||||||
|
|
||||||
|
if (parent == NULL) {
|
||||||
|
GST_UNLOCK (object);
|
||||||
|
return;
|
||||||
|
}
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "unparent");
|
GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "unparent");
|
||||||
|
object->parent = NULL;
|
||||||
|
GST_UNLOCK (object);
|
||||||
|
|
||||||
g_signal_emit (G_OBJECT (object), gst_object_signals[PARENT_UNSET], 0,
|
g_signal_emit (G_OBJECT (object), gst_object_signals[PARENT_UNSET], 0,
|
||||||
object->parent);
|
parent);
|
||||||
|
|
||||||
object->parent = NULL;
|
|
||||||
gst_object_unref (object);
|
gst_object_unref (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,7 +630,7 @@ gst_object_check_uniqueness (GList * list, const gchar * name)
|
||||||
|
|
||||||
list = g_list_next (list);
|
list = g_list_next (list);
|
||||||
|
|
||||||
if (strcmp (GST_OBJECT_NAME (child), name) == 0)
|
if (strcmp (gst_object_get_name (child), name) == 0)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,13 +55,30 @@ typedef enum
|
||||||
GST_OBJECT_FLAG_LAST = 4
|
GST_OBJECT_FLAG_LAST = 4
|
||||||
} GstObjectFlags;
|
} GstObjectFlags;
|
||||||
|
|
||||||
|
#ifdef USE_REC_LOCKS
|
||||||
|
#define GST_LOCK(obj) (g_static_rec_mutex_lock(GST_OBJECT(obj)->lock))
|
||||||
|
#define GST_TRYLOCK(obj) (g_static_rec_mutex_trylock(GST_OBJECT(obj)->lock))
|
||||||
|
#define GST_UNLOCK(obj) (g_static_rec_mutex_unlock(GST_OBJECT(obj)->lock))
|
||||||
|
#define GST_GET_LOCK(obj) (g_static_mutex_get_mutex(&GST_OBJECT(obj)->lock->mutex))
|
||||||
|
#define GST_LOCK_TYPE GStaticRecMutex
|
||||||
|
#define GST_LOCK_CREATE g_static_rec_mutex_new()
|
||||||
|
#else
|
||||||
|
#define GST_LOCK(obj) (g_mutex_lock(GST_OBJECT(obj)->lock))
|
||||||
|
#define GST_TRYLOCK(obj) (g_mutex_trylock(GST_OBJECT(obj)->lock))
|
||||||
|
#define GST_UNLOCK(obj) (g_mutex_unlock(GST_OBJECT(obj)->lock))
|
||||||
|
#define GST_GET_LOCK(obj) (GST_OBJECT(obj)->lock)
|
||||||
|
#define GST_LOCK_TYPE GMutex
|
||||||
|
#define GST_LOCK_CREATE g_mutex_new()
|
||||||
|
#endif
|
||||||
|
|
||||||
struct _GstObject {
|
struct _GstObject {
|
||||||
GObject object;
|
GObject object;
|
||||||
|
|
||||||
gchar *name;
|
gchar *name;
|
||||||
|
|
||||||
/* locking for all sorts of things */
|
/* locking for all sorts of things */
|
||||||
GMutex *lock;
|
GST_LOCK_TYPE *lock;
|
||||||
|
|
||||||
/* this object's parent */
|
/* this object's parent */
|
||||||
GstObject *parent;
|
GstObject *parent;
|
||||||
|
|
||||||
|
@ -103,11 +120,6 @@ struct _GstObjectClass {
|
||||||
#define GST_OBJECT_DESTROYED(obj) (GST_FLAG_IS_SET (obj, GST_DESTROYED))
|
#define GST_OBJECT_DESTROYED(obj) (GST_FLAG_IS_SET (obj, GST_DESTROYED))
|
||||||
#define GST_OBJECT_FLOATING(obj) (GST_FLAG_IS_SET (obj, GST_FLOATING))
|
#define GST_OBJECT_FLOATING(obj) (GST_FLAG_IS_SET (obj, GST_FLOATING))
|
||||||
|
|
||||||
/* CR1: object locking - GObject 2.0 doesn't have threadsafe locking */
|
|
||||||
#define GST_LOCK(obj) (g_mutex_lock(GST_OBJECT(obj)->lock))
|
|
||||||
#define GST_TRYLOCK(obj) (g_mutex_trylock(GST_OBJECT(obj)->lock))
|
|
||||||
#define GST_UNLOCK(obj) (g_mutex_unlock(GST_OBJECT(obj)->lock))
|
|
||||||
#define GST_GET_LOCK(obj) (GST_OBJECT(obj)->lock)
|
|
||||||
|
|
||||||
|
|
||||||
/* normal GObject stuff */
|
/* normal GObject stuff */
|
||||||
|
|
2902
gst/gstpad.c
2902
gst/gstpad.c
File diff suppressed because it is too large
Load diff
226
gst/gstpad.h
226
gst/gstpad.h
|
@ -50,6 +50,7 @@ GST_EXPORT GType _gst_ghost_pad_type;
|
||||||
#define GST_IS_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PAD))
|
#define GST_IS_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PAD))
|
||||||
#define GST_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PAD, GstPad))
|
#define GST_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PAD, GstPad))
|
||||||
#define GST_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PAD, GstPadClass))
|
#define GST_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PAD, GstPadClass))
|
||||||
|
#define GST_PAD_CAST(obj) ((GstPad*)(obj))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Real Pads
|
* Real Pads
|
||||||
|
@ -60,6 +61,7 @@ GST_EXPORT GType _gst_ghost_pad_type;
|
||||||
#define GST_IS_REAL_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_REAL_PAD))
|
#define GST_IS_REAL_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_REAL_PAD))
|
||||||
#define GST_REAL_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_REAL_PAD, GstRealPad))
|
#define GST_REAL_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_REAL_PAD, GstRealPad))
|
||||||
#define GST_REAL_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_REAL_PAD, GstRealPadClass))
|
#define GST_REAL_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_REAL_PAD, GstRealPadClass))
|
||||||
|
#define GST_REAL_PAD_CAST(obj) ((GstRealPad*)(obj))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ghost Pads
|
* Ghost Pads
|
||||||
|
@ -70,6 +72,7 @@ GST_EXPORT GType _gst_ghost_pad_type;
|
||||||
#define GST_IS_GHOST_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_GHOST_PAD))
|
#define GST_IS_GHOST_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_GHOST_PAD))
|
||||||
#define GST_GHOST_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_GHOST_PAD, GstGhostPad))
|
#define GST_GHOST_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_GHOST_PAD, GstGhostPad))
|
||||||
#define GST_GHOST_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_GHOST_PAD, GstGhostPadClass))
|
#define GST_GHOST_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_GHOST_PAD, GstGhostPadClass))
|
||||||
|
#define GST_GHOST_PAD_CAST(obj) ((GstGhostPad*)(obj))
|
||||||
|
|
||||||
|
|
||||||
/*typedef struct _GstPad GstPad; */
|
/*typedef struct _GstPad GstPad; */
|
||||||
|
@ -84,17 +87,27 @@ typedef struct _GstStaticPadTemplate GstStaticPadTemplate;
|
||||||
typedef struct _GstPadLink GstPadLink;
|
typedef struct _GstPadLink GstPadLink;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GST_PAD_LINK_REFUSED = -1,
|
GST_PAD_LINK_NOSCHED = -3, /* pads cannot cooperate in scheduling */
|
||||||
GST_PAD_LINK_DELAYED = 0,
|
GST_PAD_LINK_NOFORMAT = -2, /* pads do not have common format */
|
||||||
GST_PAD_LINK_OK = 1,
|
GST_PAD_LINK_REFUSED = -1, /* refused for some reason */
|
||||||
GST_PAD_LINK_DONE = 2
|
GST_PAD_LINK_OK = 0, /* link ok */
|
||||||
} GstPadLinkReturn;
|
} GstPadLinkReturn;
|
||||||
|
|
||||||
#define GST_PAD_LINK_FAILED(ret) (ret < GST_PAD_LINK_OK)
|
#define GST_PAD_LINK_FAILED(ret) (ret < GST_PAD_LINK_OK)
|
||||||
#define GST_PAD_LINK_SUCCESSFUL(ret) (ret >= GST_PAD_LINK_OK)
|
#define GST_PAD_LINK_SUCCESSFUL(ret) (ret >= GST_PAD_LINK_OK)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GST_FLOW_OK = 0, /* data passing was ok */
|
||||||
|
GST_FLOW_RESEND = 1, /* resend buffer, possibly with new caps */
|
||||||
|
GST_FLOW_ERROR = -1, /* some error occured */
|
||||||
|
GST_FLOW_NOT_CONNECTED = -2, /* pad is not connected */
|
||||||
|
GST_FLOW_NOT_NEGOTIATED = -3, /* pad is not negotiated */
|
||||||
|
GST_FLOW_WRONG_STATE = -4, /* pad is in wrong state */
|
||||||
|
GST_FLOW_UNEXPECTED = -5, /* did not expect anything */
|
||||||
|
GST_FLOW_NOT_SUPPORTED = -6 /* function not supported */
|
||||||
|
} GstFlowReturn;
|
||||||
|
|
||||||
/* convenience functions */
|
/* convenience functions */
|
||||||
#ifndef GST_DISABLE_DEPRECATED
|
|
||||||
#ifdef G_HAVE_ISO_VARARGS
|
#ifdef G_HAVE_ISO_VARARGS
|
||||||
#define GST_PAD_QUERY_TYPE_FUNCTION(functionname, ...) GST_QUERY_TYPE_FUNCTION (GstPad *, functionname, __VA_ARGS__);
|
#define GST_PAD_QUERY_TYPE_FUNCTION(functionname, ...) GST_QUERY_TYPE_FUNCTION (GstPad *, functionname, __VA_ARGS__);
|
||||||
#define GST_PAD_FORMATS_FUNCTION(functionname, ...) GST_FORMATS_FUNCTION (GstPad *, functionname, __VA_ARGS__);
|
#define GST_PAD_FORMATS_FUNCTION(functionname, ...) GST_FORMATS_FUNCTION (GstPad *, functionname, __VA_ARGS__);
|
||||||
|
@ -104,15 +117,19 @@ typedef enum {
|
||||||
#define GST_PAD_FORMATS_FUNCTION(functionname, a...) GST_FORMATS_FUNCTION (GstPad *, functionname, a);
|
#define GST_PAD_FORMATS_FUNCTION(functionname, a...) GST_FORMATS_FUNCTION (GstPad *, functionname, a);
|
||||||
#define GST_PAD_EVENT_MASK_FUNCTION(functionname, a...) GST_EVENT_MASK_FUNCTION (GstPad *, functionname, a);
|
#define GST_PAD_EVENT_MASK_FUNCTION(functionname, a...) GST_EVENT_MASK_FUNCTION (GstPad *, functionname, a);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* this defines the functions used to chain buffers
|
/* pad states */
|
||||||
* pad is the sink pad (so the same chain function can be used for N pads)
|
typedef gboolean (*GstPadActivateFunction) (GstPad *pad, gboolean active);
|
||||||
* buf is the buffer being passed */
|
|
||||||
typedef void (*GstPadChainFunction) (GstPad *pad,GstData *data);
|
/* data passing */
|
||||||
typedef GstData* (*GstPadGetFunction) (GstPad *pad);
|
typedef GstFlowReturn (*GstPadChainFunction) (GstPad *pad, GstBuffer *buffer);
|
||||||
|
typedef GstFlowReturn (*GstPadGetFunction) (GstPad *pad, GstBuffer **buffer);
|
||||||
|
typedef GstFlowReturn (*GstPadGetRangeFunction) (GstPad *pad, guint64 offset,
|
||||||
|
guint64 length, GstBuffer **buffer);
|
||||||
typedef gboolean (*GstPadEventFunction) (GstPad *pad, GstEvent *event);
|
typedef gboolean (*GstPadEventFunction) (GstPad *pad, GstEvent *event);
|
||||||
|
|
||||||
|
/* convert/query/format functions */
|
||||||
typedef gboolean (*GstPadConvertFunction) (GstPad *pad,
|
typedef gboolean (*GstPadConvertFunction) (GstPad *pad,
|
||||||
GstFormat src_format, gint64 src_value,
|
GstFormat src_format, gint64 src_value,
|
||||||
GstFormat *dest_format, gint64 *dest_value);
|
GstFormat *dest_format, gint64 *dest_value);
|
||||||
|
@ -123,14 +140,19 @@ typedef const GstFormat* (*GstPadFormatsFunction) (GstPad *pad);
|
||||||
typedef const GstEventMask* (*GstPadEventMaskFunction) (GstPad *pad);
|
typedef const GstEventMask* (*GstPadEventMaskFunction) (GstPad *pad);
|
||||||
typedef const GstQueryType* (*GstPadQueryTypeFunction) (GstPad *pad);
|
typedef const GstQueryType* (*GstPadQueryTypeFunction) (GstPad *pad);
|
||||||
|
|
||||||
typedef GstPadLinkReturn (*GstPadLinkFunction) (GstPad *pad, const GstCaps *caps);
|
/* linking */
|
||||||
|
typedef GstPadLinkReturn (*GstPadLinkFunction) (GstPad *pad, GstPad *peer);
|
||||||
typedef void (*GstPadUnlinkFunction) (GstPad *pad);
|
typedef void (*GstPadUnlinkFunction) (GstPad *pad);
|
||||||
typedef GstCaps* (*GstPadGetCapsFunction) (GstPad *pad);
|
|
||||||
typedef GstCaps* (*GstPadFixateFunction) (GstPad *pad, const GstCaps *caps);
|
|
||||||
typedef GstBuffer* (*GstPadBufferAllocFunction) (GstPad *pad, guint64 offset, guint size);
|
|
||||||
|
|
||||||
|
/* caps nego */
|
||||||
|
typedef GstCaps* (*GstPadGetCapsFunction) (GstPad *pad);
|
||||||
|
typedef GstBuffer* (*GstPadBufferAllocFunction) (GstPad *pad, guint64 offset, guint size,
|
||||||
|
GstCaps *caps);
|
||||||
|
/* misc */
|
||||||
typedef gboolean (*GstPadDispatcherFunction) (GstPad *pad, gpointer data);
|
typedef gboolean (*GstPadDispatcherFunction) (GstPad *pad, gpointer data);
|
||||||
|
|
||||||
|
typedef void (*GstPadBlockCallback) (GstPad *pad, gboolean blocked, gpointer user_data);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GST_PAD_UNKNOWN,
|
GST_PAD_UNKNOWN,
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
|
@ -139,6 +161,7 @@ typedef enum {
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GST_PAD_DISABLED = GST_OBJECT_FLAG_LAST,
|
GST_PAD_DISABLED = GST_OBJECT_FLAG_LAST,
|
||||||
|
GST_PAD_BLOCKED,
|
||||||
GST_PAD_NEGOTIATING,
|
GST_PAD_NEGOTIATING,
|
||||||
GST_PAD_DISPATCHING,
|
GST_PAD_DISPATCHING,
|
||||||
|
|
||||||
|
@ -164,15 +187,24 @@ struct _GstPadClass {
|
||||||
struct _GstRealPad {
|
struct _GstRealPad {
|
||||||
GstPad pad;
|
GstPad pad;
|
||||||
|
|
||||||
|
/* streaming lock and cond */
|
||||||
|
GMutex *stream_lock;
|
||||||
|
GCond *stream_cond;
|
||||||
|
|
||||||
|
/* block cond, mutex is from the object */
|
||||||
|
GCond *block_cond;
|
||||||
|
GstPadBlockCallback block_callback;
|
||||||
|
gpointer block_data;
|
||||||
|
|
||||||
/* the pad capabilities */
|
/* the pad capabilities */
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
GstPadFixateFunction appfixatefunc;
|
|
||||||
GstCaps *appfilter;
|
GstCaps *appfilter;
|
||||||
GstPadGetCapsFunction getcapsfunc;
|
GstPadGetCapsFunction getcapsfunc;
|
||||||
GstPadFixateFunction fixatefunc;
|
|
||||||
|
|
||||||
GstPadDirection direction;
|
GstPadDirection direction;
|
||||||
|
|
||||||
|
GstPadActivateFunction activatefunc;
|
||||||
|
|
||||||
GstPadLinkFunction linkfunc;
|
GstPadLinkFunction linkfunc;
|
||||||
GstPadUnlinkFunction unlinkfunc;
|
GstPadUnlinkFunction unlinkfunc;
|
||||||
GstRealPad *peer;
|
GstRealPad *peer;
|
||||||
|
@ -181,11 +213,10 @@ struct _GstRealPad {
|
||||||
|
|
||||||
/* data transport functions */
|
/* data transport functions */
|
||||||
GstPadChainFunction chainfunc;
|
GstPadChainFunction chainfunc;
|
||||||
GstPadChainFunction chainhandler;
|
|
||||||
GstPadGetFunction getfunc;
|
GstPadGetFunction getfunc;
|
||||||
GstPadGetFunction gethandler;
|
GstPadGetRangeFunction getrangefunc;
|
||||||
GstPadEventFunction eventfunc;
|
GstPadEventFunction eventfunc;
|
||||||
GstPadEventFunction eventhandler;
|
|
||||||
GstPadEventMaskFunction eventmaskfunc;
|
GstPadEventMaskFunction eventmaskfunc;
|
||||||
|
|
||||||
GList *ghostpads;
|
GList *ghostpads;
|
||||||
|
@ -197,13 +228,10 @@ struct _GstRealPad {
|
||||||
GstPadQueryTypeFunction querytypefunc;
|
GstPadQueryTypeFunction querytypefunc;
|
||||||
GstPadIntLinkFunction intlinkfunc;
|
GstPadIntLinkFunction intlinkfunc;
|
||||||
|
|
||||||
GstPadBufferAllocFunction bufferallocfunc;
|
GstPadBufferAllocFunction bufferallocfunc;
|
||||||
|
|
||||||
GstProbeDispatcher probedisp;
|
GstProbeDispatcher probedisp;
|
||||||
|
|
||||||
GstPadLink *link;
|
|
||||||
GstCaps *explicit_caps;
|
|
||||||
|
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
gpointer _gst_reserved[GST_PADDING];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -211,11 +239,9 @@ struct _GstRealPadClass {
|
||||||
GstPadClass parent_class;
|
GstPadClass parent_class;
|
||||||
|
|
||||||
/* signal callbacks */
|
/* signal callbacks */
|
||||||
void (*caps_nego_failed) (GstPad *pad, GstCaps *caps);
|
|
||||||
|
|
||||||
void (*linked) (GstPad *pad, GstPad *peer);
|
void (*linked) (GstPad *pad, GstPad *peer);
|
||||||
void (*unlinked) (GstPad *pad, GstPad *peer);
|
void (*unlinked) (GstPad *pad, GstPad *peer);
|
||||||
GstPadFixateFunction appfixatefunc;
|
void (*request_link) (GstPad *pad);
|
||||||
|
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
gpointer _gst_reserved[GST_PADDING];
|
||||||
};
|
};
|
||||||
|
@ -247,12 +273,11 @@ struct _GstGhostPadClass {
|
||||||
#define GST_RPAD_CAPS(pad) (((GstRealPad *)(pad))->caps)
|
#define GST_RPAD_CAPS(pad) (((GstRealPad *)(pad))->caps)
|
||||||
#define GST_RPAD_APPFILTER(pad) (((GstRealPad *)(pad))->appfilter)
|
#define GST_RPAD_APPFILTER(pad) (((GstRealPad *)(pad))->appfilter)
|
||||||
#define GST_RPAD_PEER(pad) (((GstRealPad *)(pad))->peer)
|
#define GST_RPAD_PEER(pad) (((GstRealPad *)(pad))->peer)
|
||||||
|
#define GST_RPAD_ACTIVATEFUNC(pad) (((GstRealPad *)(pad))->activatefunc)
|
||||||
#define GST_RPAD_CHAINFUNC(pad) (((GstRealPad *)(pad))->chainfunc)
|
#define GST_RPAD_CHAINFUNC(pad) (((GstRealPad *)(pad))->chainfunc)
|
||||||
#define GST_RPAD_CHAINHANDLER(pad) (((GstRealPad *)(pad))->chainhandler)
|
|
||||||
#define GST_RPAD_GETFUNC(pad) (((GstRealPad *)(pad))->getfunc)
|
#define GST_RPAD_GETFUNC(pad) (((GstRealPad *)(pad))->getfunc)
|
||||||
#define GST_RPAD_GETHANDLER(pad) (((GstRealPad *)(pad))->gethandler)
|
#define GST_RPAD_GETRANGEFUNC(pad) (((GstRealPad *)(pad))->getrangefunc)
|
||||||
#define GST_RPAD_EVENTFUNC(pad) (((GstRealPad *)(pad))->eventfunc)
|
#define GST_RPAD_EVENTFUNC(pad) (((GstRealPad *)(pad))->eventfunc)
|
||||||
#define GST_RPAD_EVENTHANDLER(pad) (((GstRealPad *)(pad))->eventhandler)
|
|
||||||
#define GST_RPAD_CONVERTFUNC(pad) (((GstRealPad *)(pad))->convertfunc)
|
#define GST_RPAD_CONVERTFUNC(pad) (((GstRealPad *)(pad))->convertfunc)
|
||||||
#define GST_RPAD_QUERYFUNC(pad) (((GstRealPad *)(pad))->queryfunc)
|
#define GST_RPAD_QUERYFUNC(pad) (((GstRealPad *)(pad))->queryfunc)
|
||||||
#define GST_RPAD_INTLINKFUNC(pad) (((GstRealPad *)(pad))->intlinkfunc)
|
#define GST_RPAD_INTLINKFUNC(pad) (((GstRealPad *)(pad))->intlinkfunc)
|
||||||
|
@ -263,10 +288,28 @@ struct _GstGhostPadClass {
|
||||||
#define GST_RPAD_LINKFUNC(pad) (((GstRealPad *)(pad))->linkfunc)
|
#define GST_RPAD_LINKFUNC(pad) (((GstRealPad *)(pad))->linkfunc)
|
||||||
#define GST_RPAD_UNLINKFUNC(pad) (((GstRealPad *)(pad))->unlinkfunc)
|
#define GST_RPAD_UNLINKFUNC(pad) (((GstRealPad *)(pad))->unlinkfunc)
|
||||||
#define GST_RPAD_GETCAPSFUNC(pad) (((GstRealPad *)(pad))->getcapsfunc)
|
#define GST_RPAD_GETCAPSFUNC(pad) (((GstRealPad *)(pad))->getcapsfunc)
|
||||||
#define GST_RPAD_FIXATEFUNC(pad) (((GstRealPad *)(pad))->fixatefunc)
|
|
||||||
#define GST_RPAD_BUFFERALLOCFUNC(pad) (((GstRealPad *)(pad))->bufferallocfunc)
|
#define GST_RPAD_BUFFERALLOCFUNC(pad) (((GstRealPad *)(pad))->bufferallocfunc)
|
||||||
#define GST_RPAD_LINK(pad) (((GstRealPad *)(pad))->link)
|
|
||||||
#define GST_RPAD_EXPLICIT_CAPS(pad) (((GstRealPad *)(pad))->explicit_caps)
|
#define GST_RPAD_IS_LINKED(pad) (GST_RPAD_PEER(pad) != NULL)
|
||||||
|
#define GST_RPAD_IS_ACTIVE(pad) (!GST_FLAG_IS_SET(pad, GST_PAD_DISABLED))
|
||||||
|
#define GST_RPAD_IS_BLOCKED(pad) (GST_FLAG_IS_SET (pad, GST_PAD_BLOCKED))
|
||||||
|
#define GST_RPAD_IS_NEGOTIATING(pad) (GST_FLAG_IS_SET (pad, GST_PAD_NEGOTIATING))
|
||||||
|
#define GST_RPAD_IS_DISPATCHING(pad) (GST_FLAG_IS_SET (pad, GST_PAD_DISPATCHING))
|
||||||
|
#define GST_RPAD_IS_USABLE(pad) (GST_RPAD_IS_LINKED (pad) && \
|
||||||
|
GST_RPAD_IS_ACTIVE(pad) && GST_RPAD_IS_ACTIVE(GST_RPAD_PEER (pad)))
|
||||||
|
#define GST_RPAD_CAN_PULL(pad) (GST_IS_REAL_PAD(pad) && GST_REAL_PAD(pad)->gethandler != NULL)
|
||||||
|
#define GST_RPAD_IS_SRC(pad) (GST_RPAD_DIRECTION(pad) == GST_PAD_SRC)
|
||||||
|
#define GST_RPAD_IS_SINK(pad) (GST_RPAD_DIRECTION(pad) == GST_PAD_SINK)
|
||||||
|
|
||||||
|
#define GST_STREAM_GET_LOCK(pad) (GST_PAD_REALIZE(pad)->stream_lock)
|
||||||
|
#define GST_STREAM_LOCK(pad) (g_mutex_lock(GST_STREAM_GET_LOCK(pad)))
|
||||||
|
#define GST_STREAM_TRYLOCK(pad) (g_mutex_trylock(GST_STREAM_GET_LOCK(pad)))
|
||||||
|
#define GST_STREAM_UNLOCK(pad) (g_mutex_unlock(GST_STREAM_GET_LOCK(pad)))
|
||||||
|
#define GST_STREAM_GET_COND(pad) (GST_PAD_REALIZE(pad)->stream_cond)
|
||||||
|
|
||||||
|
#define GST_PAD_BLOCK_GET_COND(pad) (GST_PAD_REALIZE(pad)->block_cond)
|
||||||
|
#define GST_PAD_BLOCK_WAIT(pad) (g_cond_wait(GST_PAD_BLOCK_GET_COND (pad), GST_GET_LOCK (pad)))
|
||||||
|
#define GST_PAD_BLOCK_SIGNAL(pad) (g_cond_signal(GST_PAD_BLOCK_GET_COND (pad)))
|
||||||
|
|
||||||
/* GstGhostPad */
|
/* GstGhostPad */
|
||||||
#define GST_GPAD_REALPAD(pad) (((GstGhostPad *)(pad))->realpad)
|
#define GST_GPAD_REALPAD(pad) (((GstGhostPad *)(pad))->realpad)
|
||||||
|
@ -274,19 +317,20 @@ struct _GstGhostPadClass {
|
||||||
/* Generic */
|
/* Generic */
|
||||||
#define GST_PAD_REALIZE(pad) (GST_IS_REAL_PAD(pad) ? ((GstRealPad *)(pad)) : GST_GPAD_REALPAD(pad))
|
#define GST_PAD_REALIZE(pad) (GST_IS_REAL_PAD(pad) ? ((GstRealPad *)(pad)) : GST_GPAD_REALPAD(pad))
|
||||||
#define GST_PAD_DIRECTION(pad) GST_RPAD_DIRECTION(GST_PAD_REALIZE(pad))
|
#define GST_PAD_DIRECTION(pad) GST_RPAD_DIRECTION(GST_PAD_REALIZE(pad))
|
||||||
#define GST_PAD_CAPS(pad) (gst_pad_get_negotiated_caps(GST_PAD (pad)))
|
#define GST_PAD_CAPS(pad) GST_RPAD_CAPS(GST_PAD_REALIZE (pad))
|
||||||
#define GST_PAD_PEER(pad) GST_PAD(GST_RPAD_PEER(GST_PAD_REALIZE(pad)))
|
#define GST_PAD_APPFILTER(pad) GST_RPAD_APPFILTER(GST_PAD_REALIZE (pad))
|
||||||
|
#define GST_PAD_PEER(pad) GST_PAD_CAST(GST_RPAD_PEER(GST_PAD_REALIZE(pad)))
|
||||||
|
|
||||||
/* Some check functions (unused?) */
|
/* Some check functions (unused?) */
|
||||||
#define GST_PAD_IS_LINKED(pad) (GST_PAD_PEER(pad) != NULL)
|
#define GST_PAD_IS_LINKED(pad) (GST_RPAD_IS_LINKED(GST_PAD_REALIZE(pad)))
|
||||||
#define GST_PAD_IS_ACTIVE(pad) (!GST_FLAG_IS_SET(GST_PAD_REALIZE(pad), GST_PAD_DISABLED))
|
#define GST_PAD_IS_ACTIVE(pad) (GST_RPAD_IS_ACTIVE(GST_PAD_REALIZE(pad)))
|
||||||
#define GST_PAD_IS_NEGOTIATING(pad) (GST_FLAG_IS_SET (pad, GST_PAD_NEGOTIATING))
|
#define GST_PAD_IS_BLOCKED(pad) (GST_RPAD_IS_BLOCKED(GST_PAD_REALIZE(pad)))
|
||||||
#define GST_PAD_IS_DISPATCHING(pad) (GST_FLAG_IS_SET (pad, GST_PAD_DISPATCHING))
|
#define GST_PAD_IS_NEGOTIATING(pad) (GST_RPAD_IS_NEGOTIATING(GST_PAD_REALIZE(pad)))
|
||||||
#define GST_PAD_IS_USABLE(pad) (GST_PAD_IS_LINKED (pad) && \
|
#define GST_PAD_IS_DISPATCHING(pad) (GST_RPAD_IS_DISPATCHING(GST_PAD_REALIZE(pad)))
|
||||||
GST_PAD_IS_ACTIVE(pad) && GST_PAD_IS_ACTIVE(GST_PAD_PEER (pad)))
|
#define GST_PAD_IS_USABLE(pad) (GST_RPAD_IS_USABLE(GST_PAD_REALIZE(pad)))
|
||||||
#define GST_PAD_CAN_PULL(pad) (GST_IS_REAL_PAD(pad) && GST_REAL_PAD(pad)->gethandler != NULL)
|
#define GST_PAD_CAN_PULL(pad) (GST_RPAD_CAN_PULL(GST_PAD_REALIZE(pad)))
|
||||||
#define GST_PAD_IS_SRC(pad) (GST_PAD_DIRECTION(pad) == GST_PAD_SRC)
|
#define GST_PAD_IS_SRC(pad) (GST_RPAD_IS_SRC(GST_PAD_REALIZE(pad)))
|
||||||
#define GST_PAD_IS_SINK(pad) (GST_PAD_DIRECTION(pad) == GST_PAD_SINK)
|
#define GST_PAD_IS_SINK(pad) (GST_RPAD_IS_SINK(GST_PAD_REALIZE(pad)))
|
||||||
|
|
||||||
/***** PadTemplate *****/
|
/***** PadTemplate *****/
|
||||||
#define GST_TYPE_PAD_TEMPLATE (gst_pad_template_get_type ())
|
#define GST_TYPE_PAD_TEMPLATE (gst_pad_template_get_type ())
|
||||||
|
@ -360,35 +404,36 @@ GstPad* gst_pad_new_from_template (GstPadTemplate *templ, const gchar *name);
|
||||||
GstPad* gst_pad_custom_new (GType type, const gchar *name, GstPadDirection direction);
|
GstPad* gst_pad_custom_new (GType type, const gchar *name, GstPadDirection direction);
|
||||||
GstPad* gst_pad_custom_new_from_template (GType type, GstPadTemplate *templ, const gchar *name);
|
GstPad* gst_pad_custom_new_from_template (GType type, GstPadTemplate *templ, const gchar *name);
|
||||||
|
|
||||||
void gst_pad_set_name (GstPad *pad, const gchar *name);
|
#define gst_pad_get_name(pad) gst_object_get_name(GST_OBJECT(pad))
|
||||||
G_CONST_RETURN gchar* gst_pad_get_name (GstPad *pad);
|
#define gst_pad_set_name(pad,name) gst_object_set_name(GST_OBJECT(pad),name)
|
||||||
|
#define gst_pad_get_parent(pad) GST_ELEMENT(gst_object_get_parent(GST_OBJECT(pad)))
|
||||||
|
#define gst_pad_set_parent(pad,parent) gst_object_set_parent(GST_OBJECT(pad),parent)
|
||||||
|
GstElement* gst_pad_get_real_parent (GstPad *pad);
|
||||||
|
|
||||||
|
|
||||||
GstPadDirection gst_pad_get_direction (GstPad *pad);
|
GstPadDirection gst_pad_get_direction (GstPad *pad);
|
||||||
|
|
||||||
void gst_pad_set_active (GstPad *pad, gboolean active);
|
gboolean gst_pad_set_active (GstPad *pad, gboolean active);
|
||||||
gboolean gst_pad_is_active (GstPad *pad);
|
gboolean gst_pad_is_active (GstPad *pad);
|
||||||
|
gboolean gst_pad_set_blocked (GstPad *pad, gboolean blocked);
|
||||||
|
gboolean gst_pad_set_blocked_async (GstPad *pad, gboolean blocked,
|
||||||
|
GstPadBlockCallback callback, gpointer user_data);
|
||||||
|
gboolean gst_pad_is_blocked (GstPad *pad);
|
||||||
|
|
||||||
void gst_pad_set_element_private (GstPad *pad, gpointer priv);
|
void gst_pad_set_element_private (GstPad *pad, gpointer priv);
|
||||||
gpointer gst_pad_get_element_private (GstPad *pad);
|
gpointer gst_pad_get_element_private (GstPad *pad);
|
||||||
|
|
||||||
void gst_pad_set_parent (GstPad *pad, GstElement *parent);
|
|
||||||
GstElement* gst_pad_get_parent (GstPad *pad);
|
|
||||||
GstElement* gst_pad_get_real_parent (GstPad *pad);
|
|
||||||
|
|
||||||
GstScheduler* gst_pad_get_scheduler (GstPad *pad);
|
|
||||||
|
|
||||||
void gst_pad_add_ghost_pad (GstPad *pad, GstPad *ghostpad);
|
|
||||||
void gst_pad_remove_ghost_pad (GstPad *pad, GstPad *ghostpad);
|
|
||||||
GList* gst_pad_get_ghost_pad_list (GstPad *pad);
|
|
||||||
|
|
||||||
GstPadTemplate* gst_pad_get_pad_template (GstPad *pad);
|
GstPadTemplate* gst_pad_get_pad_template (GstPad *pad);
|
||||||
|
|
||||||
void gst_pad_set_bufferalloc_function (GstPad *pad, GstPadBufferAllocFunction bufalloc);
|
void gst_pad_set_bufferalloc_function (GstPad *pad, GstPadBufferAllocFunction bufalloc);
|
||||||
GstBuffer* gst_pad_alloc_buffer (GstPad *pad, guint64 offset, gint size);
|
GstBuffer* gst_pad_alloc_buffer (GstPad *pad, guint64 offset, gint size);
|
||||||
|
|
||||||
/* data passing setup functions */
|
/* data passing setup functions */
|
||||||
|
void gst_pad_set_activate_function (GstPad *pad, GstPadActivateFunction activate);
|
||||||
void gst_pad_set_chain_function (GstPad *pad, GstPadChainFunction chain);
|
void gst_pad_set_chain_function (GstPad *pad, GstPadChainFunction chain);
|
||||||
void gst_pad_set_get_function (GstPad *pad, GstPadGetFunction get);
|
void gst_pad_set_get_function (GstPad *pad, GstPadGetFunction get);
|
||||||
|
void gst_pad_set_get_range_function (GstPad *pad, GstPadGetRangeFunction get);
|
||||||
|
|
||||||
void gst_pad_set_event_function (GstPad *pad, GstPadEventFunction event);
|
void gst_pad_set_event_function (GstPad *pad, GstPadEventFunction event);
|
||||||
void gst_pad_set_event_mask_function (GstPad *pad, GstPadEventMaskFunction mask_func);
|
void gst_pad_set_event_mask_function (GstPad *pad, GstPadEventMaskFunction mask_func);
|
||||||
G_CONST_RETURN GstEventMask*
|
G_CONST_RETURN GstEventMask*
|
||||||
|
@ -398,62 +443,35 @@ G_CONST_RETURN GstEventMask*
|
||||||
|
|
||||||
/* pad links */
|
/* pad links */
|
||||||
void gst_pad_set_link_function (GstPad *pad, GstPadLinkFunction link);
|
void gst_pad_set_link_function (GstPad *pad, GstPadLinkFunction link);
|
||||||
gboolean gst_pad_can_link (GstPad *srcpad, GstPad *sinkpad);
|
|
||||||
gboolean gst_pad_can_link_filtered (GstPad *srcpad, GstPad *sinkpad, const GstCaps *filtercaps);
|
|
||||||
void gst_pad_set_unlink_function (GstPad *pad, GstPadUnlinkFunction unlink);
|
void gst_pad_set_unlink_function (GstPad *pad, GstPadUnlinkFunction unlink);
|
||||||
|
|
||||||
gboolean gst_pad_link (GstPad *srcpad, GstPad *sinkpad);
|
GstPadLinkReturn gst_pad_link (GstPad *srcpad, GstPad *sinkpad);
|
||||||
gboolean gst_pad_link_filtered (GstPad *srcpad, GstPad *sinkpad, const GstCaps *filtercaps);
|
GstPadLinkReturn gst_pad_link_filtered (GstPad *srcpad, GstPad *sinkpad,
|
||||||
|
const GstCaps *filtercaps);
|
||||||
|
GstPadLinkReturn gst_pad_relink_filtered (GstPad *srcpad, GstPad *sinkpad,
|
||||||
|
const GstCaps *filtercaps);
|
||||||
void gst_pad_unlink (GstPad *srcpad, GstPad *sinkpad);
|
void gst_pad_unlink (GstPad *srcpad, GstPad *sinkpad);
|
||||||
gboolean gst_pad_is_linked (GstPad *pad);
|
gboolean gst_pad_is_linked (GstPad *pad);
|
||||||
|
|
||||||
GstPad* gst_pad_get_peer (GstPad *pad);
|
GstPad* gst_pad_get_peer (GstPad *pad);
|
||||||
|
|
||||||
/* capsnego functions */
|
/* capsnego functions */
|
||||||
G_CONST_RETURN GstCaps* gst_pad_get_negotiated_caps (GstPad *pad);
|
|
||||||
gboolean gst_pad_is_negotiated (GstPad *pad);
|
|
||||||
GstCaps* gst_pad_get_caps (GstPad *pad);
|
|
||||||
G_CONST_RETURN GstCaps* gst_pad_get_pad_template_caps (GstPad *pad);
|
|
||||||
GstPadLinkReturn gst_pad_try_set_caps (GstPad *pad, const GstCaps *caps);
|
|
||||||
GstPadLinkReturn gst_pad_try_set_caps_nonfixed (GstPad *pad, const GstCaps *caps);
|
|
||||||
gboolean gst_pad_check_compatibility (GstPad *srcpad, GstPad *sinkpad);
|
|
||||||
|
|
||||||
void gst_pad_set_getcaps_function (GstPad *pad, GstPadGetCapsFunction getcaps);
|
void gst_pad_set_getcaps_function (GstPad *pad, GstPadGetCapsFunction getcaps);
|
||||||
void gst_pad_set_fixate_function (GstPad *pad, GstPadFixateFunction fixate);
|
|
||||||
GstCaps * gst_pad_proxy_getcaps (GstPad *pad);
|
|
||||||
GstPadLinkReturn gst_pad_proxy_pad_link (GstPad *pad, const GstCaps *caps);
|
|
||||||
GstCaps * gst_pad_proxy_fixate (GstPad *pad, const GstCaps *caps);
|
|
||||||
#ifndef GST_DISABLE_DEPRECATED
|
|
||||||
GstPadLinkReturn gst_pad_proxy_link (GstPad *pad, const GstCaps *caps);
|
|
||||||
#endif
|
|
||||||
gboolean gst_pad_set_explicit_caps (GstPad *pad, const GstCaps *caps);
|
|
||||||
void gst_pad_use_explicit_caps (GstPad *pad);
|
|
||||||
gboolean gst_pad_relink_filtered (GstPad *srcpad, GstPad *sinkpad, const GstCaps *filtercaps);
|
|
||||||
#ifndef GST_DISABLE_DEPRECATED
|
|
||||||
gboolean gst_pad_perform_negotiate (GstPad *srcpad, GstPad *sinkpad);
|
|
||||||
#endif
|
|
||||||
GstPadLinkReturn gst_pad_renegotiate (GstPad *pad);
|
|
||||||
void gst_pad_unnegotiate (GstPad *pad);
|
|
||||||
gboolean gst_pad_try_relink_filtered (GstPad *srcpad, GstPad *sinkpad, const GstCaps *filtercaps);
|
|
||||||
GstCaps* gst_pad_get_allowed_caps (GstPad *pad);
|
|
||||||
void gst_pad_caps_change_notify (GstPad *pad);
|
|
||||||
|
|
||||||
gboolean gst_pad_recover_caps_error (GstPad *pad, const GstCaps *allowed);
|
G_CONST_RETURN GstCaps* gst_pad_get_pad_template_caps (GstPad *pad);
|
||||||
|
|
||||||
|
GstCaps * gst_pad_get_allowed_caps (GstPad * pad);
|
||||||
|
GstCaps * gst_pad_get_caps (GstPad * pad);
|
||||||
|
gboolean gst_pad_set_caps (GstPad * pad, GstCaps *caps);
|
||||||
|
|
||||||
/* data passing functions */
|
/* data passing functions */
|
||||||
void gst_pad_push (GstPad *pad, GstData *data);
|
GstFlowReturn gst_pad_push (GstPad *pad, GstBuffer *buffer);
|
||||||
GstData* gst_pad_pull (GstPad *pad);
|
GstFlowReturn gst_pad_pull (GstPad *pad, GstBuffer **buffer);
|
||||||
|
GstFlowReturn gst_pad_pull_range (GstPad *pad, guint64 offset, guint size,
|
||||||
|
GstBuffer **buffer);
|
||||||
|
gboolean gst_pad_push_event (GstPad *pad, GstEvent *event);
|
||||||
gboolean gst_pad_send_event (GstPad *pad, GstEvent *event);
|
gboolean gst_pad_send_event (GstPad *pad, GstEvent *event);
|
||||||
gboolean gst_pad_event_default (GstPad *pad, GstEvent *event);
|
gboolean gst_pad_event_default (GstPad *pad, GstEvent *event);
|
||||||
#ifndef GST_DISABLE_DEPRECATED
|
|
||||||
GstPad* gst_pad_selectv (GList *padlist);
|
|
||||||
GstPad* gst_pad_select (GstPad *pad, ...);
|
|
||||||
GstPad* gst_pad_select_valist (GstPad *pad, va_list varargs);
|
|
||||||
#endif
|
|
||||||
/* FIXME 0.9: rename to _select? Otherwise rename SchedulerClass pointer */
|
|
||||||
GstData * gst_pad_collectv (GstPad **selected, const GList *padlist);
|
|
||||||
GstData * gst_pad_collect (GstPad **selected, GstPad *pad, ...);
|
|
||||||
GstData * gst_pad_collect_valist (GstPad **selected, GstPad *pad, va_list varargs);
|
|
||||||
|
|
||||||
/* convert/query/format functions */
|
/* convert/query/format functions */
|
||||||
void gst_pad_set_formats_function (GstPad *pad,
|
void gst_pad_set_formats_function (GstPad *pad,
|
||||||
|
@ -490,6 +508,7 @@ GList* gst_pad_get_internal_links_default (GstPad *pad);
|
||||||
gboolean gst_pad_dispatcher (GstPad *pad, GstPadDispatcherFunction dispatch,
|
gboolean gst_pad_dispatcher (GstPad *pad, GstPadDispatcherFunction dispatch,
|
||||||
gpointer data);
|
gpointer data);
|
||||||
|
|
||||||
|
/* probes */
|
||||||
#define gst_pad_add_probe(pad, probe) \
|
#define gst_pad_add_probe(pad, probe) \
|
||||||
(gst_probe_dispatcher_add_probe (&(GST_REAL_PAD (pad)->probedisp), probe))
|
(gst_probe_dispatcher_add_probe (&(GST_REAL_PAD (pad)->probedisp), probe))
|
||||||
#define gst_pad_remove_probe(pad, probe) \
|
#define gst_pad_remove_probe(pad, probe) \
|
||||||
|
@ -513,19 +532,12 @@ GstPadTemplate* gst_pad_template_new (const gchar *name_template,
|
||||||
|
|
||||||
GstPadTemplate * gst_static_pad_template_get (GstStaticPadTemplate *pad_template);
|
GstPadTemplate * gst_static_pad_template_get (GstStaticPadTemplate *pad_template);
|
||||||
const GstCaps* gst_pad_template_get_caps (GstPadTemplate *templ);
|
const GstCaps* gst_pad_template_get_caps (GstPadTemplate *templ);
|
||||||
#ifndef GST_DISABLE_DEPRECATED
|
|
||||||
const GstCaps* gst_pad_template_get_caps_by_name (GstPadTemplate *templ, const gchar *name);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef GST_DISABLE_LOADSAVE
|
#ifndef GST_DISABLE_LOADSAVE
|
||||||
xmlNodePtr gst_ghost_pad_save_thyself (GstPad *pad,
|
xmlNodePtr gst_ghost_pad_save_thyself (GstPad *pad,
|
||||||
xmlNodePtr parent);
|
xmlNodePtr parent);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* for schedulers only */
|
|
||||||
void gst_pad_call_chain_function (GstPad *pad, GstData *data);
|
|
||||||
GstData * gst_pad_call_get_function (GstPad *pad);
|
|
||||||
|
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* GStreamer
|
/* GStreamer
|
||||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||||
* 2000 Wim Taymans <wtay@chello.be>
|
* 2004 Wim Taymans <wim@fluendo.com>
|
||||||
*
|
*
|
||||||
* gstpipeline.c: Overall pipeline management element
|
* gstpipeline.c: Overall pipeline management element
|
||||||
*
|
*
|
||||||
|
@ -25,12 +25,13 @@
|
||||||
#include "gstpipeline.h"
|
#include "gstpipeline.h"
|
||||||
#include "gstinfo.h"
|
#include "gstinfo.h"
|
||||||
#include "gstscheduler.h"
|
#include "gstscheduler.h"
|
||||||
|
#include "gstsystemclock.h"
|
||||||
|
|
||||||
static GstElementDetails gst_pipeline_details =
|
static GstElementDetails gst_pipeline_details =
|
||||||
GST_ELEMENT_DETAILS ("Pipeline object",
|
GST_ELEMENT_DETAILS ("Pipeline object",
|
||||||
"Generic/Bin",
|
"Generic/Bin",
|
||||||
"Complete pipeline object",
|
"Complete pipeline object",
|
||||||
"Erik Walthinsen <omega@cse.ogi.edu>");
|
"Erik Walthinsen <omega@cse.ogi.edu>" "Wim Taymans <wim@fluendo.com>");
|
||||||
|
|
||||||
/* Pipeline signals and args */
|
/* Pipeline signals and args */
|
||||||
enum
|
enum
|
||||||
|
@ -52,6 +53,10 @@ static void gst_pipeline_init (GTypeInstance * instance, gpointer g_class);
|
||||||
|
|
||||||
static void gst_pipeline_dispose (GObject * object);
|
static void gst_pipeline_dispose (GObject * object);
|
||||||
|
|
||||||
|
static GstBusSyncReply pipeline_bus_handler (GstBus * bus, GstMessage * message,
|
||||||
|
GstPipeline * pipeline);
|
||||||
|
|
||||||
|
static GstClock *gst_pipeline_get_clock_func (GstElement * element);
|
||||||
static GstElementStateReturn gst_pipeline_change_state (GstElement * element);
|
static GstElementStateReturn gst_pipeline_change_state (GstElement * element);
|
||||||
|
|
||||||
static GstBinClass *parent_class = NULL;
|
static GstBinClass *parent_class = NULL;
|
||||||
|
@ -104,43 +109,139 @@ gst_pipeline_class_init (gpointer g_class, gpointer class_data)
|
||||||
|
|
||||||
gstelement_class->change_state =
|
gstelement_class->change_state =
|
||||||
GST_DEBUG_FUNCPTR (gst_pipeline_change_state);
|
GST_DEBUG_FUNCPTR (gst_pipeline_change_state);
|
||||||
|
gstelement_class->get_clock = GST_DEBUG_FUNCPTR (gst_pipeline_get_clock_func);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_pipeline_init (GTypeInstance * instance, gpointer g_class)
|
gst_pipeline_init (GTypeInstance * instance, gpointer g_class)
|
||||||
{
|
{
|
||||||
GstScheduler *scheduler;
|
|
||||||
GstPipeline *pipeline = GST_PIPELINE (instance);
|
GstPipeline *pipeline = GST_PIPELINE (instance);
|
||||||
|
|
||||||
/* pipelines are managing bins */
|
|
||||||
GST_FLAG_SET (pipeline, GST_BIN_FLAG_MANAGER);
|
|
||||||
|
|
||||||
/* get an instance of the default scheduler */
|
/* get an instance of the default scheduler */
|
||||||
scheduler = gst_scheduler_factory_make (NULL, GST_ELEMENT (pipeline));
|
pipeline->scheduler =
|
||||||
|
gst_scheduler_factory_make (NULL, GST_ELEMENT (pipeline));
|
||||||
|
|
||||||
/* FIXME need better error handling */
|
/* FIXME need better error handling */
|
||||||
if (scheduler == NULL) {
|
if (pipeline->scheduler == NULL) {
|
||||||
const gchar *name = gst_scheduler_factory_get_default_name ();
|
const gchar *name = gst_scheduler_factory_get_default_name ();
|
||||||
|
|
||||||
g_error ("Critical error: could not get scheduler \"%s\"\n"
|
g_error ("Critical error: could not get scheduler \"%s\"\n"
|
||||||
"Are you sure you have a registry ?\n"
|
"Are you sure you have a registry ?\n"
|
||||||
"Run gst-register as root if you haven't done so yet.", name);
|
"Run gst-register as root if you haven't done so yet.", name);
|
||||||
}
|
}
|
||||||
|
pipeline->bus = g_object_new (gst_bus_get_type (), NULL);
|
||||||
|
gst_bus_set_sync_handler (pipeline->bus,
|
||||||
|
(GstBusSyncHandler) pipeline_bus_handler, pipeline);
|
||||||
|
pipeline->eosed = NULL;
|
||||||
|
GST_ELEMENT_MANAGER (pipeline) = pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_pipeline_dispose (GObject * object)
|
gst_pipeline_dispose (GObject * object)
|
||||||
{
|
{
|
||||||
GstPipeline *pipeline = GST_PIPELINE (object);
|
GstPipeline *pipeline = GST_PIPELINE (object);
|
||||||
GstScheduler *sched;
|
|
||||||
|
|
||||||
g_assert (GST_IS_SCHEDULER (GST_ELEMENT_SCHED (pipeline)));
|
g_assert (GST_IS_SCHEDULER (pipeline->scheduler));
|
||||||
sched = GST_ELEMENT_SCHED (pipeline);
|
|
||||||
|
|
||||||
gst_scheduler_reset (sched);
|
gst_scheduler_reset (pipeline->scheduler);
|
||||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
is_eos (GstPipeline * pipeline)
|
||||||
|
{
|
||||||
|
GstIterator *sinks;
|
||||||
|
gboolean result = TRUE;
|
||||||
|
gboolean done = FALSE;
|
||||||
|
|
||||||
|
sinks = gst_bin_iterate_sinks (GST_BIN (pipeline));
|
||||||
|
while (!done) {
|
||||||
|
gpointer data;
|
||||||
|
|
||||||
|
switch (gst_iterator_next (sinks, &data)) {
|
||||||
|
case GST_ITERATOR_OK:
|
||||||
|
{
|
||||||
|
GstElement *element = GST_ELEMENT (data);
|
||||||
|
GList *eosed;
|
||||||
|
GstElementState state, pending;
|
||||||
|
gboolean complete;
|
||||||
|
|
||||||
|
complete = gst_element_get_state (element, &state, &pending, NULL);
|
||||||
|
|
||||||
|
if (!complete) {
|
||||||
|
GST_DEBUG ("element %s still performing state change",
|
||||||
|
gst_element_get_name (element));
|
||||||
|
result = FALSE;
|
||||||
|
done = TRUE;
|
||||||
|
break;
|
||||||
|
} else if (state != GST_STATE_PLAYING) {
|
||||||
|
GST_DEBUG ("element %s not playing %d %d",
|
||||||
|
gst_element_get_name (element), GST_STATE (element),
|
||||||
|
GST_STATE_PENDING (element));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
eosed = g_list_find (pipeline->eosed, element);
|
||||||
|
if (!eosed) {
|
||||||
|
result = FALSE;
|
||||||
|
done = TRUE;
|
||||||
|
}
|
||||||
|
gst_object_unref (GST_OBJECT (element));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GST_ITERATOR_RESYNC:
|
||||||
|
result = TRUE;
|
||||||
|
gst_iterator_resync (sinks);
|
||||||
|
break;
|
||||||
|
case GST_ITERATOR_DONE:
|
||||||
|
done = TRUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstBusSyncReply
|
||||||
|
pipeline_bus_handler (GstBus * bus, GstMessage * message,
|
||||||
|
GstPipeline * pipeline)
|
||||||
|
{
|
||||||
|
GstBusSyncReply result = GST_BUS_PASS;
|
||||||
|
gboolean posteos = FALSE;
|
||||||
|
gboolean locked;
|
||||||
|
|
||||||
|
/* we don't want messages from the streaming thread while we're doing the
|
||||||
|
* state change. We do want them from the state change functions. */
|
||||||
|
locked = GST_STATE_TRYLOCK (pipeline);
|
||||||
|
|
||||||
|
switch (GST_MESSAGE_TYPE (message)) {
|
||||||
|
case GST_MESSAGE_EOS:
|
||||||
|
if (GST_MESSAGE_SRC (message) != GST_OBJECT (pipeline)) {
|
||||||
|
pipeline->eosed =
|
||||||
|
g_list_prepend (pipeline->eosed, GST_MESSAGE_SRC (message));
|
||||||
|
if (is_eos (pipeline)) {
|
||||||
|
posteos = TRUE;
|
||||||
|
}
|
||||||
|
/* we drop all EOS messages */
|
||||||
|
result = GST_BUS_DROP;
|
||||||
|
}
|
||||||
|
case GST_MESSAGE_ERROR:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (locked)
|
||||||
|
GST_STATE_UNLOCK (pipeline);
|
||||||
|
|
||||||
|
if (posteos) {
|
||||||
|
gst_bus_post (bus, gst_message_new_eos (GST_OBJECT (pipeline)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_pipeline_new:
|
* gst_pipeline_new:
|
||||||
* @name: name of new pipeline
|
* @name: name of new pipeline
|
||||||
|
@ -158,20 +259,188 @@ gst_pipeline_new (const gchar * name)
|
||||||
static GstElementStateReturn
|
static GstElementStateReturn
|
||||||
gst_pipeline_change_state (GstElement * element)
|
gst_pipeline_change_state (GstElement * element)
|
||||||
{
|
{
|
||||||
|
GstElementStateReturn result = GST_STATE_SUCCESS;
|
||||||
|
GstPipeline *pipeline = GST_PIPELINE (element);
|
||||||
|
|
||||||
switch (GST_STATE_TRANSITION (element)) {
|
switch (GST_STATE_TRANSITION (element)) {
|
||||||
case GST_STATE_NULL_TO_READY:
|
case GST_STATE_NULL_TO_READY:
|
||||||
gst_scheduler_setup (GST_ELEMENT_SCHED (element));
|
gst_scheduler_setup (pipeline->scheduler);
|
||||||
break;
|
break;
|
||||||
case GST_STATE_READY_TO_PAUSED:
|
case GST_STATE_READY_TO_PAUSED:
|
||||||
|
gst_element_set_clock (element, gst_element_get_clock (element));
|
||||||
|
pipeline->eosed = NULL;
|
||||||
|
break;
|
||||||
case GST_STATE_PAUSED_TO_PLAYING:
|
case GST_STATE_PAUSED_TO_PLAYING:
|
||||||
|
if (element->clock) {
|
||||||
|
element->base_time = gst_clock_get_time (element->clock);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case GST_STATE_PLAYING_TO_PAUSED:
|
case GST_STATE_PLAYING_TO_PAUSED:
|
||||||
case GST_STATE_PAUSED_TO_READY:
|
case GST_STATE_PAUSED_TO_READY:
|
||||||
case GST_STATE_READY_TO_NULL:
|
case GST_STATE_READY_TO_NULL:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
result = GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
|
||||||
|
|
||||||
return GST_STATE_SUCCESS;
|
/* we wait for async state changes ourselves */
|
||||||
|
if (result == GST_STATE_ASYNC) {
|
||||||
|
GST_STATE_UNLOCK (pipeline);
|
||||||
|
gst_element_get_state (element, NULL, NULL, NULL);
|
||||||
|
GST_STATE_LOCK (pipeline);
|
||||||
|
result = GST_STATE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_pipeline_get_scheduler:
|
||||||
|
* @pipeline: the pipeline
|
||||||
|
*
|
||||||
|
* Gets the #GstScheduler of this pipeline.
|
||||||
|
*
|
||||||
|
* Returns: a GstScheduler.
|
||||||
|
*/
|
||||||
|
GstScheduler *
|
||||||
|
gst_pipeline_get_scheduler (GstPipeline * pipeline)
|
||||||
|
{
|
||||||
|
return pipeline->scheduler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_pipeline_get_bus:
|
||||||
|
* @pipeline: the pipeline
|
||||||
|
*
|
||||||
|
* Gets the #GstBus of this pipeline.
|
||||||
|
*
|
||||||
|
* Returns: a GstBus
|
||||||
|
*/
|
||||||
|
GstBus *
|
||||||
|
gst_pipeline_get_bus (GstPipeline * pipeline)
|
||||||
|
{
|
||||||
|
return pipeline->bus;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstClock *
|
||||||
|
gst_pipeline_get_clock_func (GstElement * element)
|
||||||
|
{
|
||||||
|
GstClock *clock = NULL;
|
||||||
|
GstPipeline *pipeline = GST_PIPELINE (element);
|
||||||
|
|
||||||
|
/* if we have a fixed clock, use that one */
|
||||||
|
if (GST_FLAG_IS_SET (pipeline, GST_PIPELINE_FLAG_FIXED_CLOCK)) {
|
||||||
|
clock = pipeline->fixed_clock;
|
||||||
|
|
||||||
|
GST_CAT_DEBUG (GST_CAT_CLOCK, "pipeline using fixed clock %p (%s)",
|
||||||
|
clock, clock ? GST_STR_NULL (GST_OBJECT_NAME (clock)) : "-");
|
||||||
|
} else {
|
||||||
|
clock =
|
||||||
|
GST_ELEMENT_CLASS (parent_class)->get_clock (GST_ELEMENT (pipeline));
|
||||||
|
/* no clock, use a system clock */
|
||||||
|
if (!clock) {
|
||||||
|
clock = gst_system_clock_obtain ();
|
||||||
|
/* we unref since this function is not supposed to increase refcount
|
||||||
|
* of clock object returned; this is ok since the systemclock always
|
||||||
|
* has a refcount of at least one in the current code. */
|
||||||
|
gst_object_unref (GST_OBJECT (clock));
|
||||||
|
GST_CAT_DEBUG (GST_CAT_CLOCK, "pipeline obtained system clock: %p (%s)",
|
||||||
|
clock, clock ? GST_STR_NULL (GST_OBJECT_NAME (clock)) : "-");
|
||||||
|
} else {
|
||||||
|
GST_CAT_DEBUG (GST_CAT_CLOCK, "pipeline obtained clock: %p (%s)",
|
||||||
|
clock, clock ? GST_STR_NULL (GST_OBJECT_NAME (clock)) : "-");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return clock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_pipeline_get_clock:
|
||||||
|
* @pipeline: the pipeline
|
||||||
|
*
|
||||||
|
* Gets the current clock used by the pipeline.
|
||||||
|
*
|
||||||
|
* Returns: a GstClock
|
||||||
|
*/
|
||||||
|
GstClock *
|
||||||
|
gst_pipeline_get_clock (GstPipeline * pipeline)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (GST_IS_PIPELINE (pipeline), NULL);
|
||||||
|
|
||||||
|
return gst_pipeline_get_clock_func (GST_ELEMENT (pipeline));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_pipeline_use_clock:
|
||||||
|
* @pipeline: the pipeline
|
||||||
|
* @clock: the clock to use
|
||||||
|
*
|
||||||
|
* Force the pipeline to use the given clock. The pipeline will
|
||||||
|
* always use the given clock even if new clock providers are added
|
||||||
|
* to this pipeline.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_pipeline_use_clock (GstPipeline * pipeline, GstClock * clock)
|
||||||
|
{
|
||||||
|
g_return_if_fail (GST_IS_PIPELINE (pipeline));
|
||||||
|
|
||||||
|
GST_FLAG_SET (pipeline, GST_PIPELINE_FLAG_FIXED_CLOCK);
|
||||||
|
|
||||||
|
gst_object_replace ((GstObject **) & pipeline->fixed_clock,
|
||||||
|
(GstObject *) clock);
|
||||||
|
|
||||||
|
GST_CAT_DEBUG (GST_CAT_CLOCK, "pipeline using fixed clock %p (%s)", clock,
|
||||||
|
(clock ? GST_OBJECT_NAME (clock) : "nil"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_pipeline_set_clock:
|
||||||
|
* @pipeline: the pipeline
|
||||||
|
* @clock: the clock to set
|
||||||
|
*
|
||||||
|
* Set the clock for the pipeline. The clock will be distributed
|
||||||
|
* to all the elements managed by the pipeline.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_pipeline_set_clock (GstPipeline * pipeline, GstClock * clock)
|
||||||
|
{
|
||||||
|
g_return_if_fail (pipeline != NULL);
|
||||||
|
g_return_if_fail (GST_IS_PIPELINE (pipeline));
|
||||||
|
|
||||||
|
GST_ELEMENT_CLASS (parent_class)->set_clock (GST_ELEMENT (pipeline), clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_pipeline_auto_clock:
|
||||||
|
* @pipeline: the pipeline
|
||||||
|
*
|
||||||
|
* Let the pipeline select a clock automatically.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_pipeline_auto_clock (GstPipeline * pipeline)
|
||||||
|
{
|
||||||
|
g_return_if_fail (pipeline != NULL);
|
||||||
|
g_return_if_fail (GST_IS_PIPELINE (pipeline));
|
||||||
|
|
||||||
|
GST_FLAG_UNSET (pipeline, GST_PIPELINE_FLAG_FIXED_CLOCK);
|
||||||
|
|
||||||
|
gst_object_replace ((GstObject **) & pipeline->fixed_clock, NULL);
|
||||||
|
|
||||||
|
GST_CAT_DEBUG (GST_CAT_CLOCK, "pipeline using automatic clock");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_pipeline_post_message:
|
||||||
|
* @pipeline: the pipeline
|
||||||
|
* @message: the message
|
||||||
|
*
|
||||||
|
* Post a message on the message bus of this pipeline.
|
||||||
|
*
|
||||||
|
* Returns: TRUE if the message could be posted.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
gst_pipeline_post_message (GstPipeline * pipeline, GstMessage * message)
|
||||||
|
{
|
||||||
|
return gst_bus_post (pipeline->bus, message);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,9 @@
|
||||||
#ifndef __GST_PIPELINE_H__
|
#ifndef __GST_PIPELINE_H__
|
||||||
#define __GST_PIPELINE_H__
|
#define __GST_PIPELINE_H__
|
||||||
|
|
||||||
|
#include <gst/gsttypes.h>
|
||||||
#include <gst/gstbin.h>
|
#include <gst/gstbin.h>
|
||||||
|
#include <gst/gstbus.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
@ -35,12 +37,23 @@ G_BEGIN_DECLS
|
||||||
#define GST_IS_PIPELINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PIPELINE))
|
#define GST_IS_PIPELINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PIPELINE))
|
||||||
#define GST_PIPELINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_PIPELINE, GstPipelineClass))
|
#define GST_PIPELINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_PIPELINE, GstPipelineClass))
|
||||||
|
|
||||||
typedef struct _GstPipeline GstPipeline;
|
typedef enum {
|
||||||
typedef struct _GstPipelineClass GstPipelineClass;
|
/* this pipeline works with a fixed clock */
|
||||||
|
GST_PIPELINE_FLAG_FIXED_CLOCK = GST_BIN_FLAG_LAST,
|
||||||
|
|
||||||
|
/* padding */
|
||||||
|
GST_PIPELINE_FLAG_LAST = GST_BIN_FLAG_LAST + 4
|
||||||
|
} GstPipelineFlags;
|
||||||
|
|
||||||
struct _GstPipeline {
|
struct _GstPipeline {
|
||||||
GstBin bin;
|
GstBin bin;
|
||||||
|
|
||||||
|
GstBus *bus;
|
||||||
|
GstScheduler *scheduler;
|
||||||
|
GstClock *fixed_clock; /* fixed clock if any */
|
||||||
|
|
||||||
|
GList *eosed; /* list of elements that posted EOS */
|
||||||
|
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
gpointer _gst_reserved[GST_PADDING];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -53,6 +66,14 @@ struct _GstPipelineClass {
|
||||||
GType gst_pipeline_get_type (void);
|
GType gst_pipeline_get_type (void);
|
||||||
GstElement* gst_pipeline_new (const gchar *name);
|
GstElement* gst_pipeline_new (const gchar *name);
|
||||||
|
|
||||||
|
GstScheduler* gst_pipeline_get_scheduler (GstPipeline *pipeline);
|
||||||
|
GstBus* gst_pipeline_get_bus (GstPipeline *pipeline);
|
||||||
|
void gst_pipeline_use_clock (GstPipeline *pipeline, GstClock *clock);
|
||||||
|
void gst_pipeline_set_clock (GstPipeline *pipeline, GstClock *clock);
|
||||||
|
GstClock* gst_pipeline_get_clock (GstPipeline *pipeline);
|
||||||
|
void gst_pipeline_auto_clock (GstPipeline *pipeline);
|
||||||
|
|
||||||
|
gboolean gst_pipeline_post_message (GstPipeline *pipeline, GstMessage *message);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
|
|
@ -578,22 +578,6 @@ gst_plugin_get_filename (GstPlugin * plugin)
|
||||||
return plugin->filename;
|
return plugin->filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_plugin_get_version:
|
|
||||||
* @plugin: plugin to get the version of
|
|
||||||
*
|
|
||||||
* get the version of the plugin
|
|
||||||
*
|
|
||||||
* Returns: the version of the plugin
|
|
||||||
*/
|
|
||||||
G_CONST_RETURN gchar *
|
|
||||||
gst_plugin_get_version (GstPlugin * plugin)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (plugin != NULL, NULL);
|
|
||||||
|
|
||||||
return plugin->desc.version;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_plugin_get_license:
|
* gst_plugin_get_license:
|
||||||
* @plugin: plugin to get the license of
|
* @plugin: plugin to get the license of
|
||||||
|
|
|
@ -63,7 +63,7 @@ struct _GstPluginDesc {
|
||||||
gchar *license; /* effective license of plugin */
|
gchar *license; /* effective license of plugin */
|
||||||
gchar *package; /* package plugin belongs to */
|
gchar *package; /* package plugin belongs to */
|
||||||
gchar *origin; /* URL to provider of plugin */
|
gchar *origin; /* URL to provider of plugin */
|
||||||
|
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
gpointer _gst_reserved[GST_PADDING];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -71,25 +71,25 @@ struct _GstPlugin {
|
||||||
GstPluginDesc desc;
|
GstPluginDesc desc;
|
||||||
|
|
||||||
gchar * filename;
|
gchar * filename;
|
||||||
GList * features; /* list of features provided */
|
GList * features; /* list of features provided */
|
||||||
gint numfeatures;
|
gint numfeatures;
|
||||||
|
|
||||||
gpointer manager; /* managing registry */
|
gpointer manager; /* managing registry */
|
||||||
GModule * module; /* contains the module if plugin is loaded */
|
GModule * module; /* contains the module if the plugin is loaded */
|
||||||
|
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
gpointer _gst_reserved[GST_PADDING];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define GST_PLUGIN_DEFINE(major,minor,name,description,init,version,license,package,origin) \
|
#define GST_PLUGIN_DEFINE(major,minor,name,description,init,version,license,package,origin) \
|
||||||
GST_PLUGIN_EXPORT GstPluginDesc gst_plugin_desc = { \
|
GST_PLUGIN_EXPORT GstPluginDesc gst_plugin_desc = { \
|
||||||
major, \
|
major, \
|
||||||
minor, \
|
minor, \
|
||||||
name, \
|
name, \
|
||||||
description, \
|
description, \
|
||||||
init, \
|
init, \
|
||||||
NULL, \
|
NULL, \
|
||||||
version, \
|
version, \
|
||||||
license, \
|
license, \
|
||||||
package, \
|
package, \
|
||||||
origin, \
|
origin, \
|
||||||
GST_PADDING_INIT \
|
GST_PADDING_INIT \
|
||||||
|
@ -102,18 +102,18 @@ _gst_plugin_static_init__ ##init (void) \
|
||||||
static GstPluginDesc plugin_desc_ = { \
|
static GstPluginDesc plugin_desc_ = { \
|
||||||
major, \
|
major, \
|
||||||
minor, \
|
minor, \
|
||||||
name, \
|
name, \
|
||||||
description, \
|
description, \
|
||||||
init, \
|
init, \
|
||||||
NULL, \
|
NULL, \
|
||||||
version, \
|
version, \
|
||||||
license, \
|
license, \
|
||||||
package, \
|
package, \
|
||||||
origin, \
|
origin, \
|
||||||
GST_PADDING_INIT \
|
GST_PADDING_INIT \
|
||||||
}; \
|
}; \
|
||||||
_gst_plugin_register_static (&plugin_desc_); \
|
_gst_plugin_register_static (&plugin_desc_); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GST_LICENSE_UNKNOWN "unknown"
|
#define GST_LICENSE_UNKNOWN "unknown"
|
||||||
|
|
||||||
|
@ -125,23 +125,22 @@ typedef gboolean (*GstPluginFilter) (GstPlugin *plugin,
|
||||||
#define GST_TYPE_PLUGIN (gst_plugin_get_type())
|
#define GST_TYPE_PLUGIN (gst_plugin_get_type())
|
||||||
GType gst_plugin_get_type (void);
|
GType gst_plugin_get_type (void);
|
||||||
void _gst_plugin_initialize (void);
|
void _gst_plugin_initialize (void);
|
||||||
void _gst_plugin_register_static (GstPluginDesc *desc);
|
void _gst_plugin_register_static (GstPluginDesc *desc);
|
||||||
|
|
||||||
G_CONST_RETURN gchar* gst_plugin_get_name (GstPlugin *plugin);
|
G_CONST_RETURN gchar* gst_plugin_get_name (GstPlugin *plugin);
|
||||||
G_CONST_RETURN gchar* gst_plugin_get_description (GstPlugin *plugin);
|
G_CONST_RETURN gchar* gst_plugin_get_description (GstPlugin *plugin);
|
||||||
G_CONST_RETURN gchar* gst_plugin_get_filename (GstPlugin *plugin);
|
G_CONST_RETURN gchar* gst_plugin_get_filename (GstPlugin *plugin);
|
||||||
G_CONST_RETURN gchar* gst_plugin_get_version (GstPlugin *plugin);
|
|
||||||
G_CONST_RETURN gchar* gst_plugin_get_license (GstPlugin *plugin);
|
G_CONST_RETURN gchar* gst_plugin_get_license (GstPlugin *plugin);
|
||||||
G_CONST_RETURN gchar* gst_plugin_get_package (GstPlugin *plugin);
|
G_CONST_RETURN gchar* gst_plugin_get_package (GstPlugin *plugin);
|
||||||
G_CONST_RETURN gchar* gst_plugin_get_origin (GstPlugin *plugin);
|
G_CONST_RETURN gchar* gst_plugin_get_origin (GstPlugin *plugin);
|
||||||
GModule * gst_plugin_get_module (GstPlugin *plugin);
|
GModule * gst_plugin_get_module (GstPlugin *plugin);
|
||||||
gboolean gst_plugin_is_loaded (GstPlugin *plugin);
|
gboolean gst_plugin_is_loaded (GstPlugin *plugin);
|
||||||
|
|
||||||
GList* gst_plugin_feature_filter (GstPlugin *plugin,
|
GList* gst_plugin_feature_filter (GstPlugin *plugin,
|
||||||
GstPluginFeatureFilter filter,
|
GstPluginFeatureFilter filter,
|
||||||
gboolean first,
|
gboolean first,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
GList* gst_plugin_list_feature_filter (GList *list,
|
GList* gst_plugin_list_feature_filter (GList *list,
|
||||||
GstPluginFeatureFilter filter,
|
GstPluginFeatureFilter filter,
|
||||||
gboolean first,
|
gboolean first,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
@ -150,15 +149,15 @@ gboolean gst_plugin_name_filter (GstPlugin *plugin, const gchar *name);
|
||||||
GList* gst_plugin_get_feature_list (GstPlugin *plugin);
|
GList* gst_plugin_get_feature_list (GstPlugin *plugin);
|
||||||
GstPluginFeature* gst_plugin_find_feature (GstPlugin *plugin, const gchar *name, GType type);
|
GstPluginFeature* gst_plugin_find_feature (GstPlugin *plugin, const gchar *name, GType type);
|
||||||
|
|
||||||
gboolean gst_plugin_check_file (const gchar *filename, GError** error);
|
gboolean gst_plugin_check_file (const gchar *filename, GError** error);
|
||||||
GstPlugin * gst_plugin_load_file (const gchar *filename, GError** error);
|
GstPlugin * gst_plugin_load_file (const gchar *filename, GError** error);
|
||||||
gboolean gst_plugin_unload_plugin (GstPlugin *plugin);
|
gboolean gst_plugin_unload_plugin (GstPlugin *plugin);
|
||||||
|
|
||||||
void gst_plugin_add_feature (GstPlugin *plugin, GstPluginFeature *feature);
|
void gst_plugin_add_feature (GstPlugin *plugin, GstPluginFeature *feature);
|
||||||
|
|
||||||
/* shortcuts to load from the registry pool */
|
/* shortcuts to load from the registry pool */
|
||||||
gboolean gst_plugin_load (const gchar *name);
|
gboolean gst_plugin_load (const gchar *name);
|
||||||
gboolean gst_library_load (const gchar *name);
|
gboolean gst_library_load (const gchar *name);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
|
691
gst/gstqueue.c
691
gst/gstqueue.c
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include "gstqueue.h"
|
#include "gstqueue.h"
|
||||||
#include "gstscheduler.h"
|
#include "gstscheduler.h"
|
||||||
|
#include "gstpipeline.h"
|
||||||
#include "gstevent.h"
|
#include "gstevent.h"
|
||||||
#include "gstinfo.h"
|
#include "gstinfo.h"
|
||||||
#include "gsterror.h"
|
#include "gsterror.h"
|
||||||
|
@ -41,6 +42,24 @@ static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_STATIC_CAPS_ANY);
|
GST_STATIC_CAPS_ANY);
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_STATIC (queue_dataflow);
|
GST_DEBUG_CATEGORY_STATIC (queue_dataflow);
|
||||||
|
#define GST_CAT_DEFAULT (queue_dataflow)
|
||||||
|
|
||||||
|
#define STATUS(queue, msg) \
|
||||||
|
GST_CAT_LOG_OBJECT (queue_dataflow, queue, \
|
||||||
|
"(%s:%s) " msg ": %u of %u-%u buffers, %u of %u-%u " \
|
||||||
|
"bytes, %" G_GUINT64_FORMAT " of %" G_GUINT64_FORMAT \
|
||||||
|
"-%" G_GUINT64_FORMAT " ns, %u elements", \
|
||||||
|
GST_DEBUG_PAD_NAME (pad), \
|
||||||
|
queue->cur_level.buffers, \
|
||||||
|
queue->min_threshold.buffers, \
|
||||||
|
queue->max_size.buffers, \
|
||||||
|
queue->cur_level.bytes, \
|
||||||
|
queue->min_threshold.bytes, \
|
||||||
|
queue->max_size.bytes, \
|
||||||
|
queue->cur_level.time, \
|
||||||
|
queue->min_threshold.time, \
|
||||||
|
queue->max_size.time, \
|
||||||
|
queue->queue->length)
|
||||||
|
|
||||||
static GstElementDetails gst_queue_details = GST_ELEMENT_DETAILS ("Queue",
|
static GstElementDetails gst_queue_details = GST_ELEMENT_DETAILS ("Queue",
|
||||||
"Generic",
|
"Generic",
|
||||||
|
@ -95,13 +114,6 @@ enum
|
||||||
} G_STMT_END
|
} G_STMT_END
|
||||||
|
|
||||||
|
|
||||||
typedef struct _GstQueueEventResponse
|
|
||||||
{
|
|
||||||
GstEvent *event;
|
|
||||||
gboolean ret, handled;
|
|
||||||
}
|
|
||||||
GstQueueEventResponse;
|
|
||||||
|
|
||||||
static void gst_queue_base_init (GstQueueClass * klass);
|
static void gst_queue_base_init (GstQueueClass * klass);
|
||||||
static void gst_queue_class_init (GstQueueClass * klass);
|
static void gst_queue_class_init (GstQueueClass * klass);
|
||||||
static void gst_queue_init (GstQueue * queue);
|
static void gst_queue_init (GstQueue * queue);
|
||||||
|
@ -112,19 +124,24 @@ static void gst_queue_set_property (GObject * object,
|
||||||
static void gst_queue_get_property (GObject * object,
|
static void gst_queue_get_property (GObject * object,
|
||||||
guint prop_id, GValue * value, GParamSpec * pspec);
|
guint prop_id, GValue * value, GParamSpec * pspec);
|
||||||
|
|
||||||
static void gst_queue_chain (GstPad * pad, GstData * data);
|
static GstFlowReturn gst_queue_chain (GstPad * pad, GstBuffer * buffer);
|
||||||
static GstData *gst_queue_get (GstPad * pad);
|
static GstFlowReturn gst_queue_get (GstPad * pad, GstBuffer ** buffer);
|
||||||
|
static GstBuffer *gst_queue_bufferalloc (GstPad * pad, guint64 offset,
|
||||||
|
guint size, GstCaps * caps);
|
||||||
|
|
||||||
|
static gboolean gst_queue_handle_sink_event (GstPad * pad, GstEvent * event);
|
||||||
|
|
||||||
static gboolean gst_queue_handle_src_event (GstPad * pad, GstEvent * event);
|
static gboolean gst_queue_handle_src_event (GstPad * pad, GstEvent * event);
|
||||||
static gboolean gst_queue_handle_src_query (GstPad * pad,
|
static gboolean gst_queue_handle_src_query (GstPad * pad,
|
||||||
GstQueryType type, GstFormat * fmt, gint64 * value);
|
GstQueryType type, GstFormat * fmt, gint64 * value);
|
||||||
|
|
||||||
static GstCaps *gst_queue_getcaps (GstPad * pad);
|
static GstCaps *gst_queue_getcaps (GstPad * pad);
|
||||||
static GstPadLinkReturn gst_queue_link (GstPad * pad, const GstCaps * caps);
|
static GstPadLinkReturn gst_queue_link_sink (GstPad * pad, GstPad * peer);
|
||||||
|
static GstPadLinkReturn gst_queue_link_src (GstPad * pad, GstPad * peer);
|
||||||
static void gst_queue_locked_flush (GstQueue * queue);
|
static void gst_queue_locked_flush (GstQueue * queue);
|
||||||
|
|
||||||
|
static gboolean gst_queue_src_activate (GstPad * pad, gboolean active);
|
||||||
static GstElementStateReturn gst_queue_change_state (GstElement * element);
|
static GstElementStateReturn gst_queue_change_state (GstElement * element);
|
||||||
static gboolean gst_queue_release_locks (GstElement * element);
|
|
||||||
|
|
||||||
|
|
||||||
#define GST_TYPE_QUEUE_LEAKY (queue_leaky_get_type ())
|
#define GST_TYPE_QUEUE_LEAKY (queue_leaky_get_type ())
|
||||||
|
@ -197,6 +214,9 @@ gst_queue_class_init (GstQueueClass * klass)
|
||||||
|
|
||||||
parent_class = g_type_class_peek_parent (klass);
|
parent_class = g_type_class_peek_parent (klass);
|
||||||
|
|
||||||
|
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_queue_set_property);
|
||||||
|
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_queue_get_property);
|
||||||
|
|
||||||
/* signals */
|
/* signals */
|
||||||
gst_queue_signals[SIGNAL_UNDERRUN] =
|
gst_queue_signals[SIGNAL_UNDERRUN] =
|
||||||
g_signal_new ("underrun", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST,
|
g_signal_new ("underrun", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST,
|
||||||
|
@ -267,45 +287,43 @@ gst_queue_class_init (GstQueueClass * klass)
|
||||||
|
|
||||||
/* set several parent class virtual functions */
|
/* set several parent class virtual functions */
|
||||||
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_queue_finalize);
|
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_queue_finalize);
|
||||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_queue_set_property);
|
|
||||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_queue_get_property);
|
|
||||||
|
|
||||||
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_queue_change_state);
|
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_queue_change_state);
|
||||||
gstelement_class->release_locks = GST_DEBUG_FUNCPTR (gst_queue_release_locks);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_queue_init (GstQueue * queue)
|
gst_queue_init (GstQueue * queue)
|
||||||
{
|
{
|
||||||
/* scheduling on this kind of element is, well, interesting */
|
|
||||||
GST_FLAG_SET (queue, GST_ELEMENT_DECOUPLED);
|
|
||||||
GST_FLAG_SET (queue, GST_ELEMENT_EVENT_AWARE);
|
|
||||||
|
|
||||||
queue->sinkpad =
|
queue->sinkpad =
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
|
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
|
||||||
"sink");
|
"sink");
|
||||||
gst_pad_set_chain_function (queue->sinkpad,
|
gst_pad_set_chain_function (queue->sinkpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_queue_chain));
|
GST_DEBUG_FUNCPTR (gst_queue_chain));
|
||||||
gst_element_add_pad (GST_ELEMENT (queue), queue->sinkpad);
|
gst_pad_set_event_function (queue->sinkpad,
|
||||||
|
GST_DEBUG_FUNCPTR (gst_queue_handle_sink_event));
|
||||||
gst_pad_set_link_function (queue->sinkpad,
|
gst_pad_set_link_function (queue->sinkpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_queue_link));
|
GST_DEBUG_FUNCPTR (gst_queue_link_sink));
|
||||||
gst_pad_set_getcaps_function (queue->sinkpad,
|
gst_pad_set_getcaps_function (queue->sinkpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_queue_getcaps));
|
GST_DEBUG_FUNCPTR (gst_queue_getcaps));
|
||||||
gst_pad_set_active (queue->sinkpad, TRUE);
|
gst_pad_set_bufferalloc_function (queue->sinkpad,
|
||||||
|
GST_DEBUG_FUNCPTR (gst_queue_bufferalloc));
|
||||||
|
gst_element_add_pad (GST_ELEMENT (queue), queue->sinkpad);
|
||||||
|
|
||||||
queue->srcpad =
|
queue->srcpad =
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
|
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
|
||||||
"src");
|
"src");
|
||||||
gst_pad_set_get_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_get));
|
gst_pad_set_get_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_get));
|
||||||
gst_element_add_pad (GST_ELEMENT (queue), queue->srcpad);
|
gst_pad_set_activate_function (queue->srcpad,
|
||||||
gst_pad_set_link_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_link));
|
GST_DEBUG_FUNCPTR (gst_queue_src_activate));
|
||||||
|
gst_pad_set_link_function (queue->srcpad,
|
||||||
|
GST_DEBUG_FUNCPTR (gst_queue_link_src));
|
||||||
gst_pad_set_getcaps_function (queue->srcpad,
|
gst_pad_set_getcaps_function (queue->srcpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_queue_getcaps));
|
GST_DEBUG_FUNCPTR (gst_queue_getcaps));
|
||||||
gst_pad_set_event_function (queue->srcpad,
|
gst_pad_set_event_function (queue->srcpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_queue_handle_src_event));
|
GST_DEBUG_FUNCPTR (gst_queue_handle_src_event));
|
||||||
gst_pad_set_query_function (queue->srcpad,
|
gst_pad_set_query_function (queue->srcpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_queue_handle_src_query));
|
GST_DEBUG_FUNCPTR (gst_queue_handle_src_query));
|
||||||
gst_pad_set_active (queue->srcpad, TRUE);
|
gst_element_add_pad (GST_ELEMENT (queue), queue->srcpad);
|
||||||
|
|
||||||
queue->cur_level.buffers = 0; /* no content */
|
queue->cur_level.buffers = 0; /* no content */
|
||||||
queue->cur_level.bytes = 0; /* no content */
|
queue->cur_level.bytes = 0; /* no content */
|
||||||
|
@ -326,9 +344,6 @@ gst_queue_init (GstQueue * queue)
|
||||||
queue->qlock = g_mutex_new ();
|
queue->qlock = g_mutex_new ();
|
||||||
queue->item_add = g_cond_new ();
|
queue->item_add = g_cond_new ();
|
||||||
queue->item_del = g_cond_new ();
|
queue->item_del = g_cond_new ();
|
||||||
queue->event_done = g_cond_new ();
|
|
||||||
queue->events = g_queue_new ();
|
|
||||||
queue->event_lock = g_mutex_new ();
|
|
||||||
queue->queue = g_queue_new ();
|
queue->queue = g_queue_new ();
|
||||||
|
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_THREAD, queue,
|
GST_CAT_DEBUG_OBJECT (GST_CAT_THREAD, queue,
|
||||||
|
@ -349,19 +364,11 @@ gst_queue_finalize (GObject * object)
|
||||||
gst_data_unref (data);
|
gst_data_unref (data);
|
||||||
}
|
}
|
||||||
g_queue_free (queue->queue);
|
g_queue_free (queue->queue);
|
||||||
|
GST_CAT_DEBUG_OBJECT (GST_CAT_THREAD, queue, "free mutex");
|
||||||
g_mutex_free (queue->qlock);
|
g_mutex_free (queue->qlock);
|
||||||
|
GST_CAT_DEBUG_OBJECT (GST_CAT_THREAD, queue, "done free mutex");
|
||||||
g_cond_free (queue->item_add);
|
g_cond_free (queue->item_add);
|
||||||
g_cond_free (queue->item_del);
|
g_cond_free (queue->item_del);
|
||||||
g_cond_free (queue->event_done);
|
|
||||||
g_mutex_lock (queue->event_lock);
|
|
||||||
while (!g_queue_is_empty (queue->events)) {
|
|
||||||
GstQueueEventResponse *er = g_queue_pop_head (queue->events);
|
|
||||||
|
|
||||||
gst_event_unref (er->event);
|
|
||||||
}
|
|
||||||
g_mutex_unlock (queue->event_lock);
|
|
||||||
g_mutex_free (queue->event_lock);
|
|
||||||
g_queue_free (queue->events);
|
|
||||||
|
|
||||||
if (G_OBJECT_CLASS (parent_class)->finalize)
|
if (G_OBJECT_CLASS (parent_class)->finalize)
|
||||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
|
@ -371,42 +378,55 @@ static GstCaps *
|
||||||
gst_queue_getcaps (GstPad * pad)
|
gst_queue_getcaps (GstPad * pad)
|
||||||
{
|
{
|
||||||
GstQueue *queue;
|
GstQueue *queue;
|
||||||
|
GstPad *otherpad, *otherpeer;
|
||||||
|
|
||||||
queue = GST_QUEUE (gst_pad_get_parent (pad));
|
queue = GST_QUEUE (gst_object_get_parent (GST_OBJECT (pad)));
|
||||||
|
|
||||||
if (queue->cur_level.bytes > 0) {
|
otherpad = (pad == queue->srcpad ? queue->sinkpad : queue->srcpad);
|
||||||
return gst_caps_copy (queue->negotiated_caps);
|
otherpeer = gst_pad_get_peer (otherpad);
|
||||||
|
if (otherpeer == NULL) {
|
||||||
|
return gst_pad_get_caps (otherpad);
|
||||||
|
} else {
|
||||||
|
return gst_pad_get_caps (otherpeer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return gst_pad_proxy_getcaps (pad);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstPadLinkReturn
|
static GstPadLinkReturn
|
||||||
gst_queue_link (GstPad * pad, const GstCaps * caps)
|
gst_queue_link_sink (GstPad * pad, GstPad * peer)
|
||||||
|
{
|
||||||
|
return GST_PAD_LINK_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstPadLinkReturn
|
||||||
|
gst_queue_link_src (GstPad * pad, GstPad * peer)
|
||||||
|
{
|
||||||
|
GstPadLinkReturn result = GST_PAD_LINK_OK;
|
||||||
|
|
||||||
|
/* FIXME, see if we need to push or get pulled */
|
||||||
|
if (GST_RPAD_LINKFUNC (peer))
|
||||||
|
result = GST_RPAD_LINKFUNC (peer) (peer, pad);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstBuffer *
|
||||||
|
gst_queue_bufferalloc (GstPad * pad, guint64 offset, guint size, GstCaps * caps)
|
||||||
{
|
{
|
||||||
GstQueue *queue;
|
GstQueue *queue;
|
||||||
GstPadLinkReturn link_ret;
|
GstPad *otherpeer;
|
||||||
|
|
||||||
queue = GST_QUEUE (gst_pad_get_parent (pad));
|
queue = GST_QUEUE (gst_object_get_parent (GST_OBJECT (pad)));
|
||||||
|
|
||||||
if (queue->cur_level.bytes > 0) {
|
otherpeer = gst_pad_get_peer (queue->srcpad);
|
||||||
if (gst_caps_is_equal (caps, queue->negotiated_caps)) {
|
if (otherpeer == NULL || GST_RPAD_BUFFERALLOCFUNC (otherpeer) == NULL) {
|
||||||
return GST_PAD_LINK_OK;
|
/* let the default aloc function do the work */
|
||||||
}
|
return NULL;
|
||||||
return GST_PAD_LINK_REFUSED;
|
} else {
|
||||||
|
return GST_RPAD_BUFFERALLOCFUNC (otherpeer) (otherpeer, offset, size, caps);
|
||||||
}
|
}
|
||||||
|
|
||||||
link_ret = gst_pad_proxy_pad_link (pad, caps);
|
|
||||||
|
|
||||||
if (GST_PAD_LINK_SUCCESSFUL (link_ret)) {
|
|
||||||
/* we store an extra copy of the negotiated caps, just in case
|
|
||||||
* the pads become unnegotiated while we have buffers */
|
|
||||||
gst_caps_replace (&queue->negotiated_caps, gst_caps_copy (caps));
|
|
||||||
}
|
|
||||||
|
|
||||||
return link_ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_queue_locked_flush (GstQueue * queue)
|
gst_queue_locked_flush (GstQueue * queue)
|
||||||
{
|
{
|
||||||
|
@ -419,7 +439,6 @@ gst_queue_locked_flush (GstQueue * queue)
|
||||||
data when flushing */
|
data when flushing */
|
||||||
gst_data_unref (data);
|
gst_data_unref (data);
|
||||||
}
|
}
|
||||||
queue->timeval = NULL;
|
|
||||||
queue->cur_level.buffers = 0;
|
queue->cur_level.buffers = 0;
|
||||||
queue->cur_level.bytes = 0;
|
queue->cur_level.bytes = 0;
|
||||||
queue->cur_level.time = 0;
|
queue->cur_level.time = 0;
|
||||||
|
@ -431,40 +450,6 @@ gst_queue_locked_flush (GstQueue * queue)
|
||||||
g_cond_signal (queue->item_del);
|
g_cond_signal (queue->item_del);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
gst_queue_handle_pending_events (GstQueue * queue)
|
|
||||||
{
|
|
||||||
/* check for events to send upstream */
|
|
||||||
/* g_queue_get_length is glib 2.4, so don't depend on it yet, use ->length */
|
|
||||||
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue,
|
|
||||||
"handling pending events, events queue of size %d",
|
|
||||||
queue->events->length);
|
|
||||||
g_mutex_lock (queue->event_lock);
|
|
||||||
while (!g_queue_is_empty (queue->events)) {
|
|
||||||
GstQueueEventResponse *er;
|
|
||||||
|
|
||||||
er = g_queue_pop_head (queue->events);
|
|
||||||
|
|
||||||
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue,
|
|
||||||
"sending event %p (%d) from event response %p upstream",
|
|
||||||
er->event, GST_EVENT_TYPE (er->event), er);
|
|
||||||
if (er->handled) {
|
|
||||||
/* change this to an assert when this file gets reviewed properly. */
|
|
||||||
GST_ELEMENT_ERROR (queue, CORE, EVENT, (NULL),
|
|
||||||
("already handled event %p (%d) from event response %p upstream",
|
|
||||||
er->event, GST_EVENT_TYPE (er->event), er));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
g_mutex_unlock (queue->event_lock);
|
|
||||||
er->ret = gst_pad_event_default (queue->srcpad, er->event);
|
|
||||||
er->handled = TRUE;
|
|
||||||
g_cond_signal (queue->event_done);
|
|
||||||
g_mutex_lock (queue->event_lock);
|
|
||||||
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue, "event sent");
|
|
||||||
}
|
|
||||||
g_mutex_unlock (queue->event_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define STATUS(queue, msg) \
|
#define STATUS(queue, msg) \
|
||||||
GST_CAT_LOG_OBJECT (queue_dataflow, queue, \
|
GST_CAT_LOG_OBJECT (queue_dataflow, queue, \
|
||||||
"(%s:%s) " msg ": %u of %u-%u buffers, %u of %u-%u " \
|
"(%s:%s) " msg ": %u of %u-%u buffers, %u of %u-%u " \
|
||||||
|
@ -482,58 +467,80 @@ gst_queue_handle_pending_events (GstQueue * queue)
|
||||||
queue->max_size.time, \
|
queue->max_size.time, \
|
||||||
queue->queue->length)
|
queue->queue->length)
|
||||||
|
|
||||||
static void
|
static gboolean
|
||||||
gst_queue_chain (GstPad * pad, GstData * data)
|
gst_queue_handle_sink_event (GstPad * pad, GstEvent * event)
|
||||||
{
|
{
|
||||||
GstQueue *queue;
|
GstQueue *queue;
|
||||||
|
|
||||||
g_return_if_fail (pad != NULL);
|
|
||||||
g_return_if_fail (GST_IS_PAD (pad));
|
|
||||||
g_return_if_fail (data != NULL);
|
|
||||||
|
|
||||||
queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
|
queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
|
||||||
|
|
||||||
restart:
|
|
||||||
/* we have to lock the queue since we span threads */
|
|
||||||
GST_QUEUE_MUTEX_LOCK;
|
GST_QUEUE_MUTEX_LOCK;
|
||||||
|
|
||||||
gst_queue_handle_pending_events (queue);
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_FLUSH:
|
||||||
/* assume don't need to flush this buffer when the queue is filled */
|
STATUS (queue, "received flush event");
|
||||||
queue->flush = FALSE;
|
gst_queue_locked_flush (queue);
|
||||||
|
STATUS (queue, "after flush");
|
||||||
if (GST_IS_EVENT (data)) {
|
break;
|
||||||
switch (GST_EVENT_TYPE (data)) {
|
case GST_EVENT_EOS:
|
||||||
case GST_EVENT_FLUSH:
|
STATUS (queue, "received EOS");
|
||||||
STATUS (queue, "received flush event");
|
break;
|
||||||
gst_queue_locked_flush (queue);
|
default:
|
||||||
STATUS (queue, "after flush");
|
/* we put the event in the queue, we don't have to act ourselves */
|
||||||
break;
|
GST_CAT_LOG_OBJECT (queue_dataflow, queue,
|
||||||
case GST_EVENT_EOS:
|
"adding event %p of type %d", event, GST_EVENT_TYPE (event));
|
||||||
STATUS (queue, "received EOS");
|
break;
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* we put the event in the queue, we don't have to act ourselves */
|
|
||||||
GST_CAT_LOG_OBJECT (queue_dataflow, queue,
|
|
||||||
"adding event %p of type %d", data, GST_EVENT_TYPE (data));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GST_IS_BUFFER (data))
|
gst_event_ref (event);
|
||||||
GST_CAT_LOG_OBJECT (queue_dataflow, queue,
|
g_queue_push_tail (queue->queue, event);
|
||||||
"adding buffer %p of size %d", data, GST_BUFFER_SIZE (data));
|
g_cond_signal (queue->item_add);
|
||||||
|
GST_QUEUE_MUTEX_UNLOCK;
|
||||||
|
|
||||||
/* We make space available if we're "full" according to whatever
|
return TRUE;
|
||||||
* the user defined as "full". Note that this only applies to buffers.
|
}
|
||||||
* We always handle events and they don't count in our statistics. */
|
|
||||||
if (GST_IS_BUFFER (data) &&
|
static gboolean
|
||||||
((queue->max_size.buffers > 0 &&
|
gst_queue_is_empty (GstQueue * queue)
|
||||||
|
{
|
||||||
|
return (queue->queue->length == 0 ||
|
||||||
|
(queue->min_threshold.buffers > 0 &&
|
||||||
|
queue->cur_level.buffers < queue->min_threshold.buffers) ||
|
||||||
|
(queue->min_threshold.bytes > 0 &&
|
||||||
|
queue->cur_level.bytes < queue->min_threshold.bytes) ||
|
||||||
|
(queue->min_threshold.time > 0 &&
|
||||||
|
queue->cur_level.time < queue->min_threshold.time));
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_queue_is_filled (GstQueue * queue)
|
||||||
|
{
|
||||||
|
return (((queue->max_size.buffers > 0 &&
|
||||||
queue->cur_level.buffers >= queue->max_size.buffers) ||
|
queue->cur_level.buffers >= queue->max_size.buffers) ||
|
||||||
(queue->max_size.bytes > 0 &&
|
(queue->max_size.bytes > 0 &&
|
||||||
queue->cur_level.bytes >= queue->max_size.bytes) ||
|
queue->cur_level.bytes >= queue->max_size.bytes) ||
|
||||||
(queue->max_size.time > 0 &&
|
(queue->max_size.time > 0 &&
|
||||||
queue->cur_level.time >= queue->max_size.time))) {
|
queue->cur_level.time >= queue->max_size.time)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_queue_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
|
{
|
||||||
|
GstQueue *queue;
|
||||||
|
|
||||||
|
queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
|
||||||
|
|
||||||
|
/* we have to lock the queue since we span threads */
|
||||||
|
GST_QUEUE_MUTEX_LOCK;
|
||||||
|
|
||||||
|
GST_CAT_LOG_OBJECT (queue_dataflow, queue,
|
||||||
|
"adding buffer %p of size %d", buffer, GST_BUFFER_SIZE (buffer));
|
||||||
|
|
||||||
|
/* We make space available if we're "full" according to whatever
|
||||||
|
* the user defined as "full". Note that this only applies to buffers.
|
||||||
|
* We always handle events and they don't count in our statistics. */
|
||||||
|
if (gst_queue_is_filled (queue)) {
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
GST_QUEUE_MUTEX_UNLOCK;
|
||||||
g_signal_emit (G_OBJECT (queue), gst_queue_signals[SIGNAL_OVERRUN], 0);
|
g_signal_emit (G_OBJECT (queue), gst_queue_signals[SIGNAL_OVERRUN], 0);
|
||||||
GST_QUEUE_MUTEX_LOCK;
|
GST_QUEUE_MUTEX_LOCK;
|
||||||
|
@ -577,15 +584,15 @@ restart:
|
||||||
queue->queue->tail = g_list_last (item);
|
queue->queue->tail = g_list_last (item);
|
||||||
queue->queue->length--;
|
queue->queue->length--;
|
||||||
|
|
||||||
/* and unref the data at the end. Twice, because we keep a ref
|
/* and unref the buffer at the end. Twice, because we keep a ref
|
||||||
* to make things read-only. Also keep our list uptodate. */
|
* to make things read-only. Also keep our list uptodate. */
|
||||||
queue->cur_level.bytes -= GST_BUFFER_SIZE (data);
|
queue->cur_level.bytes -= GST_BUFFER_SIZE (buffer);
|
||||||
queue->cur_level.buffers--;
|
queue->cur_level.buffers--;
|
||||||
if (GST_BUFFER_DURATION (data) != GST_CLOCK_TIME_NONE)
|
if (GST_BUFFER_DURATION (buffer) != GST_CLOCK_TIME_NONE)
|
||||||
queue->cur_level.time -= GST_BUFFER_DURATION (data);
|
queue->cur_level.time -= GST_BUFFER_DURATION (buffer);
|
||||||
|
|
||||||
gst_data_unref (data);
|
gst_buffer_unref (buffer);
|
||||||
gst_data_unref (data);
|
gst_buffer_unref (buffer);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -597,63 +604,12 @@ restart:
|
||||||
case GST_QUEUE_NO_LEAK:
|
case GST_QUEUE_NO_LEAK:
|
||||||
STATUS (queue, "pre-full wait");
|
STATUS (queue, "pre-full wait");
|
||||||
|
|
||||||
while ((queue->max_size.buffers > 0 &&
|
while (gst_queue_is_filled (queue)) {
|
||||||
queue->cur_level.buffers >= queue->max_size.buffers) ||
|
STATUS (queue, "waiting for item_del signal from thread using qlock");
|
||||||
(queue->max_size.bytes > 0 &&
|
g_cond_wait (queue->item_del, queue->qlock);
|
||||||
queue->cur_level.bytes >= queue->max_size.bytes) ||
|
|
||||||
(queue->max_size.time > 0 &&
|
|
||||||
queue->cur_level.time >= queue->max_size.time)) {
|
|
||||||
/* if there's a pending state change for this queue
|
/* if there's a pending state change for this queue
|
||||||
* or its manager, switch back to iterator so bottom
|
* or its manager, switch back to iterator so bottom
|
||||||
* half of state change executes */
|
* half of state change executes */
|
||||||
if (queue->interrupt) {
|
|
||||||
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue, "interrupted");
|
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
|
||||||
if (gst_scheduler_interrupt (gst_pad_get_scheduler (queue->sinkpad),
|
|
||||||
GST_ELEMENT (queue))) {
|
|
||||||
goto out_unref;
|
|
||||||
}
|
|
||||||
/* if we got here because we were unlocked after a
|
|
||||||
* flush, we don't need to add the buffer to the
|
|
||||||
* queue again */
|
|
||||||
if (queue->flush) {
|
|
||||||
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue,
|
|
||||||
"not adding pending buffer after flush");
|
|
||||||
goto out_unref;
|
|
||||||
}
|
|
||||||
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue,
|
|
||||||
"adding pending buffer after interrupt");
|
|
||||||
goto restart;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GST_STATE (queue) != GST_STATE_PLAYING) {
|
|
||||||
/* this means the other end is shut down. Try to
|
|
||||||
* signal to resolve the error */
|
|
||||||
if (!queue->may_deadlock) {
|
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
|
||||||
gst_data_unref (data);
|
|
||||||
GST_ELEMENT_ERROR (queue, CORE, THREAD, (NULL),
|
|
||||||
("deadlock found, shutting down source pad elements"));
|
|
||||||
/* we don't go to out_unref here, since we want to
|
|
||||||
* unref the buffer *before* calling GST_ELEMENT_ERROR */
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
GST_CAT_WARNING_OBJECT (queue_dataflow, queue,
|
|
||||||
"%s: waiting for the app to restart "
|
|
||||||
"source pad elements", GST_ELEMENT_NAME (queue));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* OK, we've got a serious issue here. Imagine the situation
|
|
||||||
* where the puller (next element) is sending an event here,
|
|
||||||
* so it cannot pull events from the queue, and we cannot
|
|
||||||
* push data further because the queue is 'full' and therefore,
|
|
||||||
* we wait here (and do not handle events): deadlock! to solve
|
|
||||||
* that, we handle pending upstream events here, too. */
|
|
||||||
gst_queue_handle_pending_events (queue);
|
|
||||||
|
|
||||||
STATUS (queue, "waiting for item_del signal from thread using qlock");
|
|
||||||
g_cond_wait (queue->item_del, queue->qlock);
|
|
||||||
STATUS (queue, "received item_del signal from thread using qlock");
|
STATUS (queue, "received item_del signal from thread using qlock");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -666,19 +622,17 @@ restart:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* put the buffer on the tail of the list. We keep a reference,
|
/* put the buffer on the tail of the list. We keep a reference,
|
||||||
* so that the data is read-only while in here. There's a good
|
* so that the buffer is read-only while in here. There's a good
|
||||||
* reason to do so: we have a size and time counter, and any
|
* reason to do so: we have a size and time counter, and any
|
||||||
* modification to the content could change any of the two. */
|
* modification to the content could change any of the two. */
|
||||||
gst_data_ref (data);
|
gst_buffer_ref (buffer);
|
||||||
g_queue_push_tail (queue->queue, data);
|
g_queue_push_tail (queue->queue, buffer);
|
||||||
|
|
||||||
/* Note that we only add buffers (not events) to the statistics */
|
/* add buffer to the statistics */
|
||||||
if (GST_IS_BUFFER (data)) {
|
queue->cur_level.buffers++;
|
||||||
queue->cur_level.buffers++;
|
queue->cur_level.bytes += GST_BUFFER_SIZE (buffer);
|
||||||
queue->cur_level.bytes += GST_BUFFER_SIZE (data);
|
if (GST_BUFFER_DURATION (buffer) != GST_CLOCK_TIME_NONE)
|
||||||
if (GST_BUFFER_DURATION (data) != GST_CLOCK_TIME_NONE)
|
queue->cur_level.time += GST_BUFFER_DURATION (buffer);
|
||||||
queue->cur_level.time += GST_BUFFER_DURATION (data);
|
|
||||||
}
|
|
||||||
|
|
||||||
STATUS (queue, "+ level");
|
STATUS (queue, "+ level");
|
||||||
|
|
||||||
|
@ -686,94 +640,41 @@ restart:
|
||||||
g_cond_signal (queue->item_add);
|
g_cond_signal (queue->item_add);
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
GST_QUEUE_MUTEX_UNLOCK;
|
||||||
|
|
||||||
return;
|
return GST_FLOW_OK;
|
||||||
|
|
||||||
out_unref:
|
out_unref:
|
||||||
gst_data_unref (data);
|
gst_buffer_unref (buffer);
|
||||||
return;
|
|
||||||
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstData *
|
static GstFlowReturn
|
||||||
gst_queue_get (GstPad * pad)
|
gst_queue_get (GstPad * pad, GstBuffer ** buffer)
|
||||||
{
|
{
|
||||||
GstQueue *queue;
|
GstQueue *queue;
|
||||||
GstData *data;
|
GstData *data;
|
||||||
|
GstFlowReturn result = GST_FLOW_OK;
|
||||||
|
|
||||||
g_return_val_if_fail (pad != NULL, NULL);
|
queue = GST_QUEUE (gst_object_get_parent (GST_OBJECT (pad)));
|
||||||
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
|
|
||||||
|
|
||||||
queue = GST_QUEUE (gst_pad_get_parent (pad));
|
|
||||||
|
|
||||||
restart:
|
|
||||||
/* have to lock for thread-safety */
|
/* have to lock for thread-safety */
|
||||||
GST_QUEUE_MUTEX_LOCK;
|
GST_QUEUE_MUTEX_LOCK;
|
||||||
|
|
||||||
if (queue->queue->length == 0 ||
|
restart:
|
||||||
(queue->min_threshold.buffers > 0 &&
|
if (gst_queue_is_empty (queue)) {
|
||||||
queue->cur_level.buffers < queue->min_threshold.buffers) ||
|
|
||||||
(queue->min_threshold.bytes > 0 &&
|
|
||||||
queue->cur_level.bytes < queue->min_threshold.bytes) ||
|
|
||||||
(queue->min_threshold.time > 0 &&
|
|
||||||
queue->cur_level.time < queue->min_threshold.time)) {
|
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
GST_QUEUE_MUTEX_UNLOCK;
|
||||||
g_signal_emit (G_OBJECT (queue), gst_queue_signals[SIGNAL_UNDERRUN], 0);
|
g_signal_emit (G_OBJECT (queue), gst_queue_signals[SIGNAL_UNDERRUN], 0);
|
||||||
GST_QUEUE_MUTEX_LOCK;
|
GST_QUEUE_MUTEX_LOCK;
|
||||||
|
|
||||||
STATUS (queue, "pre-empty wait");
|
STATUS (queue, "pre-empty wait");
|
||||||
while (queue->queue->length == 0 ||
|
while (gst_queue_is_empty (queue)) {
|
||||||
(queue->min_threshold.buffers > 0 &&
|
|
||||||
queue->cur_level.buffers < queue->min_threshold.buffers) ||
|
|
||||||
(queue->min_threshold.bytes > 0 &&
|
|
||||||
queue->cur_level.bytes < queue->min_threshold.bytes) ||
|
|
||||||
(queue->min_threshold.time > 0 &&
|
|
||||||
queue->cur_level.time < queue->min_threshold.time)) {
|
|
||||||
/* if there's a pending state change for this queue or its
|
|
||||||
* manager, switch back to iterator so bottom half of state
|
|
||||||
* change executes. */
|
|
||||||
if (queue->interrupt) {
|
|
||||||
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue, "interrupted");
|
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
|
||||||
if (gst_scheduler_interrupt (gst_pad_get_scheduler (queue->srcpad),
|
|
||||||
GST_ELEMENT (queue)))
|
|
||||||
return GST_DATA (gst_event_new (GST_EVENT_INTERRUPT));
|
|
||||||
goto restart;
|
|
||||||
}
|
|
||||||
if (GST_STATE (queue) != GST_STATE_PLAYING) {
|
|
||||||
/* this means the other end is shut down */
|
|
||||||
if (!queue->may_deadlock) {
|
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
|
||||||
GST_ELEMENT_ERROR (queue, CORE, THREAD, (NULL),
|
|
||||||
("deadlock found, shutting down sink pad elements"));
|
|
||||||
goto restart;
|
|
||||||
} else {
|
|
||||||
GST_CAT_WARNING_OBJECT (queue_dataflow, queue,
|
|
||||||
"%s: waiting for the app to restart "
|
|
||||||
"source pad elements", GST_ELEMENT_NAME (queue));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
STATUS (queue, "waiting for item_add");
|
STATUS (queue, "waiting for item_add");
|
||||||
|
|
||||||
if (queue->block_timeout != GST_CLOCK_TIME_NONE) {
|
GST_LOG_OBJECT (queue, "doing g_cond_wait using qlock from thread %p",
|
||||||
GTimeVal timeout;
|
g_thread_self ());
|
||||||
|
g_cond_wait (queue->item_add, queue->qlock);
|
||||||
g_get_current_time (&timeout);
|
GST_LOG_OBJECT (queue, "done g_cond_wait using qlock from thread %p",
|
||||||
g_time_val_add (&timeout, queue->block_timeout / 1000);
|
g_thread_self ());
|
||||||
GST_LOG_OBJECT (queue, "g_cond_time_wait using qlock from thread %p",
|
|
||||||
g_thread_self ());
|
|
||||||
if (!g_cond_timed_wait (queue->item_add, queue->qlock, &timeout)) {
|
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
|
||||||
GST_CAT_WARNING_OBJECT (queue_dataflow, queue,
|
|
||||||
"Sending filler event");
|
|
||||||
return GST_DATA (gst_event_new_filler ());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
GST_LOG_OBJECT (queue, "doing g_cond_wait using qlock from thread %p",
|
|
||||||
g_thread_self ());
|
|
||||||
g_cond_wait (queue->item_add, queue->qlock);
|
|
||||||
GST_LOG_OBJECT (queue, "done g_cond_wait using qlock from thread %p",
|
|
||||||
g_thread_self ());
|
|
||||||
}
|
|
||||||
STATUS (queue, "got item_add signal");
|
STATUS (queue, "got item_add signal");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -788,120 +689,68 @@ restart:
|
||||||
GST_CAT_LOG_OBJECT (queue_dataflow, queue,
|
GST_CAT_LOG_OBJECT (queue_dataflow, queue,
|
||||||
"retrieved data %p from queue", data);
|
"retrieved data %p from queue", data);
|
||||||
|
|
||||||
if (data == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (GST_IS_BUFFER (data)) {
|
if (GST_IS_BUFFER (data)) {
|
||||||
/* Update statistics */
|
/* Update statistics */
|
||||||
queue->cur_level.buffers--;
|
queue->cur_level.buffers--;
|
||||||
queue->cur_level.bytes -= GST_BUFFER_SIZE (data);
|
queue->cur_level.bytes -= GST_BUFFER_SIZE (data);
|
||||||
if (GST_BUFFER_DURATION (data) != GST_CLOCK_TIME_NONE)
|
if (GST_BUFFER_DURATION (data) != GST_CLOCK_TIME_NONE)
|
||||||
queue->cur_level.time -= GST_BUFFER_DURATION (data);
|
queue->cur_level.time -= GST_BUFFER_DURATION (data);
|
||||||
|
|
||||||
|
*buffer = GST_BUFFER (data);
|
||||||
|
} else {
|
||||||
|
if (GST_EVENT_TYPE (data) == GST_EVENT_EOS) {
|
||||||
|
result = GST_FLOW_WRONG_STATE;
|
||||||
|
}
|
||||||
|
gst_pad_push_event (queue->srcpad, GST_EVENT (data));
|
||||||
|
if (result == GST_FLOW_OK)
|
||||||
|
goto restart;
|
||||||
|
else
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now that we're done, we can lose our own reference to
|
/* Now that we're done, we can lose our own reference to
|
||||||
* the item, since we're no longer in danger. */
|
* the item, since we're no longer in danger. */
|
||||||
gst_data_unref (data);
|
gst_data_unref (data);
|
||||||
|
|
||||||
|
done:
|
||||||
STATUS (queue, "after _get()");
|
STATUS (queue, "after _get()");
|
||||||
|
|
||||||
GST_CAT_LOG_OBJECT (queue_dataflow, queue, "signalling item_del");
|
GST_CAT_LOG_OBJECT (queue_dataflow, queue, "signalling item_del");
|
||||||
g_cond_signal (queue->item_del);
|
g_cond_signal (queue->item_del);
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
GST_QUEUE_MUTEX_UNLOCK;
|
||||||
|
|
||||||
/* FIXME: I suppose this needs to be locked, since the EOS
|
return result;
|
||||||
* bit affects the pipeline state. However, that bit is
|
|
||||||
* locked too so it'd cause a deadlock. */
|
|
||||||
if (GST_IS_EVENT (data)) {
|
|
||||||
GstEvent *event = GST_EVENT (data);
|
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
|
||||||
case GST_EVENT_EOS:
|
|
||||||
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue,
|
|
||||||
"queue \"%s\" eos", GST_ELEMENT_NAME (queue));
|
|
||||||
gst_element_set_eos (GST_ELEMENT (queue));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_queue_handle_src_event (GstPad * pad, GstEvent * event)
|
gst_queue_handle_src_event (GstPad * pad, GstEvent * event)
|
||||||
{
|
{
|
||||||
GstQueue *queue = GST_QUEUE (gst_pad_get_parent (pad));
|
GstQueue *queue = GST_QUEUE (gst_object_get_parent (GST_OBJECT (pad)));
|
||||||
gboolean res;
|
gboolean res = TRUE;
|
||||||
|
|
||||||
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue, "got event %p (%d)",
|
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue, "got event %p (%d)",
|
||||||
event, GST_EVENT_TYPE (event));
|
event, GST_EVENT_TYPE (event));
|
||||||
|
|
||||||
|
gst_event_ref (event);
|
||||||
|
res = gst_pad_event_default (pad, event);
|
||||||
GST_QUEUE_MUTEX_LOCK;
|
GST_QUEUE_MUTEX_LOCK;
|
||||||
|
|
||||||
if (gst_element_get_state (GST_ELEMENT (queue)) == GST_STATE_PLAYING) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
GstQueueEventResponse er;
|
case GST_EVENT_FLUSH:
|
||||||
|
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue,
|
||||||
/* push the event to the queue and wait for upstream consumption */
|
"FLUSH event, flushing queue\n");
|
||||||
er.event = event;
|
gst_queue_locked_flush (queue);
|
||||||
er.handled = FALSE;
|
break;
|
||||||
g_mutex_lock (queue->event_lock);
|
case GST_EVENT_SEEK:
|
||||||
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue,
|
if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) {
|
||||||
"putting event %p (%d) on internal queue", event,
|
|
||||||
GST_EVENT_TYPE (event));
|
|
||||||
g_queue_push_tail (queue->events, &er);
|
|
||||||
g_mutex_unlock (queue->event_lock);
|
|
||||||
GST_CAT_WARNING_OBJECT (queue_dataflow, queue,
|
|
||||||
"Preparing for loop for event handler");
|
|
||||||
/* see the chain function on why this is here - it prevents a deadlock */
|
|
||||||
g_cond_signal (queue->item_del);
|
|
||||||
while (!er.handled) {
|
|
||||||
GTimeVal timeout;
|
|
||||||
|
|
||||||
g_get_current_time (&timeout);
|
|
||||||
g_time_val_add (&timeout, 500 * 1000); /* half a second */
|
|
||||||
GST_LOG_OBJECT (queue, "doing g_cond_wait using qlock from thread %p",
|
|
||||||
g_thread_self ());
|
|
||||||
if (!g_cond_timed_wait (queue->event_done, queue->qlock, &timeout) &&
|
|
||||||
!er.handled) {
|
|
||||||
GST_CAT_WARNING_OBJECT (queue_dataflow, queue,
|
|
||||||
"timeout in upstream event handling, dropping event %p (%d)",
|
|
||||||
er.event, GST_EVENT_TYPE (er.event));
|
|
||||||
g_mutex_lock (queue->event_lock);
|
|
||||||
/* since this queue is for src events (ie upstream), this thread is
|
|
||||||
* the only one that is pushing stuff on it, so we're sure that
|
|
||||||
* it's still the tail element. FIXME: But in practice, we should use
|
|
||||||
* GList instead of GQueue for this so we can remove any element in
|
|
||||||
* the list. */
|
|
||||||
g_queue_pop_tail (queue->events);
|
|
||||||
g_mutex_unlock (queue->event_lock);
|
|
||||||
gst_event_unref (er.event);
|
|
||||||
res = FALSE;
|
|
||||||
goto handled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GST_CAT_WARNING_OBJECT (queue_dataflow, queue, "Event handled");
|
|
||||||
res = er.ret;
|
|
||||||
} else {
|
|
||||||
res = gst_pad_event_default (pad, event);
|
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
|
||||||
case GST_EVENT_FLUSH:
|
|
||||||
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue,
|
|
||||||
"FLUSH event, flushing queue\n");
|
|
||||||
gst_queue_locked_flush (queue);
|
gst_queue_locked_flush (queue);
|
||||||
break;
|
}
|
||||||
case GST_EVENT_SEEK:
|
default:
|
||||||
if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) {
|
break;
|
||||||
gst_queue_locked_flush (queue);
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
handled:
|
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
GST_QUEUE_MUTEX_UNLOCK;
|
||||||
|
gst_event_unref (event);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -911,10 +760,10 @@ gst_queue_handle_src_query (GstPad * pad,
|
||||||
GstQueryType type, GstFormat * fmt, gint64 * value)
|
GstQueryType type, GstFormat * fmt, gint64 * value)
|
||||||
{
|
{
|
||||||
GstQueue *queue = GST_QUEUE (gst_pad_get_parent (pad));
|
GstQueue *queue = GST_QUEUE (gst_pad_get_parent (pad));
|
||||||
gboolean res;
|
|
||||||
|
|
||||||
res = gst_pad_query (GST_PAD_PEER (queue->sinkpad), type, fmt, value);
|
if (!GST_PAD_PEER (queue->sinkpad))
|
||||||
if (!res)
|
return FALSE;
|
||||||
|
if (!gst_pad_query (GST_PAD_PEER (queue->sinkpad), type, fmt, value))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (type == GST_QUERY_POSITION) {
|
if (type == GST_QUERY_POSITION) {
|
||||||
|
@ -935,22 +784,76 @@ gst_queue_handle_src_query (GstPad * pad,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static void
|
||||||
gst_queue_release_locks (GstElement * element)
|
gst_queue_loop (GstElement * element)
|
||||||
{
|
{
|
||||||
GstQueue *queue;
|
GstQueue *queue;
|
||||||
|
GstTask *task;
|
||||||
|
GstBuffer *buffer;
|
||||||
|
GstFlowReturn ret;
|
||||||
|
|
||||||
|
g_return_if_fail (element != NULL);
|
||||||
|
g_return_if_fail (GST_IS_QUEUE (element));
|
||||||
|
|
||||||
queue = GST_QUEUE (element);
|
queue = GST_QUEUE (element);
|
||||||
|
task = queue->task;
|
||||||
|
|
||||||
GST_QUEUE_MUTEX_LOCK;
|
ret = gst_queue_get (queue->srcpad, &buffer);
|
||||||
queue->interrupt = TRUE;
|
if (ret != GST_FLOW_OK) {
|
||||||
g_cond_signal (queue->item_add);
|
GST_CAT_LOG_OBJECT (queue_dataflow, queue, "stopping, get returned %d",
|
||||||
g_cond_signal (queue->item_del);
|
ret);
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
gst_task_stop (task);
|
||||||
|
return;
|
||||||
return TRUE;
|
}
|
||||||
|
ret = gst_pad_push (queue->srcpad, buffer);
|
||||||
|
if (ret != GST_FLOW_OK) {
|
||||||
|
GST_CAT_LOG_OBJECT (queue_dataflow, queue, "stopping, push returned %d",
|
||||||
|
ret);
|
||||||
|
gst_task_stop (task);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_queue_src_activate (GstPad * pad, gboolean active)
|
||||||
|
{
|
||||||
|
gboolean result = FALSE;
|
||||||
|
GstQueue *queue;
|
||||||
|
|
||||||
|
queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
|
||||||
|
|
||||||
|
if (active) {
|
||||||
|
/* if we have a scheduler we can start the task */
|
||||||
|
if (GST_ELEMENT_MANAGER (queue)) {
|
||||||
|
GST_STREAM_LOCK (pad);
|
||||||
|
queue->task =
|
||||||
|
gst_scheduler_create_task (GST_ELEMENT_MANAGER (queue)->scheduler,
|
||||||
|
(GstTaskFunction) gst_queue_loop, queue);
|
||||||
|
|
||||||
|
gst_task_start (queue->task);
|
||||||
|
GST_STREAM_UNLOCK (pad);
|
||||||
|
result = TRUE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* step 1, unblock chain and get functions */
|
||||||
|
queue->interrupt = TRUE;
|
||||||
|
g_cond_signal (queue->item_add);
|
||||||
|
g_cond_signal (queue->item_del);
|
||||||
|
|
||||||
|
/* step 2, make sure streaming finishes */
|
||||||
|
GST_STREAM_LOCK (pad);
|
||||||
|
/* step 3, stop the task */
|
||||||
|
gst_task_stop (queue->task);
|
||||||
|
gst_object_unref (GST_OBJECT (queue->task));
|
||||||
|
GST_STREAM_UNLOCK (pad);
|
||||||
|
|
||||||
|
result = TRUE;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static GstElementStateReturn
|
static GstElementStateReturn
|
||||||
gst_queue_change_state (GstElement * element)
|
gst_queue_change_state (GstElement * element)
|
||||||
{
|
{
|
||||||
|
@ -970,53 +873,28 @@ gst_queue_change_state (GstElement * element)
|
||||||
case GST_STATE_NULL_TO_READY:
|
case GST_STATE_NULL_TO_READY:
|
||||||
gst_queue_locked_flush (queue);
|
gst_queue_locked_flush (queue);
|
||||||
break;
|
break;
|
||||||
case GST_STATE_PAUSED_TO_PLAYING:
|
case GST_STATE_READY_TO_PAUSED:
|
||||||
if (!GST_PAD_IS_LINKED (queue->sinkpad)) {
|
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, queue,
|
|
||||||
"queue %s is not linked", GST_ELEMENT_NAME (queue));
|
|
||||||
/* FIXME can this be? */
|
|
||||||
g_cond_signal (queue->item_add);
|
|
||||||
|
|
||||||
ret = GST_STATE_FAILURE;
|
|
||||||
goto unlock;
|
|
||||||
} else {
|
|
||||||
GstScheduler *src_sched, *sink_sched;
|
|
||||||
|
|
||||||
src_sched = gst_pad_get_scheduler (GST_PAD (queue->srcpad));
|
|
||||||
sink_sched = gst_pad_get_scheduler (GST_PAD (queue->sinkpad));
|
|
||||||
|
|
||||||
if (src_sched == sink_sched) {
|
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, queue,
|
|
||||||
"queue %s does not connect different schedulers",
|
|
||||||
GST_ELEMENT_NAME (queue));
|
|
||||||
|
|
||||||
g_warning ("queue %s does not connect different schedulers",
|
|
||||||
GST_ELEMENT_NAME (queue));
|
|
||||||
|
|
||||||
ret = GST_STATE_FAILURE;
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
queue->interrupt = FALSE;
|
|
||||||
break;
|
break;
|
||||||
case GST_STATE_PAUSED_TO_READY:
|
case GST_STATE_PAUSED_TO_PLAYING:
|
||||||
gst_queue_locked_flush (queue);
|
queue->interrupt = FALSE;
|
||||||
gst_caps_replace (&queue->negotiated_caps, NULL);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
|
||||||
|
|
||||||
/* this is an ugly hack to make sure our pads are always active.
|
switch (GST_STATE_TRANSITION (element)) {
|
||||||
* Reason for this is that pad activation for the queue element
|
case GST_STATE_PLAYING_TO_PAUSED:
|
||||||
* depends on 2 schedulers (ugh) */
|
break;
|
||||||
gst_pad_set_active (queue->sinkpad, TRUE);
|
case GST_STATE_PAUSED_TO_READY:
|
||||||
gst_pad_set_active (queue->srcpad, TRUE);
|
gst_queue_locked_flush (queue);
|
||||||
|
break;
|
||||||
unlock:
|
case GST_STATE_READY_TO_NULL:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
GST_QUEUE_MUTEX_UNLOCK;
|
||||||
|
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_STATES, element, "done with state change");
|
GST_CAT_LOG_OBJECT (GST_CAT_STATES, element, "done with state change");
|
||||||
|
@ -1024,7 +902,6 @@ unlock:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_queue_set_property (GObject * object,
|
gst_queue_set_property (GObject * object,
|
||||||
guint prop_id, const GValue * value, GParamSpec * pspec)
|
guint prop_id, const GValue * value, GParamSpec * pspec)
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include <gst/gstelement.h>
|
#include <gst/gstelement.h>
|
||||||
|
#include <gst/gsttask.h>
|
||||||
|
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
@ -66,6 +67,8 @@ struct _GstQueue {
|
||||||
/* the queue of data we're keeping our grubby hands on */
|
/* the queue of data we're keeping our grubby hands on */
|
||||||
GQueue *queue;
|
GQueue *queue;
|
||||||
|
|
||||||
|
GstTask *task;
|
||||||
|
|
||||||
GstQueueSize
|
GstQueueSize
|
||||||
cur_level, /* currently in the queue */
|
cur_level, /* currently in the queue */
|
||||||
max_size, /* max. amount of data allowed in the queue */
|
max_size, /* max. amount of data allowed in the queue */
|
||||||
|
@ -80,21 +83,12 @@ struct _GstQueue {
|
||||||
|
|
||||||
/* it the queue should fail on possible deadlocks */
|
/* it the queue should fail on possible deadlocks */
|
||||||
gboolean may_deadlock;
|
gboolean may_deadlock;
|
||||||
|
|
||||||
gboolean interrupt;
|
gboolean interrupt;
|
||||||
gboolean flush;
|
gboolean flush;
|
||||||
|
|
||||||
GMutex *qlock; /* lock for queue (vs object lock) */
|
GMutex *qlock; /* lock for queue (vs object lock) */
|
||||||
GCond *item_add; /* signals buffers now available for reading */
|
GCond *item_add; /* signals buffers now available for reading */
|
||||||
GCond *item_del; /* signals space now available for writing */
|
GCond *item_del; /* signals space now available for writing */
|
||||||
GCond *event_done; /* upstream event signaller */
|
|
||||||
|
|
||||||
GTimeVal *timeval; /* the timeout for the queue locking */
|
|
||||||
GQueue *events; /* upstream events get decoupled here */
|
|
||||||
|
|
||||||
GstCaps *negotiated_caps;
|
|
||||||
|
|
||||||
GMutex *event_lock; /* lock when handling the events queue */
|
|
||||||
|
|
||||||
gpointer _gst_reserved[GST_PADDING - 1];
|
gpointer _gst_reserved[GST_PADDING - 1];
|
||||||
};
|
};
|
||||||
|
|
|
@ -76,13 +76,7 @@ gst_scheduler_class_init (GstSchedulerClass * klass)
|
||||||
static void
|
static void
|
||||||
gst_scheduler_init (GstScheduler * sched)
|
gst_scheduler_init (GstScheduler * sched)
|
||||||
{
|
{
|
||||||
sched->clock_providers = NULL;
|
|
||||||
sched->clock_receivers = NULL;
|
|
||||||
sched->schedulers = NULL;
|
|
||||||
sched->state = GST_SCHEDULER_STATE_NONE;
|
|
||||||
sched->parent = NULL;
|
sched->parent = NULL;
|
||||||
sched->parent_sched = NULL;
|
|
||||||
sched->clock = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -90,15 +84,7 @@ gst_scheduler_dispose (GObject * object)
|
||||||
{
|
{
|
||||||
GstScheduler *sched = GST_SCHEDULER (object);
|
GstScheduler *sched = GST_SCHEDULER (object);
|
||||||
|
|
||||||
/* thse lists should all be NULL */
|
G_OBJECT_CLASS (parent_class)->dispose (G_OBJECT (sched));
|
||||||
GST_DEBUG ("scheduler %p dispose %p %p %p",
|
|
||||||
object,
|
|
||||||
sched->clock_providers, sched->clock_receivers, sched->schedulers);
|
|
||||||
|
|
||||||
gst_object_replace ((GstObject **) & sched->current_clock, NULL);
|
|
||||||
gst_object_replace ((GstObject **) & sched->clock, NULL);
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -139,71 +125,6 @@ gst_scheduler_reset (GstScheduler * sched)
|
||||||
sclass->reset (sched);
|
sclass->reset (sched);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_scheduler_pad_link:
|
|
||||||
* @sched: the scheduler
|
|
||||||
* @srcpad: the srcpad to link
|
|
||||||
* @sinkpad: the sinkpad to link to
|
|
||||||
*
|
|
||||||
* Links the srcpad to the given sinkpad.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
gst_scheduler_pad_link (GstScheduler * sched, GstPad * srcpad, GstPad * sinkpad)
|
|
||||||
{
|
|
||||||
GstSchedulerClass *sclass;
|
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_SCHEDULER (sched));
|
|
||||||
g_return_if_fail (GST_IS_PAD (srcpad));
|
|
||||||
g_return_if_fail (GST_IS_PAD (sinkpad));
|
|
||||||
|
|
||||||
sclass = GST_SCHEDULER_GET_CLASS (sched);
|
|
||||||
|
|
||||||
if (sclass->pad_link)
|
|
||||||
sclass->pad_link (sched, srcpad, sinkpad);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_scheduler_pad_unlink:
|
|
||||||
* @sched: the scheduler
|
|
||||||
* @srcpad: the srcpad to unlink
|
|
||||||
* @sinkpad: the sinkpad to unlink from
|
|
||||||
*
|
|
||||||
* Unlinks the srcpad from the given sinkpad.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
gst_scheduler_pad_unlink (GstScheduler * sched, GstPad * srcpad,
|
|
||||||
GstPad * sinkpad)
|
|
||||||
{
|
|
||||||
GstSchedulerClass *sclass;
|
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_SCHEDULER (sched));
|
|
||||||
g_return_if_fail (GST_IS_PAD (srcpad));
|
|
||||||
g_return_if_fail (GST_IS_PAD (sinkpad));
|
|
||||||
|
|
||||||
sclass = GST_SCHEDULER_GET_CLASS (sched);
|
|
||||||
|
|
||||||
if (sclass->pad_unlink)
|
|
||||||
sclass->pad_unlink (sched, srcpad, sinkpad);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_scheduler_pad_select:
|
|
||||||
* @sched: the scheduler
|
|
||||||
* @padlist: the padlist to select on
|
|
||||||
*
|
|
||||||
* register the given padlist for a select operation.
|
|
||||||
*
|
|
||||||
* Returns: the pad which received a buffer.
|
|
||||||
*/
|
|
||||||
GstPad *
|
|
||||||
gst_scheduler_pad_select (GstScheduler * sched, GList * padlist)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (GST_IS_SCHEDULER (sched), NULL);
|
|
||||||
g_return_val_if_fail (padlist != NULL, NULL);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_scheduler_add_element:
|
* gst_scheduler_add_element:
|
||||||
* @sched: the scheduler
|
* @sched: the scheduler
|
||||||
|
@ -215,43 +136,10 @@ void
|
||||||
gst_scheduler_add_element (GstScheduler * sched, GstElement * element)
|
gst_scheduler_add_element (GstScheduler * sched, GstElement * element)
|
||||||
{
|
{
|
||||||
GstSchedulerClass *sclass;
|
GstSchedulerClass *sclass;
|
||||||
gboolean redistribute_clock = FALSE;
|
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_SCHEDULER (sched));
|
g_return_if_fail (GST_IS_SCHEDULER (sched));
|
||||||
g_return_if_fail (GST_IS_ELEMENT (element));
|
g_return_if_fail (GST_IS_ELEMENT (element));
|
||||||
|
|
||||||
/* if it's already in this scheduler, don't bother doing anything */
|
|
||||||
if (GST_ELEMENT_SCHED (element) == sched) {
|
|
||||||
GST_CAT_DEBUG (GST_CAT_SCHEDULING, "element %s already in scheduler %p",
|
|
||||||
GST_ELEMENT_NAME (element), sched);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if it's not inside this scheduler, it has to be NULL */
|
|
||||||
g_assert (GST_ELEMENT_SCHED (element) == NULL);
|
|
||||||
|
|
||||||
if (gst_element_provides_clock (element)) {
|
|
||||||
sched->clock_providers = g_list_prepend (sched->clock_providers, element);
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "added clock provider %s",
|
|
||||||
GST_ELEMENT_NAME (element));
|
|
||||||
redistribute_clock = TRUE;
|
|
||||||
}
|
|
||||||
if (gst_element_requires_clock (element)) {
|
|
||||||
sched->clock_receivers = g_list_prepend (sched->clock_receivers, element);
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "added clock receiver %s",
|
|
||||||
GST_ELEMENT_NAME (element));
|
|
||||||
redistribute_clock = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
gst_element_set_scheduler (element, sched);
|
|
||||||
|
|
||||||
if (redistribute_clock) {
|
|
||||||
GstClock *clock;
|
|
||||||
|
|
||||||
clock = gst_scheduler_get_clock (sched);
|
|
||||||
gst_scheduler_set_clock (sched, clock);
|
|
||||||
}
|
|
||||||
|
|
||||||
sclass = GST_SCHEDULER_GET_CLASS (sched);
|
sclass = GST_SCHEDULER_GET_CLASS (sched);
|
||||||
|
|
||||||
if (sclass->add_element)
|
if (sclass->add_element)
|
||||||
|
@ -269,420 +157,31 @@ void
|
||||||
gst_scheduler_remove_element (GstScheduler * sched, GstElement * element)
|
gst_scheduler_remove_element (GstScheduler * sched, GstElement * element)
|
||||||
{
|
{
|
||||||
GstSchedulerClass *sclass;
|
GstSchedulerClass *sclass;
|
||||||
GList *link;
|
|
||||||
gboolean redistribute_clock = FALSE;
|
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_SCHEDULER (sched));
|
g_return_if_fail (GST_IS_SCHEDULER (sched));
|
||||||
g_return_if_fail (GST_IS_ELEMENT (element));
|
g_return_if_fail (GST_IS_ELEMENT (element));
|
||||||
|
|
||||||
link = g_list_find (sched->clock_providers, element);
|
|
||||||
if (link) {
|
|
||||||
sched->clock_providers = g_list_delete_link (sched->clock_providers, link);
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "removed clock provider %s",
|
|
||||||
GST_ELEMENT_NAME (element));
|
|
||||||
redistribute_clock = TRUE;
|
|
||||||
}
|
|
||||||
link = g_list_find (sched->clock_receivers, element);
|
|
||||||
if (link) {
|
|
||||||
sched->clock_receivers = g_list_delete_link (sched->clock_receivers, link);
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "removed clock receiver %s",
|
|
||||||
GST_ELEMENT_NAME (element));
|
|
||||||
redistribute_clock = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (redistribute_clock) {
|
|
||||||
GstClock *clock;
|
|
||||||
|
|
||||||
clock = gst_scheduler_get_clock (sched);
|
|
||||||
gst_scheduler_set_clock (sched, clock);
|
|
||||||
}
|
|
||||||
|
|
||||||
sclass = GST_SCHEDULER_GET_CLASS (sched);
|
sclass = GST_SCHEDULER_GET_CLASS (sched);
|
||||||
|
|
||||||
if (sclass->remove_element)
|
if (sclass->remove_element)
|
||||||
sclass->remove_element (sched, element);
|
sclass->remove_element (sched, element);
|
||||||
|
|
||||||
gst_element_set_scheduler (element, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
GstTask *
|
||||||
* gst_scheduler_state_transition:
|
gst_scheduler_create_task (GstScheduler * sched, GstTaskFunction func,
|
||||||
* @sched: the scheduler
|
gpointer data)
|
||||||
* @element: the element with the state transition
|
|
||||||
* @transition: the state transition
|
|
||||||
*
|
|
||||||
* Tell the scheduler that an element changed its state.
|
|
||||||
*
|
|
||||||
* Returns: a GstElementStateReturn indicating success or failure
|
|
||||||
* of the state transition.
|
|
||||||
*/
|
|
||||||
GstElementStateReturn
|
|
||||||
gst_scheduler_state_transition (GstScheduler * sched, GstElement * element,
|
|
||||||
gint transition)
|
|
||||||
{
|
{
|
||||||
GstSchedulerClass *sclass;
|
GstSchedulerClass *sclass;
|
||||||
|
GstTask *result = NULL;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_SCHEDULER (sched), GST_STATE_FAILURE);
|
g_return_val_if_fail (GST_IS_SCHEDULER (sched), result);
|
||||||
g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
|
|
||||||
|
|
||||||
if (element == sched->parent && sched->parent_sched == NULL) {
|
|
||||||
/* FIXME is distributing the clock in the state change still needed
|
|
||||||
* when we distribute as soon as we add/remove elements? I think not.*/
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_READY_TO_PAUSED:
|
|
||||||
{
|
|
||||||
GstClock *clock = gst_scheduler_get_clock (sched);
|
|
||||||
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK,
|
|
||||||
"scheduler READY to PAUSED clock is %p (%s)", clock,
|
|
||||||
(clock ? GST_OBJECT_NAME (clock) : "nil"));
|
|
||||||
|
|
||||||
gst_scheduler_set_clock (sched, clock);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sclass = GST_SCHEDULER_GET_CLASS (sched);
|
sclass = GST_SCHEDULER_GET_CLASS (sched);
|
||||||
|
|
||||||
if (sclass->state_transition)
|
if (sclass->create_task)
|
||||||
return sclass->state_transition (sched, element, transition);
|
result = sclass->create_task (sched, func, data);
|
||||||
|
|
||||||
return GST_STATE_SUCCESS;
|
return result;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_scheduler_scheduling_change:
|
|
||||||
* @sched: the scheduler
|
|
||||||
* @element: the element that changed its scheduling strategy
|
|
||||||
*
|
|
||||||
* Tell the scheduler that an element changed its scheduling strategy.
|
|
||||||
* An element could, for example, change its loop function or changes
|
|
||||||
* from a loop based element to a chain based element.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
gst_scheduler_scheduling_change (GstScheduler * sched, GstElement * element)
|
|
||||||
{
|
|
||||||
GstSchedulerClass *sclass;
|
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_SCHEDULER (sched));
|
|
||||||
g_return_if_fail (GST_IS_ELEMENT (element));
|
|
||||||
|
|
||||||
sclass = GST_SCHEDULER_GET_CLASS (sched);
|
|
||||||
|
|
||||||
if (sclass->scheduling_change)
|
|
||||||
sclass->scheduling_change (sched, element);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_scheduler_add_scheduler:
|
|
||||||
* @sched: a #GstScheduler to add to
|
|
||||||
* @sched2: the #GstScheduler to add
|
|
||||||
*
|
|
||||||
* Notifies the scheduler that it has to monitor this scheduler.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
gst_scheduler_add_scheduler (GstScheduler * sched, GstScheduler * sched2)
|
|
||||||
{
|
|
||||||
GstSchedulerClass *sclass;
|
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_SCHEDULER (sched));
|
|
||||||
g_return_if_fail (GST_IS_SCHEDULER (sched2));
|
|
||||||
g_return_if_fail (sched2->parent_sched == NULL);
|
|
||||||
|
|
||||||
GST_DEBUG ("gstscheduler: %p add scheduler %p", sched, sched2);
|
|
||||||
|
|
||||||
gst_object_ref (GST_OBJECT (sched2));
|
|
||||||
gst_object_ref (GST_OBJECT (sched));
|
|
||||||
|
|
||||||
sched->schedulers = g_list_prepend (sched->schedulers, sched2);
|
|
||||||
sched2->parent_sched = sched;
|
|
||||||
|
|
||||||
sclass = GST_SCHEDULER_GET_CLASS (sched);
|
|
||||||
|
|
||||||
if (sclass->add_scheduler)
|
|
||||||
sclass->add_scheduler (sched, sched2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_scheduler_remove_scheduler:
|
|
||||||
* @sched: the scheduler
|
|
||||||
* @sched2: the scheduler to remove
|
|
||||||
*
|
|
||||||
a Notifies the scheduler that it can stop monitoring this scheduler.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
gst_scheduler_remove_scheduler (GstScheduler * sched, GstScheduler * sched2)
|
|
||||||
{
|
|
||||||
GstSchedulerClass *sclass;
|
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_SCHEDULER (sched));
|
|
||||||
g_return_if_fail (GST_IS_SCHEDULER (sched2));
|
|
||||||
g_return_if_fail (sched2->parent_sched == sched);
|
|
||||||
|
|
||||||
GST_DEBUG ("gstscheduler: %p remove scheduler %p", sched, sched2);
|
|
||||||
|
|
||||||
sclass = GST_SCHEDULER_GET_CLASS (sched);
|
|
||||||
|
|
||||||
if (sclass->remove_scheduler)
|
|
||||||
sclass->remove_scheduler (sched, sched2);
|
|
||||||
|
|
||||||
sched->schedulers = g_list_remove (sched->schedulers, sched2);
|
|
||||||
sched2->parent_sched = NULL;
|
|
||||||
|
|
||||||
gst_object_unref (GST_OBJECT (sched2));
|
|
||||||
gst_object_unref (GST_OBJECT (sched));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_scheduler_lock_element:
|
|
||||||
* @sched: the scheduler
|
|
||||||
* @element: the element to lock
|
|
||||||
*
|
|
||||||
* Acquire a lock on the given element in the given scheduler.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
gst_scheduler_lock_element (GstScheduler * sched, GstElement * element)
|
|
||||||
{
|
|
||||||
g_return_if_fail (GST_IS_SCHEDULER (sched));
|
|
||||||
g_return_if_fail (GST_IS_ELEMENT (element));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_scheduler_unlock_element:
|
|
||||||
* @sched: the scheduler
|
|
||||||
* @element: the element to unlock
|
|
||||||
*
|
|
||||||
* Release the lock on the given element in the given scheduler.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
gst_scheduler_unlock_element (GstScheduler * sched, GstElement * element)
|
|
||||||
{
|
|
||||||
GstSchedulerClass *sclass;
|
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_SCHEDULER (sched));
|
|
||||||
g_return_if_fail (GST_IS_ELEMENT (element));
|
|
||||||
|
|
||||||
sclass = GST_SCHEDULER_GET_CLASS (sched);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_scheduler_error:
|
|
||||||
* @sched: the scheduler
|
|
||||||
* @element: the element with the error
|
|
||||||
*
|
|
||||||
* Tell the scheduler an element was in error
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
gst_scheduler_error (GstScheduler * sched, GstElement * element)
|
|
||||||
{
|
|
||||||
GstSchedulerClass *sclass;
|
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_SCHEDULER (sched));
|
|
||||||
g_return_if_fail (GST_IS_ELEMENT (element));
|
|
||||||
|
|
||||||
sclass = GST_SCHEDULER_GET_CLASS (sched);
|
|
||||||
|
|
||||||
if (sclass->error)
|
|
||||||
sclass->error (sched, element);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_scheduler_yield:
|
|
||||||
* @sched: the scheduler
|
|
||||||
* @element: the element requesting a yield
|
|
||||||
*
|
|
||||||
* Tell the scheduler to schedule another element.
|
|
||||||
*
|
|
||||||
* Returns: TRUE if the element should save its state, FALSE
|
|
||||||
* if the scheduler can perform this action itself.
|
|
||||||
*/
|
|
||||||
gboolean
|
|
||||||
gst_scheduler_yield (GstScheduler * sched, GstElement * element)
|
|
||||||
{
|
|
||||||
GstSchedulerClass *sclass;
|
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_SCHEDULER (sched), TRUE);
|
|
||||||
g_return_val_if_fail (GST_IS_ELEMENT (element), TRUE);
|
|
||||||
|
|
||||||
sclass = GST_SCHEDULER_GET_CLASS (sched);
|
|
||||||
|
|
||||||
if (sclass->yield)
|
|
||||||
return sclass->yield (sched, element);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_scheduler_interrupt:
|
|
||||||
* @sched: the scheduler
|
|
||||||
* @element: the element requesting an interrupt
|
|
||||||
*
|
|
||||||
* Tell the scheduler to interrupt execution of this element.
|
|
||||||
*
|
|
||||||
* Returns: TRUE if the element should return NULL from the chain/get
|
|
||||||
* function.
|
|
||||||
*/
|
|
||||||
gboolean
|
|
||||||
gst_scheduler_interrupt (GstScheduler * sched, GstElement * element)
|
|
||||||
{
|
|
||||||
GstSchedulerClass *sclass;
|
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_SCHEDULER (sched), FALSE);
|
|
||||||
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
|
|
||||||
|
|
||||||
sclass = GST_SCHEDULER_GET_CLASS (sched);
|
|
||||||
|
|
||||||
if (sclass->interrupt)
|
|
||||||
return sclass->interrupt (sched, element);
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_scheduler_get_clock:
|
|
||||||
* @sched: the scheduler
|
|
||||||
*
|
|
||||||
* Gets the current clock used by the scheduler.
|
|
||||||
*
|
|
||||||
* Returns: a GstClock
|
|
||||||
*/
|
|
||||||
GstClock *
|
|
||||||
gst_scheduler_get_clock (GstScheduler * sched)
|
|
||||||
{
|
|
||||||
GstClock *clock = NULL;
|
|
||||||
|
|
||||||
/* if we have a fixed clock, use that one */
|
|
||||||
if (GST_FLAG_IS_SET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK)) {
|
|
||||||
clock = sched->clock;
|
|
||||||
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "scheduler using fixed clock %p (%s)",
|
|
||||||
clock, clock ? GST_STR_NULL (GST_OBJECT_NAME (clock)) : "-");
|
|
||||||
} else {
|
|
||||||
GList *schedulers = sched->schedulers;
|
|
||||||
GList *providers = sched->clock_providers;
|
|
||||||
|
|
||||||
/* try to get a clock from one of the schedulers we manage first */
|
|
||||||
while (schedulers) {
|
|
||||||
GstScheduler *scheduler = GST_SCHEDULER (schedulers->data);
|
|
||||||
|
|
||||||
clock = gst_scheduler_get_clock (scheduler);
|
|
||||||
if (clock) {
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK,
|
|
||||||
"scheduler found managed sched clock %p (%s)",
|
|
||||||
clock, clock ? GST_STR_NULL (GST_OBJECT_NAME (clock)) : "-");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
schedulers = g_list_next (schedulers);
|
|
||||||
}
|
|
||||||
/* still no clock, try to find one in the providers */
|
|
||||||
while (!clock && providers) {
|
|
||||||
clock = gst_element_get_clock (GST_ELEMENT (providers->data));
|
|
||||||
if (clock)
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "scheduler found provider clock: %p (%s)",
|
|
||||||
clock, clock ? GST_STR_NULL (GST_OBJECT_NAME (clock)) : "-");
|
|
||||||
providers = g_list_next (providers);
|
|
||||||
}
|
|
||||||
/* still no clock, use a system clock */
|
|
||||||
if (!clock && sched->parent_sched == NULL) {
|
|
||||||
clock = gst_system_clock_obtain ();
|
|
||||||
/* we unref since this function is not supposed to increase refcount
|
|
||||||
* of clock object returned; this is ok since the systemclock always
|
|
||||||
* has a refcount of at least one in the current code. */
|
|
||||||
gst_object_unref (GST_OBJECT (clock));
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "scheduler obtained system clock: %p (%s)",
|
|
||||||
clock, clock ? GST_STR_NULL (GST_OBJECT_NAME (clock)) : "-");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return clock;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_scheduler_use_clock:
|
|
||||||
* @sched: the scheduler
|
|
||||||
* @clock: the clock to use
|
|
||||||
*
|
|
||||||
* Force the scheduler to use the given clock. The scheduler will
|
|
||||||
* always use the given clock even if new clock providers are added
|
|
||||||
* to this scheduler.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
gst_scheduler_use_clock (GstScheduler * sched, GstClock * clock)
|
|
||||||
{
|
|
||||||
g_return_if_fail (sched != NULL);
|
|
||||||
g_return_if_fail (GST_IS_SCHEDULER (sched));
|
|
||||||
|
|
||||||
GST_FLAG_SET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK);
|
|
||||||
|
|
||||||
gst_object_replace ((GstObject **) & sched->clock, (GstObject *) clock);
|
|
||||||
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "scheduler using fixed clock %p (%s)", clock,
|
|
||||||
(clock ? GST_OBJECT_NAME (clock) : "nil"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_scheduler_set_clock:
|
|
||||||
* @sched: the scheduler
|
|
||||||
* @clock: the clock to set
|
|
||||||
*
|
|
||||||
* Set the clock for the scheduler. The clock will be distributed
|
|
||||||
* to all the elements managed by the scheduler.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
gst_scheduler_set_clock (GstScheduler * sched, GstClock * clock)
|
|
||||||
{
|
|
||||||
GList *receivers;
|
|
||||||
GList *schedulers;
|
|
||||||
|
|
||||||
g_return_if_fail (sched != NULL);
|
|
||||||
g_return_if_fail (GST_IS_SCHEDULER (sched));
|
|
||||||
|
|
||||||
receivers = sched->clock_receivers;
|
|
||||||
schedulers = sched->schedulers;
|
|
||||||
|
|
||||||
gst_object_replace ((GstObject **) & sched->current_clock,
|
|
||||||
(GstObject *) clock);
|
|
||||||
|
|
||||||
while (receivers) {
|
|
||||||
GstElement *element = GST_ELEMENT (receivers->data);
|
|
||||||
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK,
|
|
||||||
"scheduler setting clock %p (%s) on element %s", clock,
|
|
||||||
(clock ? GST_OBJECT_NAME (clock) : "nil"), GST_ELEMENT_NAME (element));
|
|
||||||
|
|
||||||
gst_element_set_clock (element, clock);
|
|
||||||
receivers = g_list_next (receivers);
|
|
||||||
}
|
|
||||||
while (schedulers) {
|
|
||||||
GstScheduler *scheduler = GST_SCHEDULER (schedulers->data);
|
|
||||||
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK,
|
|
||||||
"scheduler setting clock %p (%s) on scheduler %p", clock,
|
|
||||||
(clock ? GST_OBJECT_NAME (clock) : "nil"), scheduler);
|
|
||||||
gst_scheduler_set_clock (scheduler, clock);
|
|
||||||
schedulers = g_list_next (schedulers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_scheduler_auto_clock:
|
|
||||||
* @sched: the scheduler
|
|
||||||
*
|
|
||||||
* Let the scheduler select a clock automatically.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
gst_scheduler_auto_clock (GstScheduler * sched)
|
|
||||||
{
|
|
||||||
g_return_if_fail (sched != NULL);
|
|
||||||
g_return_if_fail (GST_IS_SCHEDULER (sched));
|
|
||||||
|
|
||||||
GST_FLAG_UNSET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK);
|
|
||||||
|
|
||||||
gst_object_replace ((GstObject **) & sched->clock, NULL);
|
|
||||||
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "scheduler using automatic clock");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GstClockReturn gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter);
|
GstClockReturn gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter);
|
||||||
|
@ -716,32 +215,6 @@ gst_scheduler_clock_wait (GstScheduler * sched, GstElement * element,
|
||||||
return gst_clock_id_wait (id, jitter);
|
return gst_clock_id_wait (id, jitter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_scheduler_iterate:
|
|
||||||
* @sched: the scheduler
|
|
||||||
*
|
|
||||||
* Perform one iteration on the scheduler.
|
|
||||||
*
|
|
||||||
* Returns: a boolean indicating something usefull has happened.
|
|
||||||
*/
|
|
||||||
gboolean
|
|
||||||
gst_scheduler_iterate (GstScheduler * sched)
|
|
||||||
{
|
|
||||||
GstSchedulerClass *sclass;
|
|
||||||
gboolean res = FALSE;
|
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_SCHEDULER (sched), FALSE);
|
|
||||||
|
|
||||||
sclass = GST_SCHEDULER_GET_CLASS (sched);
|
|
||||||
|
|
||||||
if (sclass->iterate) {
|
|
||||||
res = sclass->iterate (sched);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_scheduler_show:
|
* gst_scheduler_show:
|
||||||
* @sched: the scheduler
|
* @sched: the scheduler
|
||||||
|
@ -964,8 +437,6 @@ gst_scheduler_factory_create (GstSchedulerFactory * factory,
|
||||||
sched = GST_SCHEDULER (g_object_new (factory->type, NULL));
|
sched = GST_SCHEDULER (g_object_new (factory->type, NULL));
|
||||||
sched->parent = parent;
|
sched->parent = parent;
|
||||||
|
|
||||||
GST_ELEMENT_SCHED (parent) = sched;
|
|
||||||
|
|
||||||
/* let's refcount the scheduler */
|
/* let's refcount the scheduler */
|
||||||
gst_object_ref (GST_OBJECT (sched));
|
gst_object_ref (GST_OBJECT (sched));
|
||||||
gst_object_sink (GST_OBJECT (sched));
|
gst_object_sink (GST_OBJECT (sched));
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <gst/gstelement.h>
|
#include <gst/gstelement.h>
|
||||||
#include <gst/gstbin.h>
|
#include <gst/gstbin.h>
|
||||||
|
#include <gst/gsttask.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
@ -38,11 +39,6 @@ G_BEGIN_DECLS
|
||||||
#define GST_SCHEDULER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_SCHEDULER, GstSchedulerClass))
|
#define GST_SCHEDULER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_SCHEDULER, GstSchedulerClass))
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/* this scheduler works with a fixed clock */
|
|
||||||
GST_SCHEDULER_FLAG_FIXED_CLOCK = GST_OBJECT_FLAG_LAST,
|
|
||||||
/* this scheduler supports select and lock calls */
|
|
||||||
GST_SCHEDULER_FLAG_NEW_API,
|
|
||||||
|
|
||||||
/* padding */
|
/* padding */
|
||||||
GST_SCHEDULER_FLAG_LAST = GST_OBJECT_FLAG_LAST + 4
|
GST_SCHEDULER_FLAG_LAST = GST_OBJECT_FLAG_LAST + 4
|
||||||
} GstSchedulerFlags;
|
} GstSchedulerFlags;
|
||||||
|
@ -52,27 +48,11 @@ typedef enum {
|
||||||
|
|
||||||
/*typedef struct _GstScheduler GstScheduler; */
|
/*typedef struct _GstScheduler GstScheduler; */
|
||||||
/*typedef struct _GstSchedulerClass GstSchedulerClass; */
|
/*typedef struct _GstSchedulerClass GstSchedulerClass; */
|
||||||
typedef enum {
|
|
||||||
GST_SCHEDULER_STATE_NONE,
|
|
||||||
GST_SCHEDULER_STATE_RUNNING,
|
|
||||||
GST_SCHEDULER_STATE_STOPPED,
|
|
||||||
GST_SCHEDULER_STATE_ERROR
|
|
||||||
} GstSchedulerState;
|
|
||||||
|
|
||||||
struct _GstScheduler {
|
struct _GstScheduler {
|
||||||
GstObject object;
|
GstObject object;
|
||||||
|
|
||||||
GstElement *parent;
|
GstElement *parent;
|
||||||
GstScheduler *parent_sched;
|
|
||||||
|
|
||||||
GstSchedulerState state;
|
|
||||||
GstClock *clock;
|
|
||||||
GstClock *current_clock;
|
|
||||||
|
|
||||||
GList *clock_providers;
|
|
||||||
GList *clock_receivers;
|
|
||||||
|
|
||||||
GList *schedulers;
|
|
||||||
|
|
||||||
gpointer _gst_reserved[GST_PADDING];
|
gpointer _gst_reserved[GST_PADDING];
|
||||||
};
|
};
|
||||||
|
@ -83,26 +63,13 @@ struct _GstSchedulerClass {
|
||||||
/* virtual methods */
|
/* virtual methods */
|
||||||
void (*setup) (GstScheduler *sched);
|
void (*setup) (GstScheduler *sched);
|
||||||
void (*reset) (GstScheduler *sched);
|
void (*reset) (GstScheduler *sched);
|
||||||
void (*add_element) (GstScheduler *sched, GstElement *element);
|
void (*add_element) (GstScheduler *sched, GstElement * element);
|
||||||
void (*remove_element) (GstScheduler *sched, GstElement *element);
|
void (*remove_element) (GstScheduler *sched, GstElement * element);
|
||||||
void (*add_scheduler) (GstScheduler *sched, GstScheduler *sched2);
|
|
||||||
void (*remove_scheduler) (GstScheduler *sched, GstScheduler *sched2);
|
GstTask* (*create_task) (GstScheduler *sched, GstTaskFunction func, gpointer data);
|
||||||
GstElementStateReturn (*state_transition) (GstScheduler *sched, GstElement *element, gint transition);
|
|
||||||
void (*scheduling_change) (GstScheduler *sched, GstElement *element);
|
|
||||||
/* next two are optional, require NEW_API flag */
|
|
||||||
/* FIXME 0.9: rename to (un)lock_object */
|
|
||||||
void (*lock_element) (GstScheduler *sched, GstObject *object);
|
|
||||||
void (*unlock_element) (GstScheduler *sched, GstObject *object);
|
|
||||||
gboolean (*yield) (GstScheduler *sched, GstElement *element);
|
|
||||||
gboolean (*interrupt) (GstScheduler *sched, GstElement *element);
|
|
||||||
void (*error) (GstScheduler *sched, GstElement *element);
|
|
||||||
void (*pad_link) (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad);
|
|
||||||
void (*pad_unlink) (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad);
|
|
||||||
/* optional, requires NEW_API flag */
|
|
||||||
GstData * (*pad_select) (GstScheduler *sched, GstPad **selected, GstPad **pads);
|
|
||||||
GstClockReturn (*clock_wait) (GstScheduler *sched, GstElement *element,
|
GstClockReturn (*clock_wait) (GstScheduler *sched, GstElement *element,
|
||||||
GstClockID id, GstClockTimeDiff *jitter);
|
GstClockID id, GstClockTimeDiff *jitter);
|
||||||
GstSchedulerState (*iterate) (GstScheduler *sched);
|
|
||||||
/* for debugging */
|
/* for debugging */
|
||||||
void (*show) (GstScheduler *sched);
|
void (*show) (GstScheduler *sched);
|
||||||
|
|
||||||
|
@ -118,32 +85,11 @@ GType gst_scheduler_get_type (void);
|
||||||
|
|
||||||
void gst_scheduler_setup (GstScheduler *sched);
|
void gst_scheduler_setup (GstScheduler *sched);
|
||||||
void gst_scheduler_reset (GstScheduler *sched);
|
void gst_scheduler_reset (GstScheduler *sched);
|
||||||
void gst_scheduler_add_element (GstScheduler *sched, GstElement *element);
|
GstTask* gst_scheduler_create_task (GstScheduler *sched, GstTaskFunction func, gpointer data);
|
||||||
void gst_scheduler_remove_element (GstScheduler *sched, GstElement *element);
|
|
||||||
void gst_scheduler_add_scheduler (GstScheduler *sched, GstScheduler *sched2);
|
|
||||||
void gst_scheduler_remove_scheduler (GstScheduler *sched, GstScheduler *sched2);
|
|
||||||
GstElementStateReturn gst_scheduler_state_transition (GstScheduler *sched, GstElement *element, gint transition);
|
|
||||||
void gst_scheduler_scheduling_change (GstScheduler *sched, GstElement *element);
|
|
||||||
#ifndef GST_DISABLE_DEPRECATED
|
|
||||||
void gst_scheduler_lock_element (GstScheduler *sched, GstElement *element);
|
|
||||||
void gst_scheduler_unlock_element (GstScheduler *sched, GstElement *element);
|
|
||||||
#endif
|
|
||||||
gboolean gst_scheduler_yield (GstScheduler *sched, GstElement *element);
|
|
||||||
gboolean gst_scheduler_interrupt (GstScheduler *sched, GstElement *element);
|
|
||||||
void gst_scheduler_error (GstScheduler *sched, GstElement *element);
|
|
||||||
void gst_scheduler_pad_link (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad);
|
|
||||||
void gst_scheduler_pad_unlink (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad);
|
|
||||||
#ifndef GST_DISABLE_DEPRECATED
|
|
||||||
GstPad* gst_scheduler_pad_select (GstScheduler *sched, GList *padlist);
|
|
||||||
#endif
|
|
||||||
GstClockReturn gst_scheduler_clock_wait (GstScheduler *sched, GstElement *element,
|
GstClockReturn gst_scheduler_clock_wait (GstScheduler *sched, GstElement *element,
|
||||||
GstClockID id, GstClockTimeDiff *jitter);
|
GstClockID id, GstClockTimeDiff *jitter);
|
||||||
gboolean gst_scheduler_iterate (GstScheduler *sched);
|
|
||||||
|
|
||||||
void gst_scheduler_use_clock (GstScheduler *sched, GstClock *clock);
|
|
||||||
void gst_scheduler_set_clock (GstScheduler *sched, GstClock *clock);
|
|
||||||
GstClock* gst_scheduler_get_clock (GstScheduler *sched);
|
|
||||||
void gst_scheduler_auto_clock (GstScheduler *sched);
|
|
||||||
|
|
||||||
void gst_scheduler_show (GstScheduler *sched);
|
void gst_scheduler_show (GstScheduler *sched);
|
||||||
|
|
||||||
|
@ -159,7 +105,7 @@ void gst_scheduler_show (GstScheduler *sched);
|
||||||
#define GST_SCHEDULER_FACTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_SCHEDULER_FACTORY, GstSchedulerFactoryClass))
|
#define GST_SCHEDULER_FACTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_SCHEDULER_FACTORY, GstSchedulerFactoryClass))
|
||||||
|
|
||||||
/* change this to change the default scheduler */
|
/* change this to change the default scheduler */
|
||||||
#define GST_SCHEDULER_DEFAULT_NAME "opt"
|
#define GST_SCHEDULER_DEFAULT_NAME "thread"
|
||||||
|
|
||||||
typedef struct _GstSchedulerFactory GstSchedulerFactory;
|
typedef struct _GstSchedulerFactory GstSchedulerFactory;
|
||||||
typedef struct _GstSchedulerFactoryClass GstSchedulerFactoryClass;
|
typedef struct _GstSchedulerFactoryClass GstSchedulerFactoryClass;
|
||||||
|
|
|
@ -191,12 +191,6 @@ gst_system_clock_wait (GstClock * clock, GstClockEntry * entry)
|
||||||
current = gst_clock_get_time (clock);
|
current = gst_clock_get_time (clock);
|
||||||
diff = GST_CLOCK_ENTRY_TIME (entry) - current;
|
diff = GST_CLOCK_ENTRY_TIME (entry) - current;
|
||||||
|
|
||||||
if (diff + clock->max_diff < 0) {
|
|
||||||
GST_WARNING_OBJECT (clock, "clock is way behind: %" G_GINT64_FORMAT
|
|
||||||
"s (max allowed is %" G_GINT64_FORMAT "s", -diff, clock->max_diff);
|
|
||||||
return GST_CLOCK_ENTRY_EARLY;
|
|
||||||
}
|
|
||||||
|
|
||||||
target = gst_system_clock_get_internal_time (clock) + diff;
|
target = gst_system_clock_get_internal_time (clock) + diff;
|
||||||
|
|
||||||
GST_CAT_DEBUG (GST_CAT_CLOCK, "real_target %" G_GUINT64_FORMAT
|
GST_CAT_DEBUG (GST_CAT_CLOCK, "real_target %" G_GUINT64_FORMAT
|
||||||
|
|
|
@ -94,7 +94,7 @@ gst_type_find_factory_dispose (GObject * object)
|
||||||
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (object);
|
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (object);
|
||||||
|
|
||||||
if (factory->caps) {
|
if (factory->caps) {
|
||||||
gst_caps_free (factory->caps);
|
gst_caps_unref (factory->caps);
|
||||||
factory->caps = NULL;
|
factory->caps = NULL;
|
||||||
}
|
}
|
||||||
if (factory->extensions) {
|
if (factory->extensions) {
|
||||||
|
|
|
@ -34,9 +34,12 @@ typedef struct _GstElement GstElement;
|
||||||
typedef struct _GstElementClass GstElementClass;
|
typedef struct _GstElementClass GstElementClass;
|
||||||
typedef struct _GstBin GstBin;
|
typedef struct _GstBin GstBin;
|
||||||
typedef struct _GstBinClass GstBinClass;
|
typedef struct _GstBinClass GstBinClass;
|
||||||
|
typedef struct _GstPipeline GstPipeline;
|
||||||
|
typedef struct _GstPipelineClass GstPipelineClass;
|
||||||
typedef struct _GstScheduler GstScheduler;
|
typedef struct _GstScheduler GstScheduler;
|
||||||
typedef struct _GstSchedulerClass GstSchedulerClass;
|
typedef struct _GstSchedulerClass GstSchedulerClass;
|
||||||
typedef struct _GstEvent GstEvent;
|
typedef struct _GstEvent GstEvent;
|
||||||
|
typedef struct _GstMessage GstMessage;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GST_STATE_VOID_PENDING = 0,
|
GST_STATE_VOID_PENDING = 0,
|
||||||
|
|
933
gst/gstutils.c
933
gst/gstutils.c
|
@ -27,6 +27,8 @@
|
||||||
#include "gstutils.h"
|
#include "gstutils.h"
|
||||||
#include "gsturitype.h"
|
#include "gsturitype.h"
|
||||||
#include "gstinfo.h"
|
#include "gstinfo.h"
|
||||||
|
#include "gst-i18n-lib.h"
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_util_dump_mem:
|
* gst_util_dump_mem:
|
||||||
|
@ -367,3 +369,934 @@ gst_print_element_args (GString * buf, gint indent, GstElement * element)
|
||||||
|
|
||||||
g_free (specs);
|
g_free (specs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GstFlowReturn
|
||||||
|
gst_element_abort_preroll (GstElement * element)
|
||||||
|
{
|
||||||
|
GstFlowReturn result = GST_FLOW_OK;
|
||||||
|
|
||||||
|
/* grab state change lock */
|
||||||
|
GST_STATE_LOCK (element);
|
||||||
|
/* if we are going to PAUSED, we can abort the state change */
|
||||||
|
if (GST_STATE_TRANSITION (element) == GST_STATE_READY_TO_PAUSED) {
|
||||||
|
gst_element_abort_state (GST_ELEMENT (element));
|
||||||
|
}
|
||||||
|
GST_STATE_UNLOCK (element);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* call with stream lock held */
|
||||||
|
GstFlowReturn
|
||||||
|
gst_element_finish_preroll (GstElement * element, GMutex * streamlock)
|
||||||
|
{
|
||||||
|
GstFlowReturn result = GST_FLOW_OK;
|
||||||
|
|
||||||
|
/* grab state change lock */
|
||||||
|
GST_STATE_LOCK (element);
|
||||||
|
/* if we are going to PAUSED, we can commit the state change */
|
||||||
|
if (GST_STATE_TRANSITION (element) == GST_STATE_READY_TO_PAUSED) {
|
||||||
|
gst_element_commit_state (GST_ELEMENT (element));
|
||||||
|
}
|
||||||
|
/* if we are paused we need to wait for playing to continue */
|
||||||
|
if (GST_STATE (element) == GST_STATE_PAUSED) {
|
||||||
|
GST_CAT_DEBUG (GST_CAT_STATES,
|
||||||
|
"element %s wants to finish preroll", GST_ELEMENT_NAME (element));
|
||||||
|
|
||||||
|
|
||||||
|
/* FIXME, release streaming lock? */
|
||||||
|
if (streamlock)
|
||||||
|
g_mutex_unlock (streamlock);
|
||||||
|
|
||||||
|
/* here we wait for the next state change */
|
||||||
|
do {
|
||||||
|
GST_CAT_DEBUG (GST_CAT_STATES, "waiting for next state change");
|
||||||
|
|
||||||
|
GST_STATE_WAIT (element);
|
||||||
|
}
|
||||||
|
while (GST_STATE (element) == GST_STATE_PAUSED);
|
||||||
|
|
||||||
|
if (streamlock)
|
||||||
|
g_mutex_lock (streamlock);
|
||||||
|
/* check if we got playing */
|
||||||
|
if (GST_STATE (element) != GST_STATE_PLAYING) {
|
||||||
|
/* not playing, we can't accept the buffer */
|
||||||
|
result = GST_FLOW_WRONG_STATE;
|
||||||
|
}
|
||||||
|
GST_CAT_DEBUG (GST_CAT_STATES, "done preroll");
|
||||||
|
}
|
||||||
|
GST_STATE_UNLOCK (element);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_element_get_compatible_pad_template:
|
||||||
|
* @element: a #GstElement to get a compatible pad template for.
|
||||||
|
* @compattempl: the #GstPadTemplate to find a compatible template for.
|
||||||
|
*
|
||||||
|
* Retrieves a pad template from @element that is compatible with @compattempl.
|
||||||
|
* Pads from compatible templates can be linked together.
|
||||||
|
*
|
||||||
|
* Returns: a compatible #GstPadTemplate, or NULL if none was found. No
|
||||||
|
* unreferencing is necessary.
|
||||||
|
*/
|
||||||
|
GstPadTemplate *
|
||||||
|
gst_element_get_compatible_pad_template (GstElement * element,
|
||||||
|
GstPadTemplate * compattempl)
|
||||||
|
{
|
||||||
|
GstPadTemplate *newtempl = NULL;
|
||||||
|
GList *padlist;
|
||||||
|
GstElementClass *class;
|
||||||
|
|
||||||
|
g_return_val_if_fail (element != NULL, NULL);
|
||||||
|
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
||||||
|
g_return_val_if_fail (compattempl != NULL, NULL);
|
||||||
|
|
||||||
|
class = GST_ELEMENT_GET_CLASS (element);
|
||||||
|
|
||||||
|
padlist = gst_element_class_get_pad_template_list (class);
|
||||||
|
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
||||||
|
"Looking for a suitable pad template in %s out of %d templates...",
|
||||||
|
GST_ELEMENT_NAME (element), g_list_length (padlist));
|
||||||
|
|
||||||
|
while (padlist) {
|
||||||
|
GstPadTemplate *padtempl = (GstPadTemplate *) padlist->data;
|
||||||
|
GstCaps *intersection;
|
||||||
|
|
||||||
|
/* Ignore name
|
||||||
|
* Ignore presence
|
||||||
|
* Check direction (must be opposite)
|
||||||
|
* Check caps
|
||||||
|
*/
|
||||||
|
GST_CAT_LOG (GST_CAT_CAPS,
|
||||||
|
"checking pad template %s", padtempl->name_template);
|
||||||
|
if (padtempl->direction != compattempl->direction) {
|
||||||
|
GST_CAT_DEBUG (GST_CAT_CAPS,
|
||||||
|
"compatible direction: found %s pad template \"%s\"",
|
||||||
|
padtempl->direction == GST_PAD_SRC ? "src" : "sink",
|
||||||
|
padtempl->name_template);
|
||||||
|
|
||||||
|
intersection = gst_caps_intersect (GST_PAD_TEMPLATE_CAPS (compattempl),
|
||||||
|
GST_PAD_TEMPLATE_CAPS (padtempl));
|
||||||
|
|
||||||
|
GST_CAT_DEBUG (GST_CAT_CAPS, "caps are %scompatible",
|
||||||
|
(intersection ? "" : "not "));
|
||||||
|
|
||||||
|
if (!gst_caps_is_empty (intersection))
|
||||||
|
newtempl = padtempl;
|
||||||
|
gst_caps_unref (intersection);
|
||||||
|
if (newtempl)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
padlist = g_list_next (padlist);
|
||||||
|
}
|
||||||
|
if (newtempl)
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
||||||
|
"Returning new pad template %p", newtempl);
|
||||||
|
else
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "No compatible pad template found");
|
||||||
|
|
||||||
|
return newtempl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstPad *
|
||||||
|
gst_element_request_pad (GstElement * element, GstPadTemplate * templ,
|
||||||
|
const gchar * name)
|
||||||
|
{
|
||||||
|
GstPad *newpad = NULL;
|
||||||
|
GstElementClass *oclass;
|
||||||
|
|
||||||
|
oclass = GST_ELEMENT_GET_CLASS (element);
|
||||||
|
|
||||||
|
if (oclass->request_new_pad)
|
||||||
|
newpad = (oclass->request_new_pad) (element, templ, name);
|
||||||
|
|
||||||
|
return newpad;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_element_get_pad_from_template:
|
||||||
|
* @element: a #GstElement.
|
||||||
|
* @templ: a #GstPadTemplate belonging to @element.
|
||||||
|
*
|
||||||
|
* Gets a pad from @element described by @templ. If the presence of @templ is
|
||||||
|
* #GST_PAD_REQUEST, requests a new pad. Can return %NULL for #GST_PAD_SOMETIMES
|
||||||
|
* templates.
|
||||||
|
*
|
||||||
|
* Returns: the #GstPad, or NULL if one could not be found or created.
|
||||||
|
*/
|
||||||
|
static GstPad *
|
||||||
|
gst_element_get_pad_from_template (GstElement * element, GstPadTemplate * templ)
|
||||||
|
{
|
||||||
|
GstPad *ret = NULL;
|
||||||
|
GstPadPresence presence;
|
||||||
|
|
||||||
|
/* If this function is ever exported, we need check the validity of `element'
|
||||||
|
* and `templ', and to make sure the template actually belongs to the
|
||||||
|
* element. */
|
||||||
|
|
||||||
|
presence = GST_PAD_TEMPLATE_PRESENCE (templ);
|
||||||
|
|
||||||
|
switch (presence) {
|
||||||
|
case GST_PAD_ALWAYS:
|
||||||
|
case GST_PAD_SOMETIMES:
|
||||||
|
ret = gst_element_get_static_pad (element, templ->name_template);
|
||||||
|
if (!ret && presence == GST_PAD_ALWAYS)
|
||||||
|
g_warning
|
||||||
|
("Element %s has an ALWAYS template %s, but no pad of the same name",
|
||||||
|
GST_OBJECT_NAME (element), templ->name_template);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GST_PAD_REQUEST:
|
||||||
|
ret = gst_element_request_pad (element, templ, NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_element_request_compatible_pad:
|
||||||
|
* @element: a #GstElement.
|
||||||
|
* @templ: the #GstPadTemplate to which the new pad should be able to link.
|
||||||
|
*
|
||||||
|
* Requests a pad from @element. The returned pad should be unlinked and
|
||||||
|
* compatible with @templ. Might return an existing pad, or request a new one.
|
||||||
|
*
|
||||||
|
* Returns: a #GstPad, or %NULL if one could not be found or created.
|
||||||
|
*/
|
||||||
|
GstPad *
|
||||||
|
gst_element_request_compatible_pad (GstElement * element,
|
||||||
|
GstPadTemplate * templ)
|
||||||
|
{
|
||||||
|
GstPadTemplate *templ_new;
|
||||||
|
GstPad *pad = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
||||||
|
g_return_val_if_fail (GST_IS_PAD_TEMPLATE (templ), NULL);
|
||||||
|
|
||||||
|
/* FIXME: should really loop through the templates, testing each for
|
||||||
|
* compatibility and pad availability. */
|
||||||
|
templ_new = gst_element_get_compatible_pad_template (element, templ);
|
||||||
|
if (templ_new)
|
||||||
|
pad = gst_element_get_pad_from_template (element, templ_new);
|
||||||
|
|
||||||
|
/* This can happen for non-request pads. No need to unref. */
|
||||||
|
if (pad && GST_PAD_PEER (pad))
|
||||||
|
pad = NULL;
|
||||||
|
|
||||||
|
return pad;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_element_get_compatible_pad_filtered:
|
||||||
|
* @element: a #GstElement in which the pad should be found.
|
||||||
|
* @pad: the #GstPad to find a compatible one for.
|
||||||
|
* @filtercaps: the #GstCaps to use as a filter.
|
||||||
|
*
|
||||||
|
* Looks for an unlinked pad to which the given pad can link. It is not
|
||||||
|
* guaranteed that linking the pads will work, though it should work in most
|
||||||
|
* cases.
|
||||||
|
*
|
||||||
|
* Returns: the #GstPad to which a link can be made, or %NULL if one cannot be
|
||||||
|
* found.
|
||||||
|
*/
|
||||||
|
GstPad *
|
||||||
|
gst_element_get_compatible_pad_filtered (GstElement * element, GstPad * pad,
|
||||||
|
const GstCaps * filtercaps)
|
||||||
|
{
|
||||||
|
const GList *pads;
|
||||||
|
GstPadTemplate *templ;
|
||||||
|
GstCaps *templcaps;
|
||||||
|
GstPad *foundpad = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
||||||
|
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
|
||||||
|
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
||||||
|
"finding pad in %s compatible with %s:%s and filter %" GST_PTR_FORMAT,
|
||||||
|
GST_ELEMENT_NAME (element), GST_DEBUG_PAD_NAME (pad), filtercaps);
|
||||||
|
|
||||||
|
/* let's use the real pad */
|
||||||
|
pad = (GstPad *) GST_PAD_REALIZE (pad);
|
||||||
|
g_return_val_if_fail (pad != NULL, NULL);
|
||||||
|
g_return_val_if_fail (GST_RPAD_PEER (pad) == NULL, NULL);
|
||||||
|
|
||||||
|
/* try to get an existing unlinked pad */
|
||||||
|
pads = gst_element_get_pad_list (element);
|
||||||
|
while (pads) {
|
||||||
|
GstPad *current = GST_PAD (pads->data);
|
||||||
|
|
||||||
|
GST_CAT_LOG (GST_CAT_ELEMENT_PADS, "examing pad %s:%s",
|
||||||
|
GST_DEBUG_PAD_NAME (current));
|
||||||
|
if (GST_PAD_PEER (current) == NULL &&
|
||||||
|
gst_pad_can_link_filtered (pad, current, filtercaps)) {
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
||||||
|
"found existing unlinked pad %s:%s", GST_DEBUG_PAD_NAME (current));
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
pads = g_list_next (pads);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try to create a new one */
|
||||||
|
/* requesting is a little crazy, we need a template. Let's create one */
|
||||||
|
templcaps = GST_PAD_CAPS (pad);
|
||||||
|
if (filtercaps != NULL) {
|
||||||
|
GstCaps *temp;
|
||||||
|
|
||||||
|
temp = gst_caps_intersect (filtercaps, templcaps);
|
||||||
|
gst_caps_unref (templcaps);
|
||||||
|
templcaps = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
templ = gst_pad_template_new ((gchar *) GST_PAD_NAME (pad),
|
||||||
|
GST_PAD_DIRECTION (pad), GST_PAD_ALWAYS, templcaps);
|
||||||
|
foundpad = gst_element_request_compatible_pad (element, templ);
|
||||||
|
gst_object_unref (GST_OBJECT (templ));
|
||||||
|
|
||||||
|
if (foundpad) {
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
||||||
|
"found existing request pad %s:%s", GST_DEBUG_PAD_NAME (foundpad));
|
||||||
|
return foundpad;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_CAT_INFO_OBJECT (GST_CAT_ELEMENT_PADS, element,
|
||||||
|
"Could not find a compatible pad to link to %s:%s",
|
||||||
|
GST_DEBUG_PAD_NAME (pad));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_element_get_compatible_pad:
|
||||||
|
* @element: a #GstElement in which the pad should be found.
|
||||||
|
* @pad: the #GstPad to find a compatible one for.
|
||||||
|
*
|
||||||
|
* Looks for an unlinked pad to which the given pad can link to.
|
||||||
|
* It is not guaranteed that linking the pads will work, though
|
||||||
|
* it should work in most cases.
|
||||||
|
*
|
||||||
|
* Returns: the #GstPad to which a link can be made, or %NULL if one
|
||||||
|
* could not be found.
|
||||||
|
*/
|
||||||
|
GstPad *
|
||||||
|
gst_element_get_compatible_pad (GstElement * element, GstPad * pad)
|
||||||
|
{
|
||||||
|
return gst_element_get_compatible_pad_filtered (element, pad, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_element_state_get_name:
|
||||||
|
* @state: a #GstElementState to get the name of.
|
||||||
|
*
|
||||||
|
* Gets a string representing the given state.
|
||||||
|
*
|
||||||
|
* Returns: a string with the name of the state.
|
||||||
|
*/
|
||||||
|
const gchar *
|
||||||
|
gst_element_state_get_name (GstElementState state)
|
||||||
|
{
|
||||||
|
switch (state) {
|
||||||
|
#ifdef GST_DEBUG_COLOR
|
||||||
|
case GST_STATE_VOID_PENDING:
|
||||||
|
return "NONE_PENDING";
|
||||||
|
break;
|
||||||
|
case GST_STATE_NULL:
|
||||||
|
return "\033[01;34mNULL\033[00m";
|
||||||
|
break;
|
||||||
|
case GST_STATE_READY:
|
||||||
|
return "\033[01;31mREADY\033[00m";
|
||||||
|
break;
|
||||||
|
case GST_STATE_PLAYING:
|
||||||
|
return "\033[01;32mPLAYING\033[00m";
|
||||||
|
break;
|
||||||
|
case GST_STATE_PAUSED:
|
||||||
|
return "\033[01;33mPAUSED\033[00m";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* This is a memory leak */
|
||||||
|
return g_strdup_printf ("\033[01;35;41mUNKNOWN!\033[00m(%d)", state);
|
||||||
|
#else
|
||||||
|
case GST_STATE_VOID_PENDING:
|
||||||
|
return "NONE_PENDING";
|
||||||
|
break;
|
||||||
|
case GST_STATE_NULL:
|
||||||
|
return "NULL";
|
||||||
|
break;
|
||||||
|
case GST_STATE_READY:
|
||||||
|
return "READY";
|
||||||
|
break;
|
||||||
|
case GST_STATE_PLAYING:
|
||||||
|
return "PLAYING";
|
||||||
|
break;
|
||||||
|
case GST_STATE_PAUSED:
|
||||||
|
return "PAUSED";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return "UNKNOWN!";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_element_link_pads_filtered:
|
||||||
|
* @src: a #GstElement containing the source pad.
|
||||||
|
* @srcpadname: the name of the #GstPad in source element or NULL for any pad.
|
||||||
|
* @dest: the #GstElement containing the destination pad.
|
||||||
|
* @destpadname: the name of the #GstPad in destination element or NULL for any pad.
|
||||||
|
* @filtercaps: the #GstCaps to use as a filter.
|
||||||
|
*
|
||||||
|
* Links the two named pads of the source and destination elements.
|
||||||
|
* Side effect is that if one of the pads has no parent, it becomes a
|
||||||
|
* child of the parent of the other element. If they have different
|
||||||
|
* parents, the link fails.
|
||||||
|
*
|
||||||
|
* Returns: TRUE if the pads could be linked, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
GstPadLinkReturn
|
||||||
|
gst_element_link_pads_filtered (GstElement * src, const gchar * srcpadname,
|
||||||
|
GstElement * dest, const gchar * destpadname, const GstCaps * filtercaps)
|
||||||
|
{
|
||||||
|
const GList *srcpads, *destpads, *srctempls, *desttempls, *l;
|
||||||
|
GstPad *srcpad, *destpad;
|
||||||
|
GstPadTemplate *srctempl, *desttempl;
|
||||||
|
GstElementClass *srcclass, *destclass;
|
||||||
|
|
||||||
|
/* checks */
|
||||||
|
g_return_val_if_fail (GST_IS_ELEMENT (src), FALSE);
|
||||||
|
g_return_val_if_fail (GST_IS_ELEMENT (dest), FALSE);
|
||||||
|
|
||||||
|
srcclass = GST_ELEMENT_GET_CLASS (src);
|
||||||
|
destclass = GST_ELEMENT_GET_CLASS (dest);
|
||||||
|
|
||||||
|
GST_CAT_INFO (GST_CAT_ELEMENT_PADS,
|
||||||
|
"trying to link element %s:%s to element %s:%s", GST_ELEMENT_NAME (src),
|
||||||
|
srcpadname ? srcpadname : "(any)", GST_ELEMENT_NAME (dest),
|
||||||
|
destpadname ? destpadname : "(any)");
|
||||||
|
|
||||||
|
/* now get the pads we're trying to link and a list of all remaining pads */
|
||||||
|
if (srcpadname) {
|
||||||
|
srcpad = gst_element_get_pad (src, srcpadname);
|
||||||
|
if (!srcpad) {
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s",
|
||||||
|
GST_ELEMENT_NAME (src), srcpadname);
|
||||||
|
return FALSE;
|
||||||
|
} else {
|
||||||
|
if (!(GST_PAD_DIRECTION (srcpad) == GST_PAD_SRC)) {
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no src pad",
|
||||||
|
GST_DEBUG_PAD_NAME (srcpad));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (GST_PAD_PEER (srcpad) != NULL) {
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is already linked",
|
||||||
|
GST_DEBUG_PAD_NAME (srcpad));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
srcpads = NULL;
|
||||||
|
} else {
|
||||||
|
srcpads = gst_element_get_pad_list (src);
|
||||||
|
srcpad = srcpads ? (GstPad *) GST_PAD_REALIZE (srcpads->data) : NULL;
|
||||||
|
}
|
||||||
|
if (destpadname) {
|
||||||
|
destpad = gst_element_get_pad (dest, destpadname);
|
||||||
|
if (!destpad) {
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s",
|
||||||
|
GST_ELEMENT_NAME (dest), destpadname);
|
||||||
|
return FALSE;
|
||||||
|
} else {
|
||||||
|
if (!(GST_PAD_DIRECTION (destpad) == GST_PAD_SINK)) {
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no sink pad",
|
||||||
|
GST_DEBUG_PAD_NAME (destpad));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (GST_PAD_PEER (destpad) != NULL) {
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is already linked",
|
||||||
|
GST_DEBUG_PAD_NAME (destpad));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
destpads = NULL;
|
||||||
|
} else {
|
||||||
|
destpads = gst_element_get_pad_list (dest);
|
||||||
|
destpad = destpads ? (GstPad *) GST_PAD_REALIZE (destpads->data) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (srcpadname && destpadname) {
|
||||||
|
/* two explicitly specified pads */
|
||||||
|
return gst_pad_link_filtered (srcpad, destpad, filtercaps);
|
||||||
|
}
|
||||||
|
if (srcpad) {
|
||||||
|
/* loop through the allowed pads in the source, trying to find a
|
||||||
|
* compatible destination pad */
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
||||||
|
"looping through allowed src and dest pads");
|
||||||
|
do {
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "trying src pad %s:%s",
|
||||||
|
GST_DEBUG_PAD_NAME (srcpad));
|
||||||
|
if ((GST_PAD_DIRECTION (srcpad) == GST_PAD_SRC) &&
|
||||||
|
(GST_PAD_PEER (srcpad) == NULL)) {
|
||||||
|
GstPad *temp = destpadname ? destpad :
|
||||||
|
gst_element_get_compatible_pad_filtered (dest, srcpad,
|
||||||
|
filtercaps);
|
||||||
|
|
||||||
|
if (temp
|
||||||
|
&& gst_pad_link_filtered (srcpad, temp,
|
||||||
|
filtercaps) == GST_PAD_LINK_OK) {
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s",
|
||||||
|
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (temp));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* find a better way for this mess */
|
||||||
|
if (srcpads) {
|
||||||
|
srcpads = g_list_next (srcpads);
|
||||||
|
if (srcpads)
|
||||||
|
srcpad = (GstPad *) GST_PAD_REALIZE (srcpads->data);
|
||||||
|
}
|
||||||
|
} while (srcpads);
|
||||||
|
}
|
||||||
|
if (srcpadname) {
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s:%s to %s",
|
||||||
|
GST_DEBUG_PAD_NAME (srcpad), GST_ELEMENT_NAME (dest));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (destpad) {
|
||||||
|
/* loop through the existing pads in the destination */
|
||||||
|
do {
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "trying dest pad %s:%s",
|
||||||
|
GST_DEBUG_PAD_NAME (destpad));
|
||||||
|
if ((GST_PAD_DIRECTION (destpad) == GST_PAD_SINK) &&
|
||||||
|
(GST_PAD_PEER (destpad) == NULL)) {
|
||||||
|
GstPad *temp = gst_element_get_compatible_pad_filtered (src, destpad,
|
||||||
|
filtercaps);
|
||||||
|
|
||||||
|
if (temp
|
||||||
|
&& gst_pad_link_filtered (temp, destpad,
|
||||||
|
filtercaps) == GST_PAD_LINK_OK) {
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s",
|
||||||
|
GST_DEBUG_PAD_NAME (temp), GST_DEBUG_PAD_NAME (destpad));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (destpads) {
|
||||||
|
destpads = g_list_next (destpads);
|
||||||
|
if (destpads)
|
||||||
|
destpad = (GstPad *) GST_PAD_REALIZE (destpads->data);
|
||||||
|
}
|
||||||
|
} while (destpads);
|
||||||
|
}
|
||||||
|
if (destpadname) {
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s to %s:%s",
|
||||||
|
GST_ELEMENT_NAME (src), GST_DEBUG_PAD_NAME (destpad));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
||||||
|
"we might have request pads on both sides, checking...");
|
||||||
|
srctempls = gst_element_class_get_pad_template_list (srcclass);
|
||||||
|
desttempls = gst_element_class_get_pad_template_list (destclass);
|
||||||
|
|
||||||
|
if (srctempls && desttempls) {
|
||||||
|
while (srctempls) {
|
||||||
|
srctempl = (GstPadTemplate *) srctempls->data;
|
||||||
|
if (srctempl->presence == GST_PAD_REQUEST) {
|
||||||
|
for (l = desttempls; l; l = l->next) {
|
||||||
|
desttempl = (GstPadTemplate *) l->data;
|
||||||
|
if (desttempl->presence == GST_PAD_REQUEST &&
|
||||||
|
desttempl->direction != srctempl->direction) {
|
||||||
|
if (gst_caps_is_always_compatible (gst_pad_template_get_caps
|
||||||
|
(srctempl), gst_pad_template_get_caps (desttempl))) {
|
||||||
|
srcpad =
|
||||||
|
gst_element_get_request_pad (src, srctempl->name_template);
|
||||||
|
destpad =
|
||||||
|
gst_element_get_request_pad (dest, desttempl->name_template);
|
||||||
|
if (gst_pad_link_filtered (srcpad, destpad,
|
||||||
|
filtercaps) == GST_PAD_LINK_OK) {
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
|
||||||
|
"linked pad %s:%s to pad %s:%s",
|
||||||
|
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
/* it failed, so we release the request pads */
|
||||||
|
gst_element_release_request_pad (src, srcpad);
|
||||||
|
gst_element_release_request_pad (dest, destpad);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
srctempls = srctempls->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s to %s",
|
||||||
|
GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_element_link_filtered:
|
||||||
|
* @src: a #GstElement containing the source pad.
|
||||||
|
* @dest: the #GstElement containing the destination pad.
|
||||||
|
* @filtercaps: the #GstCaps to use as a filter.
|
||||||
|
*
|
||||||
|
* Links @src to @dest, filtered by @filtercaps. The link must be from source to
|
||||||
|
* destination; the other direction will not be tried. The function looks for
|
||||||
|
* existing pads that aren't linked yet. It will request new pads if necessary.
|
||||||
|
* If multiple links are possible, only one is established.
|
||||||
|
*
|
||||||
|
* Returns: TRUE if the elements could be linked, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
GstPadLinkReturn
|
||||||
|
gst_element_link_filtered (GstElement * src, GstElement * dest,
|
||||||
|
const GstCaps * filtercaps)
|
||||||
|
{
|
||||||
|
return gst_element_link_pads_filtered (src, NULL, dest, NULL, filtercaps);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_element_link_many:
|
||||||
|
* @element_1: the first #GstElement in the link chain.
|
||||||
|
* @element_2: the second #GstElement in the link chain.
|
||||||
|
* @...: the NULL-terminated list of elements to link in order.
|
||||||
|
*
|
||||||
|
* Chain together a series of elements. Uses gst_element_link().
|
||||||
|
*
|
||||||
|
* Returns: TRUE on success, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
GstPadLinkReturn
|
||||||
|
gst_element_link_many (GstElement * element_1, GstElement * element_2, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
g_return_val_if_fail (element_1 != NULL && element_2 != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (GST_IS_ELEMENT (element_1) &&
|
||||||
|
GST_IS_ELEMENT (element_2), FALSE);
|
||||||
|
|
||||||
|
va_start (args, element_2);
|
||||||
|
|
||||||
|
while (element_2) {
|
||||||
|
if (!gst_element_link (element_1, element_2))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
element_1 = element_2;
|
||||||
|
element_2 = va_arg (args, GstElement *);
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end (args);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_element_link:
|
||||||
|
* @src: a #GstElement containing the source pad.
|
||||||
|
* @dest: the #GstElement containing the destination pad.
|
||||||
|
*
|
||||||
|
* Links @src to @dest with no filter caps. See gst_element_link_filtered() for
|
||||||
|
* more information.
|
||||||
|
*
|
||||||
|
* Returns: TRUE if the elements could be linked, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
GstPadLinkReturn
|
||||||
|
gst_element_link (GstElement * src, GstElement * dest)
|
||||||
|
{
|
||||||
|
return gst_element_link_pads_filtered (src, NULL, dest, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_element_link_pads:
|
||||||
|
* @src: a #GstElement containing the source pad.
|
||||||
|
* @srcpadname: the name of the #GstPad in the source element.
|
||||||
|
* @dest: the #GstElement containing the destination pad.
|
||||||
|
* @destpadname: the name of the #GstPad in destination element.
|
||||||
|
*
|
||||||
|
* Links the two named pads of the source and destination elements.
|
||||||
|
* Side effect is that if one of the pads has no parent, it becomes a
|
||||||
|
* child of the parent of the other element. If they have different
|
||||||
|
* parents, the link fails.
|
||||||
|
*
|
||||||
|
* Returns: TRUE if the pads could be linked, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
GstPadLinkReturn
|
||||||
|
gst_element_link_pads (GstElement * src, const gchar * srcpadname,
|
||||||
|
GstElement * dest, const gchar * destpadname)
|
||||||
|
{
|
||||||
|
return gst_element_link_pads_filtered (src, srcpadname, dest, destpadname,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_element_unlink_pads:
|
||||||
|
* @src: a #GstElement containing the source pad.
|
||||||
|
* @srcpadname: the name of the #GstPad in source element.
|
||||||
|
* @dest: a #GstElement containing the destination pad.
|
||||||
|
* @destpadname: the name of the #GstPad in destination element.
|
||||||
|
*
|
||||||
|
* Unlinks the two named pads of the source and destination elements.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_element_unlink_pads (GstElement * src, const gchar * srcpadname,
|
||||||
|
GstElement * dest, const gchar * destpadname)
|
||||||
|
{
|
||||||
|
GstPad *srcpad, *destpad;
|
||||||
|
|
||||||
|
g_return_if_fail (src != NULL);
|
||||||
|
g_return_if_fail (GST_IS_ELEMENT (src));
|
||||||
|
g_return_if_fail (srcpadname != NULL);
|
||||||
|
g_return_if_fail (dest != NULL);
|
||||||
|
g_return_if_fail (GST_IS_ELEMENT (dest));
|
||||||
|
g_return_if_fail (destpadname != NULL);
|
||||||
|
|
||||||
|
/* obtain the pads requested */
|
||||||
|
srcpad = gst_element_get_pad (src, srcpadname);
|
||||||
|
if (srcpad == NULL) {
|
||||||
|
GST_WARNING_OBJECT (src, "source element has no pad \"%s\"", srcpadname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
destpad = gst_element_get_pad (dest, destpadname);
|
||||||
|
if (srcpad == NULL) {
|
||||||
|
GST_WARNING_OBJECT (dest, "destination element has no pad \"%s\"",
|
||||||
|
destpadname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we're satisified they can be unlinked, let's do it */
|
||||||
|
gst_pad_unlink (srcpad, destpad);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_element_unlink_many:
|
||||||
|
* @element_1: the first #GstElement in the link chain.
|
||||||
|
* @element_2: the second #GstElement in the link chain.
|
||||||
|
* @...: the NULL-terminated list of elements to unlink in order.
|
||||||
|
*
|
||||||
|
* Unlinks a series of elements. Uses gst_element_unlink().
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_element_unlink_many (GstElement * element_1, GstElement * element_2, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
g_return_if_fail (element_1 != NULL && element_2 != NULL);
|
||||||
|
g_return_if_fail (GST_IS_ELEMENT (element_1) && GST_IS_ELEMENT (element_2));
|
||||||
|
|
||||||
|
va_start (args, element_2);
|
||||||
|
|
||||||
|
while (element_2) {
|
||||||
|
gst_element_unlink (element_1, element_2);
|
||||||
|
|
||||||
|
element_1 = element_2;
|
||||||
|
element_2 = va_arg (args, GstElement *);
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end (args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_element_unlink:
|
||||||
|
* @src: the source #GstElement to unlink.
|
||||||
|
* @dest: the sink #GstElement to unlink.
|
||||||
|
*
|
||||||
|
* Unlinks all source pads of the source element with all sink pads
|
||||||
|
* of the sink element to which they are linked.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_element_unlink (GstElement * src, GstElement * dest)
|
||||||
|
{
|
||||||
|
const GList *srcpads;
|
||||||
|
GstPad *pad;
|
||||||
|
|
||||||
|
g_return_if_fail (GST_IS_ELEMENT (src));
|
||||||
|
g_return_if_fail (GST_IS_ELEMENT (dest));
|
||||||
|
|
||||||
|
GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "unlinking \"%s\" and \"%s\"",
|
||||||
|
GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
|
||||||
|
|
||||||
|
srcpads = gst_element_get_pad_list (src);
|
||||||
|
|
||||||
|
while (srcpads) {
|
||||||
|
pad = GST_PAD (srcpads->data);
|
||||||
|
|
||||||
|
/* we only care about real src pads */
|
||||||
|
if (GST_IS_REAL_PAD (pad) && GST_PAD_IS_SRC (pad)) {
|
||||||
|
GstPad *peerpad = GST_PAD_PEER (pad);
|
||||||
|
|
||||||
|
/* see if the pad is connected and is really a pad
|
||||||
|
* of dest */
|
||||||
|
if (peerpad && (GST_OBJECT_PARENT (peerpad) == (GstObject *) dest)) {
|
||||||
|
gst_pad_unlink (pad, peerpad);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
srcpads = g_list_next (srcpads);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_pad_can_link_filtered:
|
||||||
|
* @srcpad: the source #GstPad to link.
|
||||||
|
* @sinkpad: the sink #GstPad to link.
|
||||||
|
* @filtercaps: the filter #GstCaps.
|
||||||
|
*
|
||||||
|
* Checks if the source pad and the sink pad can be linked when constrained
|
||||||
|
* by the given filter caps. Both @srcpad and @sinkpad must be unlinked.
|
||||||
|
*
|
||||||
|
* Returns: TRUE if the pads can be linked, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
gst_pad_can_link_filtered (GstPad * srcpad, GstPad * sinkpad,
|
||||||
|
const GstCaps * filtercaps)
|
||||||
|
{
|
||||||
|
GstRealPad *realsrc, *realsink;
|
||||||
|
|
||||||
|
/* FIXME This function is gross. It's almost a direct copy of
|
||||||
|
* gst_pad_link_filtered(). Any decent programmer would attempt
|
||||||
|
* to merge the two functions, which I will do some day. --ds
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* generic checks */
|
||||||
|
g_return_val_if_fail (srcpad != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (GST_IS_PAD (srcpad), FALSE);
|
||||||
|
g_return_val_if_fail (sinkpad != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (GST_IS_PAD (sinkpad), FALSE);
|
||||||
|
|
||||||
|
GST_CAT_INFO (GST_CAT_PADS, "trying to link %s:%s and %s:%s",
|
||||||
|
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
|
||||||
|
|
||||||
|
/* now we need to deal with the real/ghost stuff */
|
||||||
|
realsrc = GST_PAD_REALIZE (srcpad);
|
||||||
|
realsink = GST_PAD_REALIZE (sinkpad);
|
||||||
|
|
||||||
|
if ((GST_PAD (realsrc) != srcpad) || (GST_PAD (realsink) != sinkpad)) {
|
||||||
|
GST_CAT_INFO (GST_CAT_PADS, "*actually* linking %s:%s and %s:%s",
|
||||||
|
GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
|
||||||
|
}
|
||||||
|
/* FIXME: shouldn't we convert this to g_return_val_if_fail? */
|
||||||
|
if (GST_RPAD_PEER (realsrc) != NULL) {
|
||||||
|
GST_CAT_INFO (GST_CAT_PADS, "Real source pad %s:%s has a peer, failed",
|
||||||
|
GST_DEBUG_PAD_NAME (realsrc));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (GST_RPAD_PEER (realsink) != NULL) {
|
||||||
|
GST_CAT_INFO (GST_CAT_PADS, "Real sink pad %s:%s has a peer, failed",
|
||||||
|
GST_DEBUG_PAD_NAME (realsink));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (GST_PAD_PARENT (realsrc) == NULL) {
|
||||||
|
GST_CAT_INFO (GST_CAT_PADS, "Real src pad %s:%s has no parent, failed",
|
||||||
|
GST_DEBUG_PAD_NAME (realsrc));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (GST_PAD_PARENT (realsink) == NULL) {
|
||||||
|
GST_CAT_INFO (GST_CAT_PADS, "Real sink pad %s:%s has no parent, failed",
|
||||||
|
GST_DEBUG_PAD_NAME (realsrc));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_return_val_if_fail (realsrc != NULL, GST_PAD_LINK_REFUSED);
|
||||||
|
g_return_val_if_fail (realsink != NULL, GST_PAD_LINK_REFUSED);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_pad_can_link:
|
||||||
|
* @srcpad: the source #GstPad to link.
|
||||||
|
* @sinkpad: the sink #GstPad to link.
|
||||||
|
*
|
||||||
|
* Checks if the source pad and the sink pad can be linked.
|
||||||
|
*
|
||||||
|
* Returns: TRUE if the pads can be linked, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
gst_pad_can_link (GstPad * srcpad, GstPad * sinkpad)
|
||||||
|
{
|
||||||
|
return gst_pad_can_link_filtered (srcpad, sinkpad, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_object_default_error:
|
||||||
|
* @object: a #GObject that signalled the error.
|
||||||
|
* @orig: the #GstObject that initiated the error.
|
||||||
|
* @error: the GError.
|
||||||
|
* @debug: an additional debug information string, or NULL.
|
||||||
|
*
|
||||||
|
* A default error function.
|
||||||
|
*
|
||||||
|
* The default handler will simply print the error string using g_print.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_object_default_error (GstObject * source, GError * error, gchar * debug)
|
||||||
|
{
|
||||||
|
gchar *name = gst_object_get_path_string (source);
|
||||||
|
|
||||||
|
g_print (_("ERROR: from element %s: %s\n"), name, error->message);
|
||||||
|
if (debug)
|
||||||
|
g_print (_("Additional debug info:\n%s\n"), debug);
|
||||||
|
|
||||||
|
g_free (name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_bin_add_many:
|
||||||
|
* @bin: the bin to add the elements to
|
||||||
|
* @element_1: the first element to add to the bin
|
||||||
|
* @...: additional elements to add to the bin
|
||||||
|
*
|
||||||
|
* Adds a NULL-terminated list of elements to a bin. This function is
|
||||||
|
* equivalent to calling #gst_bin_add() for each member of the list.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_bin_add_many (GstBin * bin, GstElement * element_1, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
g_return_if_fail (GST_IS_BIN (bin));
|
||||||
|
g_return_if_fail (GST_IS_ELEMENT (element_1));
|
||||||
|
|
||||||
|
va_start (args, element_1);
|
||||||
|
|
||||||
|
while (element_1) {
|
||||||
|
gst_bin_add (bin, element_1);
|
||||||
|
|
||||||
|
element_1 = va_arg (args, GstElement *);
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end (args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_bin_remove_many:
|
||||||
|
* @bin: the bin to remove the elements from
|
||||||
|
* @element_1: the first element to remove from the bin
|
||||||
|
* @...: NULL-terminated list of elements to remove from the bin
|
||||||
|
*
|
||||||
|
* Remove a list of elements from a bin. This function is equivalent
|
||||||
|
* to calling #gst_bin_remove with each member of the list.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_bin_remove_many (GstBin * bin, GstElement * element_1, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
g_return_if_fail (GST_IS_BIN (bin));
|
||||||
|
g_return_if_fail (GST_IS_ELEMENT (element_1));
|
||||||
|
|
||||||
|
va_start (args, element_1);
|
||||||
|
|
||||||
|
while (element_1) {
|
||||||
|
gst_bin_remove (bin, element_1);
|
||||||
|
|
||||||
|
element_1 = va_arg (args, GstElement *);
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end (args);
|
||||||
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#define __GST_UTILS_H__
|
#define __GST_UTILS_H__
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <gst/gstelement.h>
|
#include <gst/gstbin.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
@ -224,6 +224,49 @@ type_as_function ## _get_type (void) \
|
||||||
|
|
||||||
#endif /* GST_HAVE_UNALIGNED_ACCESS */
|
#endif /* GST_HAVE_UNALIGNED_ACCESS */
|
||||||
|
|
||||||
|
void gst_object_default_error (GstObject * source,
|
||||||
|
GError * error, gchar * debug);
|
||||||
|
|
||||||
|
|
||||||
|
/* element functions */
|
||||||
|
GstFlowReturn gst_element_abort_preroll (GstElement *element);
|
||||||
|
GstFlowReturn gst_element_finish_preroll (GstElement *element, GMutex *streamlock);
|
||||||
|
|
||||||
|
GstPad* gst_element_get_compatible_pad (GstElement *element, GstPad *pad);
|
||||||
|
GstPad* gst_element_get_compatible_pad_filtered (GstElement *element, GstPad *pad,
|
||||||
|
const GstCaps *filtercaps);
|
||||||
|
|
||||||
|
GstPadTemplate* gst_element_get_compatible_pad_template (GstElement *element, GstPadTemplate *compattempl);
|
||||||
|
|
||||||
|
G_CONST_RETURN gchar* gst_element_state_get_name (GstElementState state);
|
||||||
|
|
||||||
|
GstPadLinkReturn gst_element_link (GstElement *src, GstElement *dest);
|
||||||
|
GstPadLinkReturn gst_element_link_many (GstElement *element_1,
|
||||||
|
GstElement *element_2, ...);
|
||||||
|
GstPadLinkReturn gst_element_link_filtered (GstElement *src, GstElement *dest,
|
||||||
|
const GstCaps *filtercaps);
|
||||||
|
void gst_element_unlink (GstElement *src, GstElement *dest);
|
||||||
|
void gst_element_unlink_many (GstElement *element_1,
|
||||||
|
GstElement *element_2, ...);
|
||||||
|
|
||||||
|
GstPadLinkReturn gst_element_link_pads (GstElement *src, const gchar *srcpadname,
|
||||||
|
GstElement *dest, const gchar *destpadname);
|
||||||
|
GstPadLinkReturn gst_element_link_pads_filtered (GstElement *src, const gchar *srcpadname,
|
||||||
|
GstElement *dest, const gchar *destpadname,
|
||||||
|
const GstCaps *filtercaps);
|
||||||
|
void gst_element_unlink_pads (GstElement *src, const gchar *srcpadname,
|
||||||
|
GstElement *dest, const gchar *destpadname);
|
||||||
|
|
||||||
|
/* pad functions */
|
||||||
|
gboolean gst_pad_can_link (GstPad *srcpad, GstPad *sinkpad);
|
||||||
|
gboolean gst_pad_can_link_filtered (GstPad *srcpad, GstPad *sinkpad, const GstCaps *filtercaps);
|
||||||
|
|
||||||
|
|
||||||
|
/* bin functions */
|
||||||
|
void gst_bin_add_many (GstBin *bin, GstElement *element_1, ...);
|
||||||
|
void gst_bin_remove_many (GstBin *bin, GstElement *element_1, ...);
|
||||||
|
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __GST_UTILS_H__ */
|
#endif /* __GST_UTILS_H__ */
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "../gstinfo.h"
|
#include "../gstinfo.h"
|
||||||
#include "../gsterror.h"
|
#include "../gsterror.h"
|
||||||
#include "../gsturi.h"
|
#include "../gsturi.h"
|
||||||
|
#include "../gstutils.h"
|
||||||
#include "../gstvalue.h"
|
#include "../gstvalue.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
@ -285,7 +286,7 @@ gst_parse_free_link (link_t *link)
|
||||||
g_slist_foreach (link->sink_pads, (GFunc) gst_parse_strfree, NULL);
|
g_slist_foreach (link->sink_pads, (GFunc) gst_parse_strfree, NULL);
|
||||||
g_slist_free (link->src_pads);
|
g_slist_free (link->src_pads);
|
||||||
g_slist_free (link->sink_pads);
|
g_slist_free (link->sink_pads);
|
||||||
if (link->caps) gst_caps_free (link->caps);
|
if (link->caps) gst_caps_unref (link->caps);
|
||||||
gst_parse_link_free (link);
|
gst_parse_link_free (link);
|
||||||
}
|
}
|
||||||
static void
|
static void
|
||||||
|
@ -351,7 +352,7 @@ gst_parse_found_pad (GstElement *src, GstPad *pad, gpointer data)
|
||||||
g_signal_handler_disconnect (src, link->signal_id);
|
g_signal_handler_disconnect (src, link->signal_id);
|
||||||
g_free (link->src_pad);
|
g_free (link->src_pad);
|
||||||
g_free (link->sink_pad);
|
g_free (link->sink_pad);
|
||||||
if (link->caps) gst_caps_free (link->caps);
|
if (link->caps) gst_caps_unref (link->caps);
|
||||||
if (!gst_element_is_locked_state (src))
|
if (!gst_element_is_locked_state (src))
|
||||||
gst_parse_element_lock (link->sink, FALSE);
|
gst_parse_element_lock (link->sink, FALSE);
|
||||||
g_free (link);
|
g_free (link);
|
||||||
|
@ -362,7 +363,7 @@ static gboolean
|
||||||
gst_parse_perform_delayed_link (GstElement *src, const gchar *src_pad,
|
gst_parse_perform_delayed_link (GstElement *src, const gchar *src_pad,
|
||||||
GstElement *sink, const gchar *sink_pad, GstCaps *caps)
|
GstElement *sink, const gchar *sink_pad, GstCaps *caps)
|
||||||
{
|
{
|
||||||
GList *templs = gst_element_get_pad_template_list (src);
|
GList *templs = gst_element_class_get_pad_template_list (GST_ELEMENT_GET_CLASS (src));
|
||||||
|
|
||||||
for (; templs; templs = templs->next) {
|
for (; templs; templs = templs->next) {
|
||||||
GstPadTemplate *templ = (GstPadTemplate *) templs->data;
|
GstPadTemplate *templ = (GstPadTemplate *) templs->data;
|
||||||
|
|
|
@ -814,7 +814,7 @@ gst_xml_registry_parse_element_factory (GMarkupParseContext * context,
|
||||||
} else if (!strcmp (tag, "interface")) {
|
} else if (!strcmp (tag, "interface")) {
|
||||||
gchar *tmp = g_strndup (text, text_len);
|
gchar *tmp = g_strndup (text, text_len);
|
||||||
|
|
||||||
__gst_element_factory_add_interface (factory, tmp);
|
//__gst_element_factory_add_interface (factory, tmp);
|
||||||
g_free (tmp);
|
g_free (tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1040,8 +1040,8 @@ gst_xml_registry_end_element (GMarkupParseContext * context,
|
||||||
xmlregistry->name_template = NULL;
|
xmlregistry->name_template = NULL;
|
||||||
xmlregistry->caps = NULL;
|
xmlregistry->caps = NULL;
|
||||||
|
|
||||||
__gst_element_factory_add_pad_template (GST_ELEMENT_FACTORY
|
//__gst_element_factory_add_pad_template (GST_ELEMENT_FACTORY
|
||||||
(xmlregistry->current_feature), template);
|
// (xmlregistry->current_feature), template);
|
||||||
xmlregistry->state = GST_XML_REGISTRY_FEATURE;
|
xmlregistry->state = GST_XML_REGISTRY_FEATURE;
|
||||||
xmlregistry->parser = gst_xml_registry_parse_element_factory;
|
xmlregistry->parser = gst_xml_registry_parse_element_factory;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,89 +1,20 @@
|
||||||
if GST_DISABLE_OMEGA_COTHREADS
|
|
||||||
omegaschedulers =
|
|
||||||
omegaschedulers_nola =
|
|
||||||
else
|
|
||||||
omegaschedulers = \
|
|
||||||
libgstbasicomegascheduler.la \
|
|
||||||
libgstentryomegascheduler.la \
|
|
||||||
libgstoptomegascheduler.la
|
|
||||||
omegaschedulers_nola = \
|
|
||||||
libgstbasicomegascheduler \
|
|
||||||
libgstentryomegascheduler \
|
|
||||||
libgstoptomegascheduler
|
|
||||||
endif
|
|
||||||
|
|
||||||
plugin_LTLIBRARIES = \
|
plugin_LTLIBRARIES = \
|
||||||
$(omegaschedulers) \
|
libthreadscheduler.la
|
||||||
libgstbasicgthreadscheduler.la \
|
|
||||||
libgstentrygthreadscheduler.la \
|
|
||||||
libgstoptscheduler.la \
|
|
||||||
libgstoptgthreadscheduler.la \
|
|
||||||
libgstfairgthreadscheduler.la
|
|
||||||
AS_LIBTOOL_LIBS = \
|
AS_LIBTOOL_LIBS = \
|
||||||
$(omegaschedulers_nola) \
|
libthreadscheduler
|
||||||
libgstbasicgthreadscheduler \
|
|
||||||
libgstentrygthreadscheduler \
|
|
||||||
libgstoptscheduler \
|
|
||||||
libgstoptgthreadscheduler \
|
|
||||||
libgstfairgthreadscheduler
|
|
||||||
|
|
||||||
if GST_DISABLE_OMEGA_COTHREADS
|
libthreadscheduler_la_SOURCES = threadscheduler.c
|
||||||
else
|
libthreadscheduler_la_CFLAGS = $(GST_OBJ_CFLAGS)
|
||||||
libgstbasicomegascheduler_la_SOURCES = gstbasicscheduler.c
|
libthreadscheduler_la_LIBADD = $(GST_OBJ_LIBS)
|
||||||
libgstbasicomegascheduler_la_CFLAGS = $(GST_OBJ_CFLAGS) -D_COTHREADS_OMEGA
|
libthreadscheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||||
libgstbasicomegascheduler_la_LIBADD = $(GST_OBJ_LIBS) ../libcothreads.la
|
|
||||||
libgstbasicomegascheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS)
|
|
||||||
endif
|
|
||||||
|
|
||||||
libgstbasicgthreadscheduler_la_SOURCES = gstbasicscheduler.c
|
noinst_HEADERS =
|
||||||
libgstbasicgthreadscheduler_la_CFLAGS = $(GST_OBJ_CFLAGS) -D_COTHREADS_GTHREAD
|
|
||||||
libgstbasicgthreadscheduler_la_LIBADD = $(GST_OBJ_LIBS)
|
|
||||||
libgstbasicgthreadscheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS)
|
|
||||||
|
|
||||||
libgstentrygthreadscheduler_la_SOURCES = entryscheduler.c
|
|
||||||
libgstentrygthreadscheduler_la_CFLAGS = $(GST_OBJ_CFLAGS) -D_COTHREADS_GTHREAD
|
|
||||||
libgstentrygthreadscheduler_la_LIBADD = $(GST_OBJ_LIBS)
|
|
||||||
libgstentrygthreadscheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS)
|
|
||||||
|
|
||||||
if GST_DISABLE_OMEGA_COTHREADS
|
|
||||||
else
|
|
||||||
libgstentryomegascheduler_la_SOURCES = entryscheduler.c
|
|
||||||
libgstentryomegascheduler_la_CFLAGS = $(GST_OBJ_CFLAGS) -D_COTHREADS_OMEGA
|
|
||||||
libgstentryomegascheduler_la_LIBADD = $(GST_OBJ_LIBS) ../libcothreads.la
|
|
||||||
libgstentryomegascheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS)
|
|
||||||
endif
|
|
||||||
|
|
||||||
libgstoptscheduler_la_SOURCES = gstoptimalscheduler.c
|
|
||||||
libgstoptscheduler_la_CFLAGS = $(GST_OBJ_CFLAGS)
|
|
||||||
libgstoptscheduler_la_LIBADD = $(GST_OBJ_LIBS)
|
|
||||||
libgstoptscheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS)
|
|
||||||
|
|
||||||
if GST_DISABLE_OMEGA_COTHREADS
|
|
||||||
else
|
|
||||||
libgstoptomegascheduler_la_SOURCES = gstoptimalscheduler.c
|
|
||||||
libgstoptomegascheduler_la_CFLAGS = $(GST_OBJ_CFLAGS) -D_COTHREADS_OMEGA -DUSE_COTHREADS
|
|
||||||
libgstoptomegascheduler_la_LIBADD = $(GST_OBJ_LIBS) ../libcothreads.la
|
|
||||||
libgstoptomegascheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS)
|
|
||||||
endif
|
|
||||||
|
|
||||||
libgstoptgthreadscheduler_la_SOURCES = gstoptimalscheduler.c
|
|
||||||
libgstoptgthreadscheduler_la_CFLAGS = $(GST_OBJ_CFLAGS) -D_COTHREADS_GTHREAD -DUSE_COTHREADS
|
|
||||||
libgstoptgthreadscheduler_la_LIBADD = $(GST_OBJ_LIBS)
|
|
||||||
libgstoptgthreadscheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS)
|
|
||||||
|
|
||||||
libgstfairgthreadscheduler_la_SOURCES = fairscheduler.c faircothreads.c
|
|
||||||
libgstfairgthreadscheduler_la_CFLAGS = $(GST_OBJ_CFLAGS) -D_COTHREADS_GTHREAD
|
|
||||||
libgstfairgthreadscheduler_la_LIBADD = $(GST_OBJ_LIBS)
|
|
||||||
libgstfairgthreadscheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS)
|
|
||||||
|
|
||||||
noinst_HEADERS = cothreads_compat.h gthread-cothreads.h faircothreads.h
|
|
||||||
|
|
||||||
if AS_LIBTOOL_WIN32
|
if AS_LIBTOOL_WIN32
|
||||||
|
|
||||||
as_libtool_noinst_DATA_files = $(AS_LIBTOOL_LIB).lib
|
as_libtool_noinst_DATA_files = $(AS_LIBTOOL_LIB).lib
|
||||||
|
|
||||||
as_libtool_LDFLAGS = -no-undefined
|
|
||||||
|
|
||||||
# depend on this in install-data-local
|
# depend on this in install-data-local
|
||||||
as-libtool-install-data-local:
|
as-libtool-install-data-local:
|
||||||
for i in $(AS_LIBTOOL_LIBS); do \
|
for i in $(AS_LIBTOOL_LIBS); do \
|
||||||
|
|
|
@ -153,7 +153,7 @@ gst_bytestream_get_next_buf (GstByteStream * bs)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
GST_DEBUG ("get_next_buf: pulling buffer");
|
GST_DEBUG ("get_next_buf: pulling buffer");
|
||||||
nextbuf = GST_BUFFER (gst_pad_pull (bs->pad));
|
gst_pad_pull (bs->pad, &nextbuf);
|
||||||
|
|
||||||
if (!nextbuf)
|
if (!nextbuf)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
|
@ -39,7 +39,7 @@ GST_BOILERPLATE_FULL (GstFilePad, gst_file_pad, GstRealPad, GST_TYPE_REAL_PAD,
|
||||||
static void gst_file_pad_dispose (GObject * object);
|
static void gst_file_pad_dispose (GObject * object);
|
||||||
static void gst_file_pad_finalize (GObject * object);
|
static void gst_file_pad_finalize (GObject * object);
|
||||||
|
|
||||||
static void gst_file_pad_chain (GstPad * pad, GstData * data);
|
//static void gst_file_pad_chain (GstPad * pad, GstData * data);
|
||||||
static void gst_file_pad_parent_set (GstObject * object,
|
static void gst_file_pad_parent_set (GstObject * object,
|
||||||
GstObject * parent);
|
GstObject * parent);
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ gst_file_pad_init (GstFilePad * pad)
|
||||||
/* must do this for set_chain_function to work */
|
/* must do this for set_chain_function to work */
|
||||||
real->direction = GST_PAD_SINK;
|
real->direction = GST_PAD_SINK;
|
||||||
|
|
||||||
gst_pad_set_chain_function (GST_PAD (real), gst_file_pad_chain);
|
//gst_pad_set_chain_function (GST_PAD (real), gst_file_pad_chain);
|
||||||
|
|
||||||
pad->adapter = gst_adapter_new ();
|
pad->adapter = gst_adapter_new ();
|
||||||
pad->in_seek = FALSE;
|
pad->in_seek = FALSE;
|
||||||
|
@ -98,6 +98,7 @@ gst_file_pad_finalize (GObject * object)
|
||||||
GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
|
GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
static void
|
static void
|
||||||
gst_file_pad_chain (GstPad * gst_pad, GstData * data)
|
gst_file_pad_chain (GstPad * gst_pad, GstData * data)
|
||||||
{
|
{
|
||||||
|
@ -174,6 +175,7 @@ gst_file_pad_chain (GstPad * gst_pad, GstData * data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_file_pad_parent_set (GstObject * object, GstObject * parent)
|
gst_file_pad_parent_set (GstObject * object, GstObject * parent)
|
||||||
|
@ -183,10 +185,8 @@ gst_file_pad_parent_set (GstObject * object, GstObject * parent)
|
||||||
/* FIXME: we can only be added to elements, right? */
|
/* FIXME: we can only be added to elements, right? */
|
||||||
element = GST_ELEMENT (parent);
|
element = GST_ELEMENT (parent);
|
||||||
|
|
||||||
if (element->loopfunc)
|
//if (element->loopfunc)
|
||||||
g_warning ("attempt to add a GstFilePad to a loopbased element.");
|
// g_warning ("attempt to add a GstFilePad to a loopbased element.");
|
||||||
if (!GST_FLAG_IS_SET (element, GST_ELEMENT_EVENT_AWARE))
|
|
||||||
g_warning ("elements using GstFilePad must be event-aware.");
|
|
||||||
|
|
||||||
GST_CALL_PARENT (GST_OBJECT_CLASS, parent_set, (object, parent));
|
GST_CALL_PARENT (GST_OBJECT_CLASS, parent_set, (object, parent));
|
||||||
}
|
}
|
||||||
|
|
|
@ -324,7 +324,6 @@ gst_dp_packet_from_event (const GstEvent * event, GstDPHeaderFlag flags,
|
||||||
return FALSE;
|
return FALSE;
|
||||||
case GST_EVENT_EOS:
|
case GST_EVENT_EOS:
|
||||||
case GST_EVENT_FLUSH:
|
case GST_EVENT_FLUSH:
|
||||||
case GST_EVENT_EMPTY:
|
|
||||||
case GST_EVENT_DISCONTINUOUS:
|
case GST_EVENT_DISCONTINUOUS:
|
||||||
GST_WRITE_UINT64_BE (h + 8, GST_EVENT_TIMESTAMP (event));
|
GST_WRITE_UINT64_BE (h + 8, GST_EVENT_TIMESTAMP (event));
|
||||||
pl_length = 0;
|
pl_length = 0;
|
||||||
|
@ -354,9 +353,6 @@ gst_dp_packet_from_event (const GstEvent * event, GstDPHeaderFlag flags,
|
||||||
case GST_EVENT_SEGMENT_DONE:
|
case GST_EVENT_SEGMENT_DONE:
|
||||||
case GST_EVENT_SIZE:
|
case GST_EVENT_SIZE:
|
||||||
case GST_EVENT_RATE:
|
case GST_EVENT_RATE:
|
||||||
case GST_EVENT_FILLER:
|
|
||||||
case GST_EVENT_TS_OFFSET:
|
|
||||||
case GST_EVENT_INTERRUPT:
|
|
||||||
case GST_EVENT_NAVIGATION:
|
case GST_EVENT_NAVIGATION:
|
||||||
case GST_EVENT_TAG:
|
case GST_EVENT_TAG:
|
||||||
g_warning ("Unhandled event type %d, ignoring", GST_EVENT_TYPE (event));
|
g_warning ("Unhandled event type %d, ignoring", GST_EVENT_TYPE (event));
|
||||||
|
@ -489,7 +485,6 @@ gst_dp_event_from_packet (guint header_length, const guint8 * header,
|
||||||
return FALSE;
|
return FALSE;
|
||||||
case GST_EVENT_EOS:
|
case GST_EVENT_EOS:
|
||||||
case GST_EVENT_FLUSH:
|
case GST_EVENT_FLUSH:
|
||||||
case GST_EVENT_EMPTY:
|
|
||||||
case GST_EVENT_DISCONTINUOUS:
|
case GST_EVENT_DISCONTINUOUS:
|
||||||
event = gst_event_new (type);
|
event = gst_event_new (type);
|
||||||
GST_EVENT_TIMESTAMP (event) = GST_DP_HEADER_TIMESTAMP (header);
|
GST_EVENT_TIMESTAMP (event) = GST_DP_HEADER_TIMESTAMP (header);
|
||||||
|
@ -527,9 +522,6 @@ gst_dp_event_from_packet (guint header_length, const guint8 * header,
|
||||||
case GST_EVENT_SEGMENT_DONE:
|
case GST_EVENT_SEGMENT_DONE:
|
||||||
case GST_EVENT_SIZE:
|
case GST_EVENT_SIZE:
|
||||||
case GST_EVENT_RATE:
|
case GST_EVENT_RATE:
|
||||||
case GST_EVENT_FILLER:
|
|
||||||
case GST_EVENT_TS_OFFSET:
|
|
||||||
case GST_EVENT_INTERRUPT:
|
|
||||||
case GST_EVENT_NAVIGATION:
|
case GST_EVENT_NAVIGATION:
|
||||||
case GST_EVENT_TAG:
|
case GST_EVENT_TAG:
|
||||||
g_warning ("Unhandled event type %d, ignoring", GST_EVENT_TYPE (event));
|
g_warning ("Unhandled event type %d, ignoring", GST_EVENT_TYPE (event));
|
||||||
|
|
|
@ -24,16 +24,17 @@ endif
|
||||||
|
|
||||||
libgstelements_la_DEPENDENCIES = ../libgstreamer-@GST_MAJORMINOR@.la
|
libgstelements_la_DEPENDENCIES = ../libgstreamer-@GST_MAJORMINOR@.la
|
||||||
libgstelements_la_SOURCES = \
|
libgstelements_la_SOURCES = \
|
||||||
gstaggregator.c \
|
|
||||||
gstbufferstore.c \
|
|
||||||
gstelements.c \
|
|
||||||
gstfakesink.c \
|
|
||||||
gstfakesrc.c \
|
gstfakesrc.c \
|
||||||
gstfilesink.c \
|
gstfakesink.c \
|
||||||
gstfilesrc.c \
|
gstfilesrc.c \
|
||||||
|
gstidentity.c \
|
||||||
|
gstelements.c \
|
||||||
|
#gstaggregator.c \
|
||||||
|
gstbufferstore.c \
|
||||||
|
gstfakesink.c \
|
||||||
|
gstfilesink.c \
|
||||||
gstfdsink.c \
|
gstfdsink.c \
|
||||||
gstfdsrc.c \
|
gstfdsrc.c \
|
||||||
gstidentity.c \
|
|
||||||
gstmd5sink.c \
|
gstmd5sink.c \
|
||||||
$(multifilesrc) \
|
$(multifilesrc) \
|
||||||
$(pipefilter) \
|
$(pipefilter) \
|
||||||
|
|
|
@ -55,24 +55,24 @@ extern GType gst_filesrc_get_type (void);
|
||||||
extern GstElementDetails gst_filesrc_details;
|
extern GstElementDetails gst_filesrc_details;
|
||||||
|
|
||||||
static struct _elements_entry _elements[] = {
|
static struct _elements_entry _elements[] = {
|
||||||
{"aggregator", GST_RANK_NONE, gst_aggregator_get_type},
|
// {"aggregator", GST_RANK_NONE, gst_aggregator_get_type},
|
||||||
{"fakesrc", GST_RANK_NONE, gst_fakesrc_get_type},
|
{"fakesrc", GST_RANK_NONE, gst_fakesrc_get_type},
|
||||||
{"fakesink", GST_RANK_NONE, gst_fakesink_get_type},
|
{"fakesink", GST_RANK_NONE, gst_fakesink_get_type},
|
||||||
{"fdsink", GST_RANK_NONE, gst_fdsink_get_type},
|
|
||||||
{"fdsrc", GST_RANK_NONE, gst_fdsrc_get_type},
|
|
||||||
{"filesrc", GST_RANK_NONE, gst_filesrc_get_type},
|
{"filesrc", GST_RANK_NONE, gst_filesrc_get_type},
|
||||||
{"filesink", GST_RANK_NONE, gst_filesink_get_type},
|
|
||||||
{"identity", GST_RANK_NONE, gst_identity_get_type},
|
{"identity", GST_RANK_NONE, gst_identity_get_type},
|
||||||
{"md5sink", GST_RANK_NONE, gst_md5sink_get_type},
|
// {"fdsink", GST_RANK_NONE, gst_fdsink_get_type},
|
||||||
|
// {"fdsrc", GST_RANK_NONE, gst_fdsrc_get_type},
|
||||||
|
// {"filesink", GST_RANK_NONE, gst_filesink_get_type},
|
||||||
|
// {"md5sink", GST_RANK_NONE, gst_md5sink_get_type},
|
||||||
#ifndef HAVE_WIN32
|
#ifndef HAVE_WIN32
|
||||||
{"multifilesrc", GST_RANK_NONE, gst_multifilesrc_get_type},
|
// {"multifilesrc", GST_RANK_NONE, gst_multifilesrc_get_type},
|
||||||
{"pipefilter", GST_RANK_NONE, gst_pipefilter_get_type},
|
// {"pipefilter", GST_RANK_NONE, gst_pipefilter_get_type},
|
||||||
#endif
|
#endif
|
||||||
{"shaper", GST_RANK_NONE, gst_shaper_get_type},
|
// {"shaper", GST_RANK_NONE, gst_shaper_get_type},
|
||||||
{"statistics", GST_RANK_NONE, gst_statistics_get_type},
|
// {"statistics", GST_RANK_NONE, gst_statistics_get_type},
|
||||||
{"tee", GST_RANK_NONE, gst_tee_get_type},
|
// {"tee", GST_RANK_NONE, gst_tee_get_type},
|
||||||
{"typefind", GST_RANK_NONE, gst_type_find_element_get_type},
|
// {"typefind", GST_RANK_NONE, gst_type_find_element_get_type},
|
||||||
{NULL, 0},
|
// {NULL, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
|
|
@ -113,7 +113,8 @@ static void gst_fakesink_get_property (GObject * object, guint prop_id,
|
||||||
|
|
||||||
static GstElementStateReturn gst_fakesink_change_state (GstElement * element);
|
static GstElementStateReturn gst_fakesink_change_state (GstElement * element);
|
||||||
|
|
||||||
static void gst_fakesink_chain (GstPad * pad, GstData * _data);
|
static GstFlowReturn gst_fakesink_chain (GstPad * pad, GstBuffer * buffer);
|
||||||
|
static gboolean gst_fakesink_event (GstPad * pad, GstEvent * event);
|
||||||
|
|
||||||
static guint gst_fakesink_signals[LAST_SIGNAL] = { 0 };
|
static guint gst_fakesink_signals[LAST_SIGNAL] = { 0 };
|
||||||
|
|
||||||
|
@ -138,6 +139,8 @@ gst_fakesink_class_init (GstFakeSinkClass * klass)
|
||||||
gobject_class = (GObjectClass *) klass;
|
gobject_class = (GObjectClass *) klass;
|
||||||
gstelement_class = (GstElementClass *) klass;
|
gstelement_class = (GstElementClass *) klass;
|
||||||
|
|
||||||
|
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesink_set_property);
|
||||||
|
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesink_get_property);
|
||||||
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_SINKS,
|
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_SINKS,
|
||||||
g_param_spec_int ("num_sinks", "Number of sinks",
|
g_param_spec_int ("num_sinks", "Number of sinks",
|
||||||
|
@ -169,9 +172,6 @@ gst_fakesink_class_init (GstFakeSinkClass * klass)
|
||||||
gst_marshal_VOID__BOXED_OBJECT, G_TYPE_NONE, 2,
|
gst_marshal_VOID__BOXED_OBJECT, G_TYPE_NONE, 2,
|
||||||
GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD);
|
GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD);
|
||||||
|
|
||||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesink_set_property);
|
|
||||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesink_get_property);
|
|
||||||
|
|
||||||
gstelement_class->request_new_pad =
|
gstelement_class->request_new_pad =
|
||||||
GST_DEBUG_FUNCPTR (gst_fakesink_request_new_pad);
|
GST_DEBUG_FUNCPTR (gst_fakesink_request_new_pad);
|
||||||
gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_fakesink_set_clock);
|
gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_fakesink_set_clock);
|
||||||
|
@ -189,6 +189,7 @@ gst_fakesink_init (GstFakeSink * fakesink)
|
||||||
"sink");
|
"sink");
|
||||||
gst_element_add_pad (GST_ELEMENT (fakesink), pad);
|
gst_element_add_pad (GST_ELEMENT (fakesink), pad);
|
||||||
gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_fakesink_chain));
|
gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_fakesink_chain));
|
||||||
|
gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_fakesink_event));
|
||||||
|
|
||||||
fakesink->silent = FALSE;
|
fakesink->silent = FALSE;
|
||||||
fakesink->dump = FALSE;
|
fakesink->dump = FALSE;
|
||||||
|
@ -196,8 +197,6 @@ gst_fakesink_init (GstFakeSink * fakesink)
|
||||||
fakesink->last_message = NULL;
|
fakesink->last_message = NULL;
|
||||||
fakesink->state_error = FAKESINK_STATE_ERROR_NONE;
|
fakesink->state_error = FAKESINK_STATE_ERROR_NONE;
|
||||||
fakesink->signal_handoffs = FALSE;
|
fakesink->signal_handoffs = FALSE;
|
||||||
|
|
||||||
GST_FLAG_SET (fakesink, GST_ELEMENT_EVENT_AWARE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -308,45 +307,72 @@ gst_fakesink_get_property (GObject * object, guint prop_id, GValue * value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static gboolean
|
||||||
gst_fakesink_chain (GstPad * pad, GstData * _data)
|
gst_fakesink_event (GstPad * pad, GstEvent * event)
|
||||||
{
|
{
|
||||||
GstBuffer *buf = GST_BUFFER (_data);
|
|
||||||
GstFakeSink *fakesink;
|
GstFakeSink *fakesink;
|
||||||
|
gboolean result = TRUE;
|
||||||
g_return_if_fail (pad != NULL);
|
|
||||||
g_return_if_fail (GST_IS_PAD (pad));
|
|
||||||
g_return_if_fail (buf != NULL);
|
|
||||||
|
|
||||||
fakesink = GST_FAKESINK (GST_OBJECT_PARENT (pad));
|
fakesink = GST_FAKESINK (GST_OBJECT_PARENT (pad));
|
||||||
|
|
||||||
if (GST_IS_EVENT (buf)) {
|
GST_STREAM_LOCK (pad);
|
||||||
GstEvent *event = GST_EVENT (buf);
|
|
||||||
|
|
||||||
if (!fakesink->silent) {
|
if (!fakesink->silent) {
|
||||||
g_free (fakesink->last_message);
|
g_free (fakesink->last_message);
|
||||||
|
|
||||||
fakesink->last_message =
|
fakesink->last_message =
|
||||||
g_strdup_printf ("chain ******* (%s:%s)E (type: %d) %p",
|
g_strdup_printf ("chain ******* (%s:%s)E (type: %d) %p",
|
||||||
GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event);
|
GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event);
|
||||||
|
|
||||||
g_object_notify (G_OBJECT (fakesink), "last_message");
|
g_object_notify (G_OBJECT (fakesink), "last_message");
|
||||||
}
|
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
|
||||||
case GST_EVENT_DISCONTINUOUS:
|
|
||||||
if (fakesink->sync && fakesink->clock) {
|
|
||||||
gint64 value = GST_EVENT_DISCONT_OFFSET (event, 0).value;
|
|
||||||
|
|
||||||
gst_element_set_time (GST_ELEMENT (fakesink), value);
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
gst_pad_event_default (pad, event);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_EOS:
|
||||||
|
{
|
||||||
|
gst_element_finish_preroll (GST_ELEMENT (fakesink),
|
||||||
|
GST_STREAM_GET_LOCK (pad));
|
||||||
|
gst_pipeline_post_message (GST_ELEMENT_MANAGER (fakesink),
|
||||||
|
gst_message_new_eos (GST_OBJECT (fakesink)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GST_EVENT_DISCONTINUOUS:
|
||||||
|
if (fakesink->sync && fakesink->clock) {
|
||||||
|
//gint64 value = GST_EVENT_DISCONT_OFFSET (event, 0).value;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
result = gst_pad_event_default (pad, event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
GST_STREAM_UNLOCK (pad);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_fakesink_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
|
{
|
||||||
|
GstBuffer *buf = GST_BUFFER (buffer);
|
||||||
|
GstFakeSink *fakesink;
|
||||||
|
GstFlowReturn result = GST_FLOW_OK;
|
||||||
|
GstCaps *caps;
|
||||||
|
|
||||||
|
fakesink = GST_FAKESINK (GST_OBJECT_PARENT (pad));
|
||||||
|
|
||||||
|
caps = gst_buffer_get_caps (buffer);
|
||||||
|
if (caps && caps != GST_PAD_CAPS (pad)) {
|
||||||
|
gst_pad_set_caps (pad, caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* grab streaming lock to synchronize with event method */
|
||||||
|
GST_STREAM_LOCK (pad);
|
||||||
|
|
||||||
|
result =
|
||||||
|
gst_element_finish_preroll (GST_ELEMENT (fakesink),
|
||||||
|
GST_STREAM_GET_LOCK (pad));
|
||||||
|
if (result != GST_FLOW_OK)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
if (fakesink->sync && fakesink->clock) {
|
if (fakesink->sync && fakesink->clock) {
|
||||||
gst_element_wait (GST_ELEMENT (fakesink), GST_BUFFER_TIMESTAMP (buf));
|
gst_element_wait (GST_ELEMENT (fakesink), GST_BUFFER_TIMESTAMP (buf));
|
||||||
}
|
}
|
||||||
|
@ -374,12 +400,17 @@ gst_fakesink_chain (GstPad * pad, GstData * _data)
|
||||||
gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
|
gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
GST_STREAM_UNLOCK (pad);
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstElementStateReturn
|
static GstElementStateReturn
|
||||||
gst_fakesink_change_state (GstElement * element)
|
gst_fakesink_change_state (GstElement * element)
|
||||||
{
|
{
|
||||||
|
GstElementStateReturn ret = GST_STATE_SUCCESS;
|
||||||
GstFakeSink *fakesink = GST_FAKESINK (element);
|
GstFakeSink *fakesink = GST_FAKESINK (element);
|
||||||
|
|
||||||
switch (GST_STATE_TRANSITION (element)) {
|
switch (GST_STATE_TRANSITION (element)) {
|
||||||
|
@ -390,6 +421,8 @@ gst_fakesink_change_state (GstElement * element)
|
||||||
case GST_STATE_READY_TO_PAUSED:
|
case GST_STATE_READY_TO_PAUSED:
|
||||||
if (fakesink->state_error == FAKESINK_STATE_ERROR_READY_PAUSED)
|
if (fakesink->state_error == FAKESINK_STATE_ERROR_READY_PAUSED)
|
||||||
goto error;
|
goto error;
|
||||||
|
/* need to complete preroll before this state change completes */
|
||||||
|
ret = GST_STATE_ASYNC;
|
||||||
break;
|
break;
|
||||||
case GST_STATE_PAUSED_TO_PLAYING:
|
case GST_STATE_PAUSED_TO_PLAYING:
|
||||||
if (fakesink->state_error == FAKESINK_STATE_ERROR_PAUSED_PLAYING)
|
if (fakesink->state_error == FAKESINK_STATE_ERROR_PAUSED_PLAYING)
|
||||||
|
@ -412,9 +445,9 @@ gst_fakesink_change_state (GstElement * element)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
||||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||||
|
|
||||||
return GST_STATE_SUCCESS;
|
return ret;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
GST_ELEMENT_ERROR (element, CORE, STATE_CHANGE, (NULL), (NULL));
|
GST_ELEMENT_ERROR (element, CORE, STATE_CHANGE, (NULL), (NULL));
|
||||||
|
|
|
@ -180,6 +180,7 @@ GST_BOILERPLATE_FULL (GstFakeSrc, gst_fakesrc, GstElement, GST_TYPE_ELEMENT,
|
||||||
static GstPad *gst_fakesrc_request_new_pad (GstElement * element,
|
static GstPad *gst_fakesrc_request_new_pad (GstElement * element,
|
||||||
GstPadTemplate * templ, const gchar * unused);
|
GstPadTemplate * templ, const gchar * unused);
|
||||||
static void gst_fakesrc_update_functions (GstFakeSrc * src);
|
static void gst_fakesrc_update_functions (GstFakeSrc * src);
|
||||||
|
static gboolean gst_fakesrc_activate (GstPad * pad, gboolean active);
|
||||||
static void gst_fakesrc_set_property (GObject * object, guint prop_id,
|
static void gst_fakesrc_set_property (GObject * object, guint prop_id,
|
||||||
const GValue * value, GParamSpec * pspec);
|
const GValue * value, GParamSpec * pspec);
|
||||||
static void gst_fakesrc_get_property (GObject * object, guint prop_id,
|
static void gst_fakesrc_get_property (GObject * object, guint prop_id,
|
||||||
|
@ -188,7 +189,7 @@ static void gst_fakesrc_set_clock (GstElement * element, GstClock * clock);
|
||||||
|
|
||||||
static GstElementStateReturn gst_fakesrc_change_state (GstElement * element);
|
static GstElementStateReturn gst_fakesrc_change_state (GstElement * element);
|
||||||
|
|
||||||
static GstData *gst_fakesrc_get (GstPad * pad);
|
static GstFlowReturn gst_fakesrc_get (GstPad * pad, GstBuffer ** buffer);
|
||||||
static void gst_fakesrc_loop (GstElement * element);
|
static void gst_fakesrc_loop (GstElement * element);
|
||||||
|
|
||||||
static guint gst_fakesrc_signals[LAST_SIGNAL] = { 0 };
|
static guint gst_fakesrc_signals[LAST_SIGNAL] = { 0 };
|
||||||
|
@ -214,6 +215,8 @@ gst_fakesrc_class_init (GstFakeSrcClass * klass)
|
||||||
gobject_class = (GObjectClass *) klass;
|
gobject_class = (GObjectClass *) klass;
|
||||||
gstelement_class = (GstElementClass *) klass;
|
gstelement_class = (GstElementClass *) klass;
|
||||||
|
|
||||||
|
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesrc_set_property);
|
||||||
|
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesrc_get_property);
|
||||||
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_SOURCES,
|
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_SOURCES,
|
||||||
g_param_spec_int ("num-sources", "num-sources", "Number of sources",
|
g_param_spec_int ("num-sources", "num-sources", "Number of sources",
|
||||||
|
@ -281,9 +284,6 @@ gst_fakesrc_class_init (GstFakeSrcClass * klass)
|
||||||
gst_marshal_VOID__BOXED_OBJECT, G_TYPE_NONE, 2,
|
gst_marshal_VOID__BOXED_OBJECT, G_TYPE_NONE, 2,
|
||||||
GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD);
|
GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD);
|
||||||
|
|
||||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesrc_set_property);
|
|
||||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesrc_get_property);
|
|
||||||
|
|
||||||
gstelement_class->request_new_pad =
|
gstelement_class->request_new_pad =
|
||||||
GST_DEBUG_FUNCPTR (gst_fakesrc_request_new_pad);
|
GST_DEBUG_FUNCPTR (gst_fakesrc_request_new_pad);
|
||||||
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_fakesrc_change_state);
|
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_fakesrc_change_state);
|
||||||
|
@ -434,7 +434,7 @@ gst_fakesrc_event_handler (GstPad * pad, GstEvent * event)
|
||||||
{
|
{
|
||||||
GstFakeSrc *src;
|
GstFakeSrc *src;
|
||||||
|
|
||||||
src = GST_FAKESRC (gst_pad_get_parent (pad));
|
src = GST_FAKESRC (gst_object_get_parent (GST_OBJECT (pad)));
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
case GST_EVENT_SEEK:
|
case GST_EVENT_SEEK:
|
||||||
|
@ -467,13 +467,6 @@ gst_fakesrc_update_functions (GstFakeSrc * src)
|
||||||
{
|
{
|
||||||
GList *pads;
|
GList *pads;
|
||||||
|
|
||||||
if (src->loop_based) {
|
|
||||||
gst_element_set_loop_function (GST_ELEMENT (src),
|
|
||||||
GST_DEBUG_FUNCPTR (gst_fakesrc_loop));
|
|
||||||
} else {
|
|
||||||
gst_element_set_loop_function (GST_ELEMENT (src), NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
pads = GST_ELEMENT (src)->pads;
|
pads = GST_ELEMENT (src)->pads;
|
||||||
while (pads) {
|
while (pads) {
|
||||||
GstPad *pad = GST_PAD (pads->data);
|
GstPad *pad = GST_PAD (pads->data);
|
||||||
|
@ -484,6 +477,7 @@ gst_fakesrc_update_functions (GstFakeSrc * src)
|
||||||
gst_pad_set_get_function (pad, GST_DEBUG_FUNCPTR (gst_fakesrc_get));
|
gst_pad_set_get_function (pad, GST_DEBUG_FUNCPTR (gst_fakesrc_get));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gst_pad_set_activate_function (pad, gst_fakesrc_activate);
|
||||||
gst_pad_set_event_function (pad, gst_fakesrc_event_handler);
|
gst_pad_set_event_function (pad, gst_fakesrc_event_handler);
|
||||||
gst_pad_set_event_mask_function (pad, gst_fakesrc_get_event_mask);
|
gst_pad_set_event_mask_function (pad, gst_fakesrc_get_event_mask);
|
||||||
gst_pad_set_query_function (pad, gst_fakesrc_query);
|
gst_pad_set_query_function (pad, gst_fakesrc_query);
|
||||||
|
@ -790,36 +784,40 @@ gst_fakesrc_create_buffer (GstFakeSrc * src)
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstData *
|
static GstFlowReturn
|
||||||
gst_fakesrc_get (GstPad * pad)
|
gst_fakesrc_get (GstPad * pad, GstBuffer ** buffer)
|
||||||
{
|
{
|
||||||
GstFakeSrc *src;
|
GstFakeSrc *src;
|
||||||
GstBuffer *buf;
|
GstBuffer *buf;
|
||||||
GstClockTime time;
|
GstClockTime time;
|
||||||
|
GstFlowReturn result = GST_FLOW_OK;
|
||||||
|
|
||||||
g_return_val_if_fail (pad != NULL, NULL);
|
g_return_val_if_fail (pad != NULL, GST_FLOW_ERROR);
|
||||||
|
|
||||||
src = GST_FAKESRC (GST_OBJECT_PARENT (pad));
|
src = GST_FAKESRC (GST_OBJECT_PARENT (pad));
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_FAKESRC (src), NULL);
|
g_return_val_if_fail (GST_IS_FAKESRC (src), GST_FLOW_ERROR);
|
||||||
|
|
||||||
|
GST_STREAM_LOCK (pad);
|
||||||
if (src->need_flush) {
|
if (src->need_flush) {
|
||||||
src->need_flush = FALSE;
|
src->need_flush = FALSE;
|
||||||
return GST_DATA (gst_event_new (GST_EVENT_FLUSH));
|
gst_pad_push_event (pad, gst_event_new (GST_EVENT_FLUSH));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src->buffer_count == src->segment_end) {
|
if (src->buffer_count == src->segment_end) {
|
||||||
if (src->segment_loop) {
|
if (src->segment_loop) {
|
||||||
return GST_DATA (gst_event_new (GST_EVENT_SEGMENT_DONE));
|
gst_pad_push_event (pad, gst_event_new (GST_EVENT_SEGMENT_DONE));
|
||||||
} else {
|
} else {
|
||||||
gst_element_set_eos (GST_ELEMENT (src));
|
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||||
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
result = GST_FLOW_UNEXPECTED;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src->rt_num_buffers == 0) {
|
if (src->rt_num_buffers == 0) {
|
||||||
gst_element_set_eos (GST_ELEMENT (src));
|
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||||
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
result = GST_FLOW_UNEXPECTED;
|
||||||
|
goto done;
|
||||||
} else {
|
} else {
|
||||||
if (src->rt_num_buffers > 0)
|
if (src->rt_num_buffers > 0)
|
||||||
src->rt_num_buffers--;
|
src->rt_num_buffers--;
|
||||||
|
@ -827,8 +825,9 @@ gst_fakesrc_get (GstPad * pad)
|
||||||
|
|
||||||
if (src->eos) {
|
if (src->eos) {
|
||||||
GST_INFO ("fakesrc is setting eos on pad");
|
GST_INFO ("fakesrc is setting eos on pad");
|
||||||
gst_element_set_eos (GST_ELEMENT (src));
|
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||||
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
result = GST_FLOW_UNEXPECTED;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = gst_fakesrc_create_buffer (src);
|
buf = gst_fakesrc_create_buffer (src);
|
||||||
|
@ -867,7 +866,12 @@ gst_fakesrc_get (GstPad * pad)
|
||||||
|
|
||||||
src->bytes_sent += GST_BUFFER_SIZE (buf);
|
src->bytes_sent += GST_BUFFER_SIZE (buf);
|
||||||
|
|
||||||
return GST_DATA (buf);
|
*buffer = buf;
|
||||||
|
|
||||||
|
done:
|
||||||
|
GST_STREAM_UNLOCK (pad);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -881,35 +885,82 @@ gst_fakesrc_loop (GstElement * element)
|
||||||
{
|
{
|
||||||
GstFakeSrc *src;
|
GstFakeSrc *src;
|
||||||
const GList *pads;
|
const GList *pads;
|
||||||
|
GstTask *task;
|
||||||
|
|
||||||
g_return_if_fail (element != NULL);
|
g_return_if_fail (element != NULL);
|
||||||
g_return_if_fail (GST_IS_FAKESRC (element));
|
g_return_if_fail (GST_IS_FAKESRC (element));
|
||||||
|
|
||||||
src = GST_FAKESRC (element);
|
src = GST_FAKESRC (element);
|
||||||
|
task = src->task;
|
||||||
|
|
||||||
pads = gst_element_get_pad_list (element);
|
pads = element->pads;
|
||||||
|
|
||||||
while (pads) {
|
while (pads) {
|
||||||
GstPad *pad = GST_PAD (pads->data);
|
GstPad *pad = GST_PAD (pads->data);
|
||||||
GstData *data;
|
GstBuffer *buffer;
|
||||||
|
GstFlowReturn ret;
|
||||||
|
|
||||||
data = gst_fakesrc_get (pad);
|
ret = gst_fakesrc_get (pad, &buffer);
|
||||||
gst_pad_push (pad, data);
|
if (ret != GST_FLOW_OK) {
|
||||||
|
gst_task_stop (task);
|
||||||
if (src->eos) {
|
return;
|
||||||
|
}
|
||||||
|
ret = gst_pad_push (pad, buffer);
|
||||||
|
if (ret != GST_FLOW_OK) {
|
||||||
|
gst_task_stop (task);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (src->eos) {
|
||||||
|
gst_task_stop (task);
|
||||||
|
return;
|
||||||
|
}
|
||||||
pads = g_list_next (pads);
|
pads = g_list_next (pads);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_fakesrc_activate (GstPad * pad, gboolean active)
|
||||||
|
{
|
||||||
|
gboolean result = FALSE;
|
||||||
|
GstFakeSrc *fakesrc;
|
||||||
|
|
||||||
|
fakesrc = GST_FAKESRC (GST_OBJECT_PARENT (pad));
|
||||||
|
|
||||||
|
if (active) {
|
||||||
|
/* if we have a scheduler we can start the task */
|
||||||
|
if (GST_ELEMENT_MANAGER (fakesrc)) {
|
||||||
|
GST_STREAM_LOCK (pad);
|
||||||
|
fakesrc->task =
|
||||||
|
gst_scheduler_create_task (GST_ELEMENT_MANAGER (fakesrc)->scheduler,
|
||||||
|
(GstTaskFunction) gst_fakesrc_loop, fakesrc);
|
||||||
|
|
||||||
|
gst_task_start (fakesrc->task);
|
||||||
|
GST_STREAM_UNLOCK (pad);
|
||||||
|
result = TRUE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* step 1, unblock clock sync (if any) */
|
||||||
|
|
||||||
|
/* step 2, make sure streaming finishes */
|
||||||
|
GST_STREAM_LOCK (pad);
|
||||||
|
/* step 3, stop the task */
|
||||||
|
gst_task_stop (fakesrc->task);
|
||||||
|
gst_object_unref (GST_OBJECT (fakesrc->task));
|
||||||
|
GST_STREAM_UNLOCK (pad);
|
||||||
|
|
||||||
|
result = TRUE;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static GstElementStateReturn
|
static GstElementStateReturn
|
||||||
gst_fakesrc_change_state (GstElement * element)
|
gst_fakesrc_change_state (GstElement * element)
|
||||||
{
|
{
|
||||||
GstFakeSrc *fakesrc;
|
GstFakeSrc *fakesrc;
|
||||||
|
GstElementStateReturn result = GST_STATE_FAILURE;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_FAKESRC (element), GST_STATE_FAILURE);
|
g_return_val_if_fail (GST_IS_FAKESRC (element), result);
|
||||||
|
|
||||||
fakesrc = GST_FAKESRC (element);
|
fakesrc = GST_FAKESRC (element);
|
||||||
|
|
||||||
|
@ -917,6 +968,7 @@ gst_fakesrc_change_state (GstElement * element)
|
||||||
case GST_STATE_NULL_TO_READY:
|
case GST_STATE_NULL_TO_READY:
|
||||||
break;
|
break;
|
||||||
case GST_STATE_READY_TO_PAUSED:
|
case GST_STATE_READY_TO_PAUSED:
|
||||||
|
{
|
||||||
fakesrc->buffer_count = 0;
|
fakesrc->buffer_count = 0;
|
||||||
fakesrc->pattern_byte = 0x00;
|
fakesrc->pattern_byte = 0x00;
|
||||||
fakesrc->need_flush = FALSE;
|
fakesrc->need_flush = FALSE;
|
||||||
|
@ -924,7 +976,14 @@ gst_fakesrc_change_state (GstElement * element)
|
||||||
fakesrc->bytes_sent = 0;
|
fakesrc->bytes_sent = 0;
|
||||||
fakesrc->rt_num_buffers = fakesrc->num_buffers;
|
fakesrc->rt_num_buffers = fakesrc->num_buffers;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case GST_STATE_PAUSED_TO_PLAYING:
|
case GST_STATE_PAUSED_TO_PLAYING:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||||
|
|
||||||
|
switch (GST_STATE_TRANSITION (element)) {
|
||||||
case GST_STATE_PLAYING_TO_PAUSED:
|
case GST_STATE_PLAYING_TO_PAUSED:
|
||||||
break;
|
break;
|
||||||
case GST_STATE_PAUSED_TO_READY:
|
case GST_STATE_PAUSED_TO_READY:
|
||||||
|
@ -941,8 +1000,5 @@ gst_fakesrc_change_state (GstElement * element)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
return result;
|
||||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
|
||||||
|
|
||||||
return GST_STATE_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,8 @@ struct _GstFakeSrc {
|
||||||
gboolean loop_based;
|
gboolean loop_based;
|
||||||
gboolean eos;
|
gboolean eos;
|
||||||
|
|
||||||
|
GstTask *task;
|
||||||
|
|
||||||
GstFakeSrcOutputType output;
|
GstFakeSrcOutputType output;
|
||||||
GstFakeSrcDataType data;
|
GstFakeSrcDataType data;
|
||||||
GstFakeSrcSizeType sizetype;
|
GstFakeSrcSizeType sizetype;
|
||||||
|
|
|
@ -170,11 +170,12 @@ static void gst_filesrc_get_property (GObject * object, guint prop_id,
|
||||||
GValue * value, GParamSpec * pspec);
|
GValue * value, GParamSpec * pspec);
|
||||||
|
|
||||||
static gboolean gst_filesrc_check_filesize (GstFileSrc * src);
|
static gboolean gst_filesrc_check_filesize (GstFileSrc * src);
|
||||||
static GstData *gst_filesrc_get (GstPad * pad);
|
static GstFlowReturn gst_filesrc_get (GstPad * pad, GstBuffer ** buffer);
|
||||||
static gboolean gst_filesrc_srcpad_event (GstPad * pad, GstEvent * event);
|
static gboolean gst_filesrc_srcpad_event (GstPad * pad, GstEvent * event);
|
||||||
static gboolean gst_filesrc_srcpad_query (GstPad * pad, GstQueryType type,
|
static gboolean gst_filesrc_srcpad_query (GstPad * pad, GstQueryType type,
|
||||||
GstFormat * format, gint64 * value);
|
GstFormat * format, gint64 * value);
|
||||||
|
|
||||||
|
static gboolean gst_filesrc_activate (GstPad * pad, gboolean active);
|
||||||
static GstElementStateReturn gst_filesrc_change_state (GstElement * element);
|
static GstElementStateReturn gst_filesrc_change_state (GstElement * element);
|
||||||
|
|
||||||
static void gst_filesrc_uri_handler_init (gpointer g_iface,
|
static void gst_filesrc_uri_handler_init (gpointer g_iface,
|
||||||
|
@ -214,6 +215,8 @@ gst_filesrc_class_init (GstFileSrcClass * klass)
|
||||||
|
|
||||||
gobject_class = (GObjectClass *) klass;
|
gobject_class = (GObjectClass *) klass;
|
||||||
|
|
||||||
|
gobject_class->set_property = gst_filesrc_set_property;
|
||||||
|
gobject_class->get_property = gst_filesrc_get_property;
|
||||||
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FD,
|
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FD,
|
||||||
g_param_spec_int ("fd", "File-descriptor",
|
g_param_spec_int ("fd", "File-descriptor",
|
||||||
|
@ -235,8 +238,6 @@ gst_filesrc_class_init (GstFileSrcClass * klass)
|
||||||
"Touch data to force disk read", FALSE, G_PARAM_READWRITE));
|
"Touch data to force disk read", FALSE, G_PARAM_READWRITE));
|
||||||
|
|
||||||
gobject_class->dispose = gst_filesrc_dispose;
|
gobject_class->dispose = gst_filesrc_dispose;
|
||||||
gobject_class->set_property = gst_filesrc_set_property;
|
|
||||||
gobject_class->get_property = gst_filesrc_get_property;
|
|
||||||
|
|
||||||
gstelement_class->change_state = gst_filesrc_change_state;
|
gstelement_class->change_state = gst_filesrc_change_state;
|
||||||
}
|
}
|
||||||
|
@ -248,6 +249,7 @@ gst_filesrc_init (GstFileSrc * src)
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
|
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
|
||||||
"src");
|
"src");
|
||||||
gst_pad_set_get_function (src->srcpad, gst_filesrc_get);
|
gst_pad_set_get_function (src->srcpad, gst_filesrc_get);
|
||||||
|
gst_pad_set_activate_function (src->srcpad, gst_filesrc_activate);
|
||||||
gst_pad_set_event_function (src->srcpad, gst_filesrc_srcpad_event);
|
gst_pad_set_event_function (src->srcpad, gst_filesrc_srcpad_event);
|
||||||
gst_pad_set_event_mask_function (src->srcpad, gst_filesrc_get_event_mask);
|
gst_pad_set_event_mask_function (src->srcpad, gst_filesrc_get_event_mask);
|
||||||
gst_pad_set_query_function (src->srcpad, gst_filesrc_srcpad_query);
|
gst_pad_set_query_function (src->srcpad, gst_filesrc_srcpad_query);
|
||||||
|
@ -672,7 +674,7 @@ gst_filesrc_get_read (GstFileSrc * src)
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
GST_DEBUG ("non-regular file hits EOS");
|
GST_DEBUG ("non-regular file hits EOS");
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
gst_element_set_eos (GST_ELEMENT (src));
|
//gst_element_set_eos (GST_ELEMENT (src));
|
||||||
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
||||||
}
|
}
|
||||||
readsize = ret;
|
readsize = ret;
|
||||||
|
@ -686,20 +688,22 @@ gst_filesrc_get_read (GstFileSrc * src)
|
||||||
return GST_DATA (buf);
|
return GST_DATA (buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstData *
|
static GstFlowReturn
|
||||||
gst_filesrc_get (GstPad * pad)
|
gst_filesrc_get (GstPad * pad, GstBuffer ** buffer)
|
||||||
{
|
{
|
||||||
GstFileSrc *src;
|
GstFileSrc *src;
|
||||||
|
GstData *data;
|
||||||
|
|
||||||
g_return_val_if_fail (pad != NULL, NULL);
|
|
||||||
src = GST_FILESRC (gst_pad_get_parent (pad));
|
src = GST_FILESRC (gst_pad_get_parent (pad));
|
||||||
g_return_val_if_fail (GST_FLAG_IS_SET (src, GST_FILESRC_OPEN), NULL);
|
|
||||||
|
g_return_val_if_fail (GST_FLAG_IS_SET (src, GST_FILESRC_OPEN),
|
||||||
|
GST_FLOW_WRONG_STATE);
|
||||||
|
|
||||||
/* check for flush */
|
/* check for flush */
|
||||||
if (src->need_flush) {
|
if (src->need_flush) {
|
||||||
src->need_flush = FALSE;
|
src->need_flush = FALSE;
|
||||||
GST_DEBUG_OBJECT (src, "sending flush");
|
GST_DEBUG_OBJECT (src, "sending flush");
|
||||||
return GST_DATA (gst_event_new_flush ());
|
gst_pad_push_event (pad, gst_event_new_flush ());
|
||||||
}
|
}
|
||||||
/* check for seek */
|
/* check for seek */
|
||||||
if (src->need_discont) {
|
if (src->need_discont) {
|
||||||
|
@ -710,7 +714,7 @@ gst_filesrc_get (GstPad * pad)
|
||||||
gst_event_new_discontinuous (src->need_discont > 1, GST_FORMAT_BYTES,
|
gst_event_new_discontinuous (src->need_discont > 1, GST_FORMAT_BYTES,
|
||||||
(guint64) src->curoffset, GST_FORMAT_UNDEFINED);
|
(guint64) src->curoffset, GST_FORMAT_UNDEFINED);
|
||||||
src->need_discont = 0;
|
src->need_discont = 0;
|
||||||
return GST_DATA (event);
|
gst_pad_push_event (pad, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check for EOF if it's a regular file */
|
/* check for EOF if it's a regular file */
|
||||||
|
@ -721,20 +725,31 @@ gst_filesrc_get (GstPad * pad)
|
||||||
GST_DEBUG_OBJECT (src, "eos %" G_GINT64_FORMAT " %" G_GINT64_FORMAT,
|
GST_DEBUG_OBJECT (src, "eos %" G_GINT64_FORMAT " %" G_GINT64_FORMAT,
|
||||||
src->curoffset, src->filelen);
|
src->curoffset, src->filelen);
|
||||||
}
|
}
|
||||||
gst_element_set_eos (GST_ELEMENT (src));
|
//gst_element_set_eos (GST_ELEMENT (src));
|
||||||
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||||
|
return GST_FLOW_WRONG_STATE;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef HAVE_MMAP
|
#ifdef HAVE_MMAP
|
||||||
if (src->using_mmap) {
|
if (src->using_mmap) {
|
||||||
return gst_filesrc_get_mmap (src);
|
data = gst_filesrc_get_mmap (src);
|
||||||
} else {
|
} else {
|
||||||
return gst_filesrc_get_read (src);
|
data = gst_filesrc_get_read (src);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
return gst_filesrc_get_read (src);
|
data = gst_filesrc_get_read (src);
|
||||||
#endif
|
#endif
|
||||||
|
if (data == NULL)
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
|
||||||
|
if (GST_IS_EVENT (data)) {
|
||||||
|
gst_pad_push_event (pad, GST_EVENT (data));
|
||||||
|
} else {
|
||||||
|
*buffer = GST_BUFFER (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TRUE if the filesize of the file was updated */
|
/* TRUE if the filesize of the file was updated */
|
||||||
|
@ -848,10 +863,69 @@ gst_filesrc_close_file (GstFileSrc * src)
|
||||||
GST_FLAG_UNSET (src, GST_FILESRC_OPEN);
|
GST_FLAG_UNSET (src, GST_FILESRC_OPEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_filesrc_loop (GstElement * element)
|
||||||
|
{
|
||||||
|
GstFileSrc *filesrc;
|
||||||
|
GstFlowReturn result;
|
||||||
|
GstBuffer *buffer;
|
||||||
|
|
||||||
|
filesrc = GST_FILESRC (element);
|
||||||
|
|
||||||
|
result = gst_filesrc_get (filesrc->srcpad, &buffer);
|
||||||
|
if (result != GST_FLOW_OK) {
|
||||||
|
gst_task_stop (filesrc->task);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
result = gst_pad_push (filesrc->srcpad, buffer);
|
||||||
|
if (result != GST_FLOW_OK) {
|
||||||
|
gst_task_stop (filesrc->task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_filesrc_activate (GstPad * pad, gboolean active)
|
||||||
|
{
|
||||||
|
gboolean result = FALSE;
|
||||||
|
GstFileSrc *filesrc;
|
||||||
|
|
||||||
|
filesrc = GST_FILESRC (GST_OBJECT_PARENT (pad));
|
||||||
|
|
||||||
|
if (active) {
|
||||||
|
/* try to start the task */
|
||||||
|
GST_STREAM_LOCK (pad);
|
||||||
|
filesrc->task = gst_element_create_task (GST_ELEMENT (filesrc),
|
||||||
|
(GstTaskFunction) gst_filesrc_loop, filesrc);
|
||||||
|
|
||||||
|
if (filesrc->task) {
|
||||||
|
gst_task_start (filesrc->task);
|
||||||
|
result = TRUE;
|
||||||
|
} else {
|
||||||
|
result = FALSE;
|
||||||
|
}
|
||||||
|
GST_STREAM_UNLOCK (pad);
|
||||||
|
} else {
|
||||||
|
/* step 1, unblock clock sync (if any) */
|
||||||
|
|
||||||
|
/* step 2, make sure streaming finishes */
|
||||||
|
GST_STREAM_LOCK (pad);
|
||||||
|
/* step 3, stop the task */
|
||||||
|
gst_task_stop (filesrc->task);
|
||||||
|
gst_object_unref (GST_OBJECT (filesrc->task));
|
||||||
|
GST_STREAM_UNLOCK (pad);
|
||||||
|
|
||||||
|
result = TRUE;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static GstElementStateReturn
|
static GstElementStateReturn
|
||||||
gst_filesrc_change_state (GstElement * element)
|
gst_filesrc_change_state (GstElement * element)
|
||||||
{
|
{
|
||||||
|
GstElementStateReturn result = GST_STATE_SUCCESS;
|
||||||
|
|
||||||
GstFileSrc *src = GST_FILESRC (element);
|
GstFileSrc *src = GST_FILESRC (element);
|
||||||
|
|
||||||
switch (GST_STATE_TRANSITION (element)) {
|
switch (GST_STATE_TRANSITION (element)) {
|
||||||
|
@ -865,6 +939,16 @@ gst_filesrc_change_state (GstElement * element)
|
||||||
return GST_STATE_FAILURE;
|
return GST_STATE_FAILURE;
|
||||||
}
|
}
|
||||||
src->need_discont = 2;
|
src->need_discont = 2;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case GST_STATE_PAUSED_TO_PLAYING:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||||
|
|
||||||
|
switch (GST_STATE_TRANSITION (element)) {
|
||||||
|
case GST_STATE_PLAYING_TO_PAUSED:
|
||||||
break;
|
break;
|
||||||
case GST_STATE_PAUSED_TO_READY:
|
case GST_STATE_PAUSED_TO_READY:
|
||||||
if (GST_FLAG_IS_SET (element, GST_FILESRC_OPEN))
|
if (GST_FLAG_IS_SET (element, GST_FILESRC_OPEN))
|
||||||
|
@ -874,10 +958,7 @@ gst_filesrc_change_state (GstElement * element)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
return result;
|
||||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
|
||||||
|
|
||||||
return GST_STATE_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
|
|
@ -69,6 +69,8 @@ struct _GstFileSrc {
|
||||||
gboolean is_regular; /* whether it's (symlink to)
|
gboolean is_regular; /* whether it's (symlink to)
|
||||||
a regular file */
|
a regular file */
|
||||||
|
|
||||||
|
GstTask *task;
|
||||||
|
|
||||||
GstBuffer *mapbuf;
|
GstBuffer *mapbuf;
|
||||||
size_t mapsize;
|
size_t mapsize;
|
||||||
|
|
||||||
|
|
|
@ -99,7 +99,8 @@ static void gst_identity_get_property (GObject * object, guint prop_id,
|
||||||
GValue * value, GParamSpec * pspec);
|
GValue * value, GParamSpec * pspec);
|
||||||
static GstElementStateReturn gst_identity_change_state (GstElement * element);
|
static GstElementStateReturn gst_identity_change_state (GstElement * element);
|
||||||
|
|
||||||
static void gst_identity_chain (GstPad * pad, GstData * _data);
|
static gboolean gst_identity_event (GstPad * pad, GstEvent * event);
|
||||||
|
static GstFlowReturn gst_identity_chain (GstPad * pad, GstBuffer * buffer);
|
||||||
static void gst_identity_set_clock (GstElement * element, GstClock * clock);
|
static void gst_identity_set_clock (GstElement * element, GstClock * clock);
|
||||||
|
|
||||||
|
|
||||||
|
@ -138,6 +139,9 @@ gst_identity_class_init (GstIdentityClass * klass)
|
||||||
gobject_class = G_OBJECT_CLASS (klass);
|
gobject_class = G_OBJECT_CLASS (klass);
|
||||||
gstelement_class = GST_ELEMENT_CLASS (klass);
|
gstelement_class = GST_ELEMENT_CLASS (klass);
|
||||||
|
|
||||||
|
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_identity_set_property);
|
||||||
|
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_identity_get_property);
|
||||||
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOOP_BASED,
|
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOOP_BASED,
|
||||||
g_param_spec_boolean ("loop-based", "Loop-based",
|
g_param_spec_boolean ("loop-based", "Loop-based",
|
||||||
"Set to TRUE to use loop-based rather than chain-based scheduling",
|
"Set to TRUE to use loop-based rather than chain-based scheduling",
|
||||||
|
@ -185,8 +189,6 @@ gst_identity_class_init (GstIdentityClass * klass)
|
||||||
GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE);
|
GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE);
|
||||||
|
|
||||||
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_identity_finalize);
|
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_identity_finalize);
|
||||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_identity_set_property);
|
|
||||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_identity_get_property);
|
|
||||||
|
|
||||||
gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_identity_set_clock);
|
gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_identity_set_clock);
|
||||||
gstelement_class->change_state =
|
gstelement_class->change_state =
|
||||||
|
@ -203,15 +205,13 @@ gst_identity_init (GstIdentity * identity)
|
||||||
gst_element_add_pad (GST_ELEMENT (identity), identity->sinkpad);
|
gst_element_add_pad (GST_ELEMENT (identity), identity->sinkpad);
|
||||||
gst_pad_set_chain_function (identity->sinkpad,
|
gst_pad_set_chain_function (identity->sinkpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_identity_chain));
|
GST_DEBUG_FUNCPTR (gst_identity_chain));
|
||||||
gst_pad_set_link_function (identity->sinkpad, gst_pad_proxy_pad_link);
|
gst_pad_set_event_function (identity->sinkpad,
|
||||||
gst_pad_set_getcaps_function (identity->sinkpad, gst_pad_proxy_getcaps);
|
GST_DEBUG_FUNCPTR (gst_identity_event));
|
||||||
|
|
||||||
identity->srcpad =
|
identity->srcpad =
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
|
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
|
||||||
"src");
|
"src");
|
||||||
gst_element_add_pad (GST_ELEMENT (identity), identity->srcpad);
|
gst_element_add_pad (GST_ELEMENT (identity), identity->srcpad);
|
||||||
gst_pad_set_link_function (identity->srcpad, gst_pad_proxy_pad_link);
|
|
||||||
gst_pad_set_getcaps_function (identity->srcpad, gst_pad_proxy_getcaps);
|
|
||||||
|
|
||||||
identity->loop_based = DEFAULT_LOOP_BASED;
|
identity->loop_based = DEFAULT_LOOP_BASED;
|
||||||
identity->sleep_time = DEFAULT_SLEEP_TIME;
|
identity->sleep_time = DEFAULT_SLEEP_TIME;
|
||||||
|
@ -225,8 +225,6 @@ gst_identity_init (GstIdentity * identity)
|
||||||
identity->dump = DEFAULT_DUMP;
|
identity->dump = DEFAULT_DUMP;
|
||||||
identity->last_message = NULL;
|
identity->last_message = NULL;
|
||||||
identity->srccaps = NULL;
|
identity->srccaps = NULL;
|
||||||
|
|
||||||
GST_FLAG_SET (identity, GST_ELEMENT_EVENT_AWARE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -237,35 +235,37 @@ gst_identity_set_clock (GstElement * element, GstClock * clock)
|
||||||
gst_object_replace ((GstObject **) & identity->clock, (GstObject *) clock);
|
gst_object_replace ((GstObject **) & identity->clock, (GstObject *) clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
static void
|
gst_identity_event (GstPad * pad, GstEvent * event)
|
||||||
gst_identity_chain (GstPad * pad, GstData * _data)
|
|
||||||
{
|
{
|
||||||
GstBuffer *buf = GST_BUFFER (_data);
|
|
||||||
GstIdentity *identity;
|
GstIdentity *identity;
|
||||||
guint i;
|
|
||||||
|
|
||||||
g_return_if_fail (pad != NULL);
|
|
||||||
g_return_if_fail (GST_IS_PAD (pad));
|
|
||||||
g_return_if_fail (buf != NULL);
|
|
||||||
|
|
||||||
identity = GST_IDENTITY (gst_pad_get_parent (pad));
|
identity = GST_IDENTITY (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
if (GST_IS_EVENT (buf)) {
|
if (!identity->silent) {
|
||||||
GstEvent *event = GST_EVENT (buf);
|
g_free (identity->last_message);
|
||||||
|
|
||||||
if (!identity->silent) {
|
identity->last_message =
|
||||||
g_free (identity->last_message);
|
g_strdup_printf ("chain ******* (%s:%s)E (type: %d) %p",
|
||||||
|
GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event);
|
||||||
|
|
||||||
identity->last_message =
|
g_object_notify (G_OBJECT (identity), "last_message");
|
||||||
g_strdup_printf ("chain ******* (%s:%s)E (type: %d) %p",
|
|
||||||
GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event);
|
|
||||||
|
|
||||||
g_object_notify (G_OBJECT (identity), "last_message");
|
|
||||||
}
|
|
||||||
gst_pad_event_default (pad, event);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
return gst_pad_push_event (identity->srcpad, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_identity_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
|
{
|
||||||
|
GstBuffer *buf = GST_BUFFER (buffer);
|
||||||
|
GstIdentity *identity;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
g_return_val_if_fail (pad != NULL, GST_FLOW_ERROR);
|
||||||
|
g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR);
|
||||||
|
g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
|
||||||
|
|
||||||
|
identity = GST_IDENTITY (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
/* see if we need to do perfect stream checking */
|
/* see if we need to do perfect stream checking */
|
||||||
/* invalid timestamp drops us out of check. FIXME: maybe warn ? */
|
/* invalid timestamp drops us out of check. FIXME: maybe warn ? */
|
||||||
|
@ -302,7 +302,7 @@ gst_identity_chain (GstPad * pad, GstData * _data)
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
GST_ELEMENT_ERROR (identity, CORE, FAILED,
|
GST_ELEMENT_ERROR (identity, CORE, FAILED,
|
||||||
(_("Failed after iterations as requested.")), (NULL));
|
(_("Failed after iterations as requested.")), (NULL));
|
||||||
return;
|
return GST_FLOW_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,7 +319,7 @@ gst_identity_chain (GstPad * pad, GstData * _data)
|
||||||
GST_BUFFER_OFFSET_END (buf), GST_BUFFER_FLAGS (buf), buf);
|
GST_BUFFER_OFFSET_END (buf), GST_BUFFER_FLAGS (buf), buf);
|
||||||
g_object_notify (G_OBJECT (identity), "last-message");
|
g_object_notify (G_OBJECT (identity), "last-message");
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
return;
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (identity->dump) {
|
if (identity->dump) {
|
||||||
|
@ -365,37 +365,33 @@ gst_identity_chain (GstPad * pad, GstData * _data)
|
||||||
}
|
}
|
||||||
|
|
||||||
identity->bytes_handled += GST_BUFFER_SIZE (buf);
|
identity->bytes_handled += GST_BUFFER_SIZE (buf);
|
||||||
gst_pad_push (identity->srcpad, GST_DATA (buf));
|
gst_pad_push (identity->srcpad, buf);
|
||||||
|
|
||||||
if (identity->sleep_time)
|
if (identity->sleep_time)
|
||||||
g_usleep (identity->sleep_time);
|
g_usleep (identity->sleep_time);
|
||||||
}
|
}
|
||||||
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
static void
|
static void
|
||||||
gst_identity_loop (GstElement * element)
|
gst_identity_loop (GstElement * element)
|
||||||
{
|
{
|
||||||
GstIdentity *identity;
|
GstIdentity *identity;
|
||||||
GstBuffer *buf;
|
GstBuffer *buf;
|
||||||
|
GstFlowReturn ret;
|
||||||
|
|
||||||
g_return_if_fail (element != NULL);
|
g_return_if_fail (element != NULL);
|
||||||
g_return_if_fail (GST_IS_IDENTITY (element));
|
g_return_if_fail (GST_IS_IDENTITY (element));
|
||||||
|
|
||||||
identity = GST_IDENTITY (element);
|
identity = GST_IDENTITY (element);
|
||||||
|
|
||||||
buf = GST_BUFFER (gst_pad_pull (identity->sinkpad));
|
ret = gst_pad_pull (identity->sinkpad, &buf);
|
||||||
if (GST_IS_EVENT (buf)) {
|
if (ret == GST_FLOW_OK) {
|
||||||
GstEvent *event = GST_EVENT (buf);
|
gst_identity_chain (identity->sinkpad, buf);
|
||||||
|
|
||||||
if (GST_EVENT_IS_INTERRUPT (event)) {
|
|
||||||
gst_event_unref (event);
|
|
||||||
} else {
|
|
||||||
gst_pad_event_default (identity->sinkpad, event);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
gst_identity_chain (identity->sinkpad, GST_DATA (buf));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_identity_set_property (GObject * object, guint prop_id,
|
gst_identity_set_property (GObject * object, guint prop_id,
|
||||||
|
@ -412,12 +408,9 @@ gst_identity_set_property (GObject * object, guint prop_id,
|
||||||
case ARG_LOOP_BASED:
|
case ARG_LOOP_BASED:
|
||||||
identity->loop_based = g_value_get_boolean (value);
|
identity->loop_based = g_value_get_boolean (value);
|
||||||
if (identity->loop_based) {
|
if (identity->loop_based) {
|
||||||
gst_element_set_loop_function (GST_ELEMENT (identity),
|
|
||||||
gst_identity_loop);
|
|
||||||
gst_pad_set_chain_function (identity->sinkpad, NULL);
|
gst_pad_set_chain_function (identity->sinkpad, NULL);
|
||||||
} else {
|
} else {
|
||||||
gst_pad_set_chain_function (identity->sinkpad, gst_identity_chain);
|
gst_pad_set_chain_function (identity->sinkpad, gst_identity_chain);
|
||||||
gst_element_set_loop_function (GST_ELEMENT (identity), NULL);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ARG_SLEEP_TIME:
|
case ARG_SLEEP_TIME:
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include "gstqueue.h"
|
#include "gstqueue.h"
|
||||||
#include "gstscheduler.h"
|
#include "gstscheduler.h"
|
||||||
|
#include "gstpipeline.h"
|
||||||
#include "gstevent.h"
|
#include "gstevent.h"
|
||||||
#include "gstinfo.h"
|
#include "gstinfo.h"
|
||||||
#include "gsterror.h"
|
#include "gsterror.h"
|
||||||
|
@ -41,6 +42,24 @@ static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_STATIC_CAPS_ANY);
|
GST_STATIC_CAPS_ANY);
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_STATIC (queue_dataflow);
|
GST_DEBUG_CATEGORY_STATIC (queue_dataflow);
|
||||||
|
#define GST_CAT_DEFAULT (queue_dataflow)
|
||||||
|
|
||||||
|
#define STATUS(queue, msg) \
|
||||||
|
GST_CAT_LOG_OBJECT (queue_dataflow, queue, \
|
||||||
|
"(%s:%s) " msg ": %u of %u-%u buffers, %u of %u-%u " \
|
||||||
|
"bytes, %" G_GUINT64_FORMAT " of %" G_GUINT64_FORMAT \
|
||||||
|
"-%" G_GUINT64_FORMAT " ns, %u elements", \
|
||||||
|
GST_DEBUG_PAD_NAME (pad), \
|
||||||
|
queue->cur_level.buffers, \
|
||||||
|
queue->min_threshold.buffers, \
|
||||||
|
queue->max_size.buffers, \
|
||||||
|
queue->cur_level.bytes, \
|
||||||
|
queue->min_threshold.bytes, \
|
||||||
|
queue->max_size.bytes, \
|
||||||
|
queue->cur_level.time, \
|
||||||
|
queue->min_threshold.time, \
|
||||||
|
queue->max_size.time, \
|
||||||
|
queue->queue->length)
|
||||||
|
|
||||||
static GstElementDetails gst_queue_details = GST_ELEMENT_DETAILS ("Queue",
|
static GstElementDetails gst_queue_details = GST_ELEMENT_DETAILS ("Queue",
|
||||||
"Generic",
|
"Generic",
|
||||||
|
@ -95,13 +114,6 @@ enum
|
||||||
} G_STMT_END
|
} G_STMT_END
|
||||||
|
|
||||||
|
|
||||||
typedef struct _GstQueueEventResponse
|
|
||||||
{
|
|
||||||
GstEvent *event;
|
|
||||||
gboolean ret, handled;
|
|
||||||
}
|
|
||||||
GstQueueEventResponse;
|
|
||||||
|
|
||||||
static void gst_queue_base_init (GstQueueClass * klass);
|
static void gst_queue_base_init (GstQueueClass * klass);
|
||||||
static void gst_queue_class_init (GstQueueClass * klass);
|
static void gst_queue_class_init (GstQueueClass * klass);
|
||||||
static void gst_queue_init (GstQueue * queue);
|
static void gst_queue_init (GstQueue * queue);
|
||||||
|
@ -112,19 +124,24 @@ static void gst_queue_set_property (GObject * object,
|
||||||
static void gst_queue_get_property (GObject * object,
|
static void gst_queue_get_property (GObject * object,
|
||||||
guint prop_id, GValue * value, GParamSpec * pspec);
|
guint prop_id, GValue * value, GParamSpec * pspec);
|
||||||
|
|
||||||
static void gst_queue_chain (GstPad * pad, GstData * data);
|
static GstFlowReturn gst_queue_chain (GstPad * pad, GstBuffer * buffer);
|
||||||
static GstData *gst_queue_get (GstPad * pad);
|
static GstFlowReturn gst_queue_get (GstPad * pad, GstBuffer ** buffer);
|
||||||
|
static GstBuffer *gst_queue_bufferalloc (GstPad * pad, guint64 offset,
|
||||||
|
guint size, GstCaps * caps);
|
||||||
|
|
||||||
|
static gboolean gst_queue_handle_sink_event (GstPad * pad, GstEvent * event);
|
||||||
|
|
||||||
static gboolean gst_queue_handle_src_event (GstPad * pad, GstEvent * event);
|
static gboolean gst_queue_handle_src_event (GstPad * pad, GstEvent * event);
|
||||||
static gboolean gst_queue_handle_src_query (GstPad * pad,
|
static gboolean gst_queue_handle_src_query (GstPad * pad,
|
||||||
GstQueryType type, GstFormat * fmt, gint64 * value);
|
GstQueryType type, GstFormat * fmt, gint64 * value);
|
||||||
|
|
||||||
static GstCaps *gst_queue_getcaps (GstPad * pad);
|
static GstCaps *gst_queue_getcaps (GstPad * pad);
|
||||||
static GstPadLinkReturn gst_queue_link (GstPad * pad, const GstCaps * caps);
|
static GstPadLinkReturn gst_queue_link_sink (GstPad * pad, GstPad * peer);
|
||||||
|
static GstPadLinkReturn gst_queue_link_src (GstPad * pad, GstPad * peer);
|
||||||
static void gst_queue_locked_flush (GstQueue * queue);
|
static void gst_queue_locked_flush (GstQueue * queue);
|
||||||
|
|
||||||
|
static gboolean gst_queue_src_activate (GstPad * pad, gboolean active);
|
||||||
static GstElementStateReturn gst_queue_change_state (GstElement * element);
|
static GstElementStateReturn gst_queue_change_state (GstElement * element);
|
||||||
static gboolean gst_queue_release_locks (GstElement * element);
|
|
||||||
|
|
||||||
|
|
||||||
#define GST_TYPE_QUEUE_LEAKY (queue_leaky_get_type ())
|
#define GST_TYPE_QUEUE_LEAKY (queue_leaky_get_type ())
|
||||||
|
@ -197,6 +214,9 @@ gst_queue_class_init (GstQueueClass * klass)
|
||||||
|
|
||||||
parent_class = g_type_class_peek_parent (klass);
|
parent_class = g_type_class_peek_parent (klass);
|
||||||
|
|
||||||
|
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_queue_set_property);
|
||||||
|
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_queue_get_property);
|
||||||
|
|
||||||
/* signals */
|
/* signals */
|
||||||
gst_queue_signals[SIGNAL_UNDERRUN] =
|
gst_queue_signals[SIGNAL_UNDERRUN] =
|
||||||
g_signal_new ("underrun", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST,
|
g_signal_new ("underrun", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST,
|
||||||
|
@ -267,45 +287,43 @@ gst_queue_class_init (GstQueueClass * klass)
|
||||||
|
|
||||||
/* set several parent class virtual functions */
|
/* set several parent class virtual functions */
|
||||||
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_queue_finalize);
|
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_queue_finalize);
|
||||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_queue_set_property);
|
|
||||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_queue_get_property);
|
|
||||||
|
|
||||||
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_queue_change_state);
|
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_queue_change_state);
|
||||||
gstelement_class->release_locks = GST_DEBUG_FUNCPTR (gst_queue_release_locks);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_queue_init (GstQueue * queue)
|
gst_queue_init (GstQueue * queue)
|
||||||
{
|
{
|
||||||
/* scheduling on this kind of element is, well, interesting */
|
|
||||||
GST_FLAG_SET (queue, GST_ELEMENT_DECOUPLED);
|
|
||||||
GST_FLAG_SET (queue, GST_ELEMENT_EVENT_AWARE);
|
|
||||||
|
|
||||||
queue->sinkpad =
|
queue->sinkpad =
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
|
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
|
||||||
"sink");
|
"sink");
|
||||||
gst_pad_set_chain_function (queue->sinkpad,
|
gst_pad_set_chain_function (queue->sinkpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_queue_chain));
|
GST_DEBUG_FUNCPTR (gst_queue_chain));
|
||||||
gst_element_add_pad (GST_ELEMENT (queue), queue->sinkpad);
|
gst_pad_set_event_function (queue->sinkpad,
|
||||||
|
GST_DEBUG_FUNCPTR (gst_queue_handle_sink_event));
|
||||||
gst_pad_set_link_function (queue->sinkpad,
|
gst_pad_set_link_function (queue->sinkpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_queue_link));
|
GST_DEBUG_FUNCPTR (gst_queue_link_sink));
|
||||||
gst_pad_set_getcaps_function (queue->sinkpad,
|
gst_pad_set_getcaps_function (queue->sinkpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_queue_getcaps));
|
GST_DEBUG_FUNCPTR (gst_queue_getcaps));
|
||||||
gst_pad_set_active (queue->sinkpad, TRUE);
|
gst_pad_set_bufferalloc_function (queue->sinkpad,
|
||||||
|
GST_DEBUG_FUNCPTR (gst_queue_bufferalloc));
|
||||||
|
gst_element_add_pad (GST_ELEMENT (queue), queue->sinkpad);
|
||||||
|
|
||||||
queue->srcpad =
|
queue->srcpad =
|
||||||
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
|
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
|
||||||
"src");
|
"src");
|
||||||
gst_pad_set_get_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_get));
|
gst_pad_set_get_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_get));
|
||||||
gst_element_add_pad (GST_ELEMENT (queue), queue->srcpad);
|
gst_pad_set_activate_function (queue->srcpad,
|
||||||
gst_pad_set_link_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_link));
|
GST_DEBUG_FUNCPTR (gst_queue_src_activate));
|
||||||
|
gst_pad_set_link_function (queue->srcpad,
|
||||||
|
GST_DEBUG_FUNCPTR (gst_queue_link_src));
|
||||||
gst_pad_set_getcaps_function (queue->srcpad,
|
gst_pad_set_getcaps_function (queue->srcpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_queue_getcaps));
|
GST_DEBUG_FUNCPTR (gst_queue_getcaps));
|
||||||
gst_pad_set_event_function (queue->srcpad,
|
gst_pad_set_event_function (queue->srcpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_queue_handle_src_event));
|
GST_DEBUG_FUNCPTR (gst_queue_handle_src_event));
|
||||||
gst_pad_set_query_function (queue->srcpad,
|
gst_pad_set_query_function (queue->srcpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_queue_handle_src_query));
|
GST_DEBUG_FUNCPTR (gst_queue_handle_src_query));
|
||||||
gst_pad_set_active (queue->srcpad, TRUE);
|
gst_element_add_pad (GST_ELEMENT (queue), queue->srcpad);
|
||||||
|
|
||||||
queue->cur_level.buffers = 0; /* no content */
|
queue->cur_level.buffers = 0; /* no content */
|
||||||
queue->cur_level.bytes = 0; /* no content */
|
queue->cur_level.bytes = 0; /* no content */
|
||||||
|
@ -326,9 +344,6 @@ gst_queue_init (GstQueue * queue)
|
||||||
queue->qlock = g_mutex_new ();
|
queue->qlock = g_mutex_new ();
|
||||||
queue->item_add = g_cond_new ();
|
queue->item_add = g_cond_new ();
|
||||||
queue->item_del = g_cond_new ();
|
queue->item_del = g_cond_new ();
|
||||||
queue->event_done = g_cond_new ();
|
|
||||||
queue->events = g_queue_new ();
|
|
||||||
queue->event_lock = g_mutex_new ();
|
|
||||||
queue->queue = g_queue_new ();
|
queue->queue = g_queue_new ();
|
||||||
|
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_THREAD, queue,
|
GST_CAT_DEBUG_OBJECT (GST_CAT_THREAD, queue,
|
||||||
|
@ -349,19 +364,11 @@ gst_queue_finalize (GObject * object)
|
||||||
gst_data_unref (data);
|
gst_data_unref (data);
|
||||||
}
|
}
|
||||||
g_queue_free (queue->queue);
|
g_queue_free (queue->queue);
|
||||||
|
GST_CAT_DEBUG_OBJECT (GST_CAT_THREAD, queue, "free mutex");
|
||||||
g_mutex_free (queue->qlock);
|
g_mutex_free (queue->qlock);
|
||||||
|
GST_CAT_DEBUG_OBJECT (GST_CAT_THREAD, queue, "done free mutex");
|
||||||
g_cond_free (queue->item_add);
|
g_cond_free (queue->item_add);
|
||||||
g_cond_free (queue->item_del);
|
g_cond_free (queue->item_del);
|
||||||
g_cond_free (queue->event_done);
|
|
||||||
g_mutex_lock (queue->event_lock);
|
|
||||||
while (!g_queue_is_empty (queue->events)) {
|
|
||||||
GstQueueEventResponse *er = g_queue_pop_head (queue->events);
|
|
||||||
|
|
||||||
gst_event_unref (er->event);
|
|
||||||
}
|
|
||||||
g_mutex_unlock (queue->event_lock);
|
|
||||||
g_mutex_free (queue->event_lock);
|
|
||||||
g_queue_free (queue->events);
|
|
||||||
|
|
||||||
if (G_OBJECT_CLASS (parent_class)->finalize)
|
if (G_OBJECT_CLASS (parent_class)->finalize)
|
||||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
|
@ -371,42 +378,55 @@ static GstCaps *
|
||||||
gst_queue_getcaps (GstPad * pad)
|
gst_queue_getcaps (GstPad * pad)
|
||||||
{
|
{
|
||||||
GstQueue *queue;
|
GstQueue *queue;
|
||||||
|
GstPad *otherpad, *otherpeer;
|
||||||
|
|
||||||
queue = GST_QUEUE (gst_pad_get_parent (pad));
|
queue = GST_QUEUE (gst_object_get_parent (GST_OBJECT (pad)));
|
||||||
|
|
||||||
if (queue->cur_level.bytes > 0) {
|
otherpad = (pad == queue->srcpad ? queue->sinkpad : queue->srcpad);
|
||||||
return gst_caps_copy (queue->negotiated_caps);
|
otherpeer = gst_pad_get_peer (otherpad);
|
||||||
|
if (otherpeer == NULL) {
|
||||||
|
return gst_pad_get_caps (otherpad);
|
||||||
|
} else {
|
||||||
|
return gst_pad_get_caps (otherpeer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return gst_pad_proxy_getcaps (pad);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstPadLinkReturn
|
static GstPadLinkReturn
|
||||||
gst_queue_link (GstPad * pad, const GstCaps * caps)
|
gst_queue_link_sink (GstPad * pad, GstPad * peer)
|
||||||
|
{
|
||||||
|
return GST_PAD_LINK_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstPadLinkReturn
|
||||||
|
gst_queue_link_src (GstPad * pad, GstPad * peer)
|
||||||
|
{
|
||||||
|
GstPadLinkReturn result = GST_PAD_LINK_OK;
|
||||||
|
|
||||||
|
/* FIXME, see if we need to push or get pulled */
|
||||||
|
if (GST_RPAD_LINKFUNC (peer))
|
||||||
|
result = GST_RPAD_LINKFUNC (peer) (peer, pad);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstBuffer *
|
||||||
|
gst_queue_bufferalloc (GstPad * pad, guint64 offset, guint size, GstCaps * caps)
|
||||||
{
|
{
|
||||||
GstQueue *queue;
|
GstQueue *queue;
|
||||||
GstPadLinkReturn link_ret;
|
GstPad *otherpeer;
|
||||||
|
|
||||||
queue = GST_QUEUE (gst_pad_get_parent (pad));
|
queue = GST_QUEUE (gst_object_get_parent (GST_OBJECT (pad)));
|
||||||
|
|
||||||
if (queue->cur_level.bytes > 0) {
|
otherpeer = gst_pad_get_peer (queue->srcpad);
|
||||||
if (gst_caps_is_equal (caps, queue->negotiated_caps)) {
|
if (otherpeer == NULL || GST_RPAD_BUFFERALLOCFUNC (otherpeer) == NULL) {
|
||||||
return GST_PAD_LINK_OK;
|
/* let the default aloc function do the work */
|
||||||
}
|
return NULL;
|
||||||
return GST_PAD_LINK_REFUSED;
|
} else {
|
||||||
|
return GST_RPAD_BUFFERALLOCFUNC (otherpeer) (otherpeer, offset, size, caps);
|
||||||
}
|
}
|
||||||
|
|
||||||
link_ret = gst_pad_proxy_pad_link (pad, caps);
|
|
||||||
|
|
||||||
if (GST_PAD_LINK_SUCCESSFUL (link_ret)) {
|
|
||||||
/* we store an extra copy of the negotiated caps, just in case
|
|
||||||
* the pads become unnegotiated while we have buffers */
|
|
||||||
gst_caps_replace (&queue->negotiated_caps, gst_caps_copy (caps));
|
|
||||||
}
|
|
||||||
|
|
||||||
return link_ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_queue_locked_flush (GstQueue * queue)
|
gst_queue_locked_flush (GstQueue * queue)
|
||||||
{
|
{
|
||||||
|
@ -419,7 +439,6 @@ gst_queue_locked_flush (GstQueue * queue)
|
||||||
data when flushing */
|
data when flushing */
|
||||||
gst_data_unref (data);
|
gst_data_unref (data);
|
||||||
}
|
}
|
||||||
queue->timeval = NULL;
|
|
||||||
queue->cur_level.buffers = 0;
|
queue->cur_level.buffers = 0;
|
||||||
queue->cur_level.bytes = 0;
|
queue->cur_level.bytes = 0;
|
||||||
queue->cur_level.time = 0;
|
queue->cur_level.time = 0;
|
||||||
|
@ -431,40 +450,6 @@ gst_queue_locked_flush (GstQueue * queue)
|
||||||
g_cond_signal (queue->item_del);
|
g_cond_signal (queue->item_del);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
gst_queue_handle_pending_events (GstQueue * queue)
|
|
||||||
{
|
|
||||||
/* check for events to send upstream */
|
|
||||||
/* g_queue_get_length is glib 2.4, so don't depend on it yet, use ->length */
|
|
||||||
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue,
|
|
||||||
"handling pending events, events queue of size %d",
|
|
||||||
queue->events->length);
|
|
||||||
g_mutex_lock (queue->event_lock);
|
|
||||||
while (!g_queue_is_empty (queue->events)) {
|
|
||||||
GstQueueEventResponse *er;
|
|
||||||
|
|
||||||
er = g_queue_pop_head (queue->events);
|
|
||||||
|
|
||||||
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue,
|
|
||||||
"sending event %p (%d) from event response %p upstream",
|
|
||||||
er->event, GST_EVENT_TYPE (er->event), er);
|
|
||||||
if (er->handled) {
|
|
||||||
/* change this to an assert when this file gets reviewed properly. */
|
|
||||||
GST_ELEMENT_ERROR (queue, CORE, EVENT, (NULL),
|
|
||||||
("already handled event %p (%d) from event response %p upstream",
|
|
||||||
er->event, GST_EVENT_TYPE (er->event), er));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
g_mutex_unlock (queue->event_lock);
|
|
||||||
er->ret = gst_pad_event_default (queue->srcpad, er->event);
|
|
||||||
er->handled = TRUE;
|
|
||||||
g_cond_signal (queue->event_done);
|
|
||||||
g_mutex_lock (queue->event_lock);
|
|
||||||
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue, "event sent");
|
|
||||||
}
|
|
||||||
g_mutex_unlock (queue->event_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define STATUS(queue, msg) \
|
#define STATUS(queue, msg) \
|
||||||
GST_CAT_LOG_OBJECT (queue_dataflow, queue, \
|
GST_CAT_LOG_OBJECT (queue_dataflow, queue, \
|
||||||
"(%s:%s) " msg ": %u of %u-%u buffers, %u of %u-%u " \
|
"(%s:%s) " msg ": %u of %u-%u buffers, %u of %u-%u " \
|
||||||
|
@ -482,58 +467,80 @@ gst_queue_handle_pending_events (GstQueue * queue)
|
||||||
queue->max_size.time, \
|
queue->max_size.time, \
|
||||||
queue->queue->length)
|
queue->queue->length)
|
||||||
|
|
||||||
static void
|
static gboolean
|
||||||
gst_queue_chain (GstPad * pad, GstData * data)
|
gst_queue_handle_sink_event (GstPad * pad, GstEvent * event)
|
||||||
{
|
{
|
||||||
GstQueue *queue;
|
GstQueue *queue;
|
||||||
|
|
||||||
g_return_if_fail (pad != NULL);
|
|
||||||
g_return_if_fail (GST_IS_PAD (pad));
|
|
||||||
g_return_if_fail (data != NULL);
|
|
||||||
|
|
||||||
queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
|
queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
|
||||||
|
|
||||||
restart:
|
|
||||||
/* we have to lock the queue since we span threads */
|
|
||||||
GST_QUEUE_MUTEX_LOCK;
|
GST_QUEUE_MUTEX_LOCK;
|
||||||
|
|
||||||
gst_queue_handle_pending_events (queue);
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_FLUSH:
|
||||||
/* assume don't need to flush this buffer when the queue is filled */
|
STATUS (queue, "received flush event");
|
||||||
queue->flush = FALSE;
|
gst_queue_locked_flush (queue);
|
||||||
|
STATUS (queue, "after flush");
|
||||||
if (GST_IS_EVENT (data)) {
|
break;
|
||||||
switch (GST_EVENT_TYPE (data)) {
|
case GST_EVENT_EOS:
|
||||||
case GST_EVENT_FLUSH:
|
STATUS (queue, "received EOS");
|
||||||
STATUS (queue, "received flush event");
|
break;
|
||||||
gst_queue_locked_flush (queue);
|
default:
|
||||||
STATUS (queue, "after flush");
|
/* we put the event in the queue, we don't have to act ourselves */
|
||||||
break;
|
GST_CAT_LOG_OBJECT (queue_dataflow, queue,
|
||||||
case GST_EVENT_EOS:
|
"adding event %p of type %d", event, GST_EVENT_TYPE (event));
|
||||||
STATUS (queue, "received EOS");
|
break;
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* we put the event in the queue, we don't have to act ourselves */
|
|
||||||
GST_CAT_LOG_OBJECT (queue_dataflow, queue,
|
|
||||||
"adding event %p of type %d", data, GST_EVENT_TYPE (data));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GST_IS_BUFFER (data))
|
gst_event_ref (event);
|
||||||
GST_CAT_LOG_OBJECT (queue_dataflow, queue,
|
g_queue_push_tail (queue->queue, event);
|
||||||
"adding buffer %p of size %d", data, GST_BUFFER_SIZE (data));
|
g_cond_signal (queue->item_add);
|
||||||
|
GST_QUEUE_MUTEX_UNLOCK;
|
||||||
|
|
||||||
/* We make space available if we're "full" according to whatever
|
return TRUE;
|
||||||
* the user defined as "full". Note that this only applies to buffers.
|
}
|
||||||
* We always handle events and they don't count in our statistics. */
|
|
||||||
if (GST_IS_BUFFER (data) &&
|
static gboolean
|
||||||
((queue->max_size.buffers > 0 &&
|
gst_queue_is_empty (GstQueue * queue)
|
||||||
|
{
|
||||||
|
return (queue->queue->length == 0 ||
|
||||||
|
(queue->min_threshold.buffers > 0 &&
|
||||||
|
queue->cur_level.buffers < queue->min_threshold.buffers) ||
|
||||||
|
(queue->min_threshold.bytes > 0 &&
|
||||||
|
queue->cur_level.bytes < queue->min_threshold.bytes) ||
|
||||||
|
(queue->min_threshold.time > 0 &&
|
||||||
|
queue->cur_level.time < queue->min_threshold.time));
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_queue_is_filled (GstQueue * queue)
|
||||||
|
{
|
||||||
|
return (((queue->max_size.buffers > 0 &&
|
||||||
queue->cur_level.buffers >= queue->max_size.buffers) ||
|
queue->cur_level.buffers >= queue->max_size.buffers) ||
|
||||||
(queue->max_size.bytes > 0 &&
|
(queue->max_size.bytes > 0 &&
|
||||||
queue->cur_level.bytes >= queue->max_size.bytes) ||
|
queue->cur_level.bytes >= queue->max_size.bytes) ||
|
||||||
(queue->max_size.time > 0 &&
|
(queue->max_size.time > 0 &&
|
||||||
queue->cur_level.time >= queue->max_size.time))) {
|
queue->cur_level.time >= queue->max_size.time)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_queue_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
|
{
|
||||||
|
GstQueue *queue;
|
||||||
|
|
||||||
|
queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
|
||||||
|
|
||||||
|
/* we have to lock the queue since we span threads */
|
||||||
|
GST_QUEUE_MUTEX_LOCK;
|
||||||
|
|
||||||
|
GST_CAT_LOG_OBJECT (queue_dataflow, queue,
|
||||||
|
"adding buffer %p of size %d", buffer, GST_BUFFER_SIZE (buffer));
|
||||||
|
|
||||||
|
/* We make space available if we're "full" according to whatever
|
||||||
|
* the user defined as "full". Note that this only applies to buffers.
|
||||||
|
* We always handle events and they don't count in our statistics. */
|
||||||
|
if (gst_queue_is_filled (queue)) {
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
GST_QUEUE_MUTEX_UNLOCK;
|
||||||
g_signal_emit (G_OBJECT (queue), gst_queue_signals[SIGNAL_OVERRUN], 0);
|
g_signal_emit (G_OBJECT (queue), gst_queue_signals[SIGNAL_OVERRUN], 0);
|
||||||
GST_QUEUE_MUTEX_LOCK;
|
GST_QUEUE_MUTEX_LOCK;
|
||||||
|
@ -577,15 +584,15 @@ restart:
|
||||||
queue->queue->tail = g_list_last (item);
|
queue->queue->tail = g_list_last (item);
|
||||||
queue->queue->length--;
|
queue->queue->length--;
|
||||||
|
|
||||||
/* and unref the data at the end. Twice, because we keep a ref
|
/* and unref the buffer at the end. Twice, because we keep a ref
|
||||||
* to make things read-only. Also keep our list uptodate. */
|
* to make things read-only. Also keep our list uptodate. */
|
||||||
queue->cur_level.bytes -= GST_BUFFER_SIZE (data);
|
queue->cur_level.bytes -= GST_BUFFER_SIZE (buffer);
|
||||||
queue->cur_level.buffers--;
|
queue->cur_level.buffers--;
|
||||||
if (GST_BUFFER_DURATION (data) != GST_CLOCK_TIME_NONE)
|
if (GST_BUFFER_DURATION (buffer) != GST_CLOCK_TIME_NONE)
|
||||||
queue->cur_level.time -= GST_BUFFER_DURATION (data);
|
queue->cur_level.time -= GST_BUFFER_DURATION (buffer);
|
||||||
|
|
||||||
gst_data_unref (data);
|
gst_buffer_unref (buffer);
|
||||||
gst_data_unref (data);
|
gst_buffer_unref (buffer);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -597,63 +604,12 @@ restart:
|
||||||
case GST_QUEUE_NO_LEAK:
|
case GST_QUEUE_NO_LEAK:
|
||||||
STATUS (queue, "pre-full wait");
|
STATUS (queue, "pre-full wait");
|
||||||
|
|
||||||
while ((queue->max_size.buffers > 0 &&
|
while (gst_queue_is_filled (queue)) {
|
||||||
queue->cur_level.buffers >= queue->max_size.buffers) ||
|
STATUS (queue, "waiting for item_del signal from thread using qlock");
|
||||||
(queue->max_size.bytes > 0 &&
|
g_cond_wait (queue->item_del, queue->qlock);
|
||||||
queue->cur_level.bytes >= queue->max_size.bytes) ||
|
|
||||||
(queue->max_size.time > 0 &&
|
|
||||||
queue->cur_level.time >= queue->max_size.time)) {
|
|
||||||
/* if there's a pending state change for this queue
|
/* if there's a pending state change for this queue
|
||||||
* or its manager, switch back to iterator so bottom
|
* or its manager, switch back to iterator so bottom
|
||||||
* half of state change executes */
|
* half of state change executes */
|
||||||
if (queue->interrupt) {
|
|
||||||
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue, "interrupted");
|
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
|
||||||
if (gst_scheduler_interrupt (gst_pad_get_scheduler (queue->sinkpad),
|
|
||||||
GST_ELEMENT (queue))) {
|
|
||||||
goto out_unref;
|
|
||||||
}
|
|
||||||
/* if we got here because we were unlocked after a
|
|
||||||
* flush, we don't need to add the buffer to the
|
|
||||||
* queue again */
|
|
||||||
if (queue->flush) {
|
|
||||||
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue,
|
|
||||||
"not adding pending buffer after flush");
|
|
||||||
goto out_unref;
|
|
||||||
}
|
|
||||||
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue,
|
|
||||||
"adding pending buffer after interrupt");
|
|
||||||
goto restart;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GST_STATE (queue) != GST_STATE_PLAYING) {
|
|
||||||
/* this means the other end is shut down. Try to
|
|
||||||
* signal to resolve the error */
|
|
||||||
if (!queue->may_deadlock) {
|
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
|
||||||
gst_data_unref (data);
|
|
||||||
GST_ELEMENT_ERROR (queue, CORE, THREAD, (NULL),
|
|
||||||
("deadlock found, shutting down source pad elements"));
|
|
||||||
/* we don't go to out_unref here, since we want to
|
|
||||||
* unref the buffer *before* calling GST_ELEMENT_ERROR */
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
GST_CAT_WARNING_OBJECT (queue_dataflow, queue,
|
|
||||||
"%s: waiting for the app to restart "
|
|
||||||
"source pad elements", GST_ELEMENT_NAME (queue));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* OK, we've got a serious issue here. Imagine the situation
|
|
||||||
* where the puller (next element) is sending an event here,
|
|
||||||
* so it cannot pull events from the queue, and we cannot
|
|
||||||
* push data further because the queue is 'full' and therefore,
|
|
||||||
* we wait here (and do not handle events): deadlock! to solve
|
|
||||||
* that, we handle pending upstream events here, too. */
|
|
||||||
gst_queue_handle_pending_events (queue);
|
|
||||||
|
|
||||||
STATUS (queue, "waiting for item_del signal from thread using qlock");
|
|
||||||
g_cond_wait (queue->item_del, queue->qlock);
|
|
||||||
STATUS (queue, "received item_del signal from thread using qlock");
|
STATUS (queue, "received item_del signal from thread using qlock");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -666,19 +622,17 @@ restart:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* put the buffer on the tail of the list. We keep a reference,
|
/* put the buffer on the tail of the list. We keep a reference,
|
||||||
* so that the data is read-only while in here. There's a good
|
* so that the buffer is read-only while in here. There's a good
|
||||||
* reason to do so: we have a size and time counter, and any
|
* reason to do so: we have a size and time counter, and any
|
||||||
* modification to the content could change any of the two. */
|
* modification to the content could change any of the two. */
|
||||||
gst_data_ref (data);
|
gst_buffer_ref (buffer);
|
||||||
g_queue_push_tail (queue->queue, data);
|
g_queue_push_tail (queue->queue, buffer);
|
||||||
|
|
||||||
/* Note that we only add buffers (not events) to the statistics */
|
/* add buffer to the statistics */
|
||||||
if (GST_IS_BUFFER (data)) {
|
queue->cur_level.buffers++;
|
||||||
queue->cur_level.buffers++;
|
queue->cur_level.bytes += GST_BUFFER_SIZE (buffer);
|
||||||
queue->cur_level.bytes += GST_BUFFER_SIZE (data);
|
if (GST_BUFFER_DURATION (buffer) != GST_CLOCK_TIME_NONE)
|
||||||
if (GST_BUFFER_DURATION (data) != GST_CLOCK_TIME_NONE)
|
queue->cur_level.time += GST_BUFFER_DURATION (buffer);
|
||||||
queue->cur_level.time += GST_BUFFER_DURATION (data);
|
|
||||||
}
|
|
||||||
|
|
||||||
STATUS (queue, "+ level");
|
STATUS (queue, "+ level");
|
||||||
|
|
||||||
|
@ -686,94 +640,41 @@ restart:
|
||||||
g_cond_signal (queue->item_add);
|
g_cond_signal (queue->item_add);
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
GST_QUEUE_MUTEX_UNLOCK;
|
||||||
|
|
||||||
return;
|
return GST_FLOW_OK;
|
||||||
|
|
||||||
out_unref:
|
out_unref:
|
||||||
gst_data_unref (data);
|
gst_buffer_unref (buffer);
|
||||||
return;
|
|
||||||
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstData *
|
static GstFlowReturn
|
||||||
gst_queue_get (GstPad * pad)
|
gst_queue_get (GstPad * pad, GstBuffer ** buffer)
|
||||||
{
|
{
|
||||||
GstQueue *queue;
|
GstQueue *queue;
|
||||||
GstData *data;
|
GstData *data;
|
||||||
|
GstFlowReturn result = GST_FLOW_OK;
|
||||||
|
|
||||||
g_return_val_if_fail (pad != NULL, NULL);
|
queue = GST_QUEUE (gst_object_get_parent (GST_OBJECT (pad)));
|
||||||
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
|
|
||||||
|
|
||||||
queue = GST_QUEUE (gst_pad_get_parent (pad));
|
|
||||||
|
|
||||||
restart:
|
|
||||||
/* have to lock for thread-safety */
|
/* have to lock for thread-safety */
|
||||||
GST_QUEUE_MUTEX_LOCK;
|
GST_QUEUE_MUTEX_LOCK;
|
||||||
|
|
||||||
if (queue->queue->length == 0 ||
|
restart:
|
||||||
(queue->min_threshold.buffers > 0 &&
|
if (gst_queue_is_empty (queue)) {
|
||||||
queue->cur_level.buffers < queue->min_threshold.buffers) ||
|
|
||||||
(queue->min_threshold.bytes > 0 &&
|
|
||||||
queue->cur_level.bytes < queue->min_threshold.bytes) ||
|
|
||||||
(queue->min_threshold.time > 0 &&
|
|
||||||
queue->cur_level.time < queue->min_threshold.time)) {
|
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
GST_QUEUE_MUTEX_UNLOCK;
|
||||||
g_signal_emit (G_OBJECT (queue), gst_queue_signals[SIGNAL_UNDERRUN], 0);
|
g_signal_emit (G_OBJECT (queue), gst_queue_signals[SIGNAL_UNDERRUN], 0);
|
||||||
GST_QUEUE_MUTEX_LOCK;
|
GST_QUEUE_MUTEX_LOCK;
|
||||||
|
|
||||||
STATUS (queue, "pre-empty wait");
|
STATUS (queue, "pre-empty wait");
|
||||||
while (queue->queue->length == 0 ||
|
while (gst_queue_is_empty (queue)) {
|
||||||
(queue->min_threshold.buffers > 0 &&
|
|
||||||
queue->cur_level.buffers < queue->min_threshold.buffers) ||
|
|
||||||
(queue->min_threshold.bytes > 0 &&
|
|
||||||
queue->cur_level.bytes < queue->min_threshold.bytes) ||
|
|
||||||
(queue->min_threshold.time > 0 &&
|
|
||||||
queue->cur_level.time < queue->min_threshold.time)) {
|
|
||||||
/* if there's a pending state change for this queue or its
|
|
||||||
* manager, switch back to iterator so bottom half of state
|
|
||||||
* change executes. */
|
|
||||||
if (queue->interrupt) {
|
|
||||||
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue, "interrupted");
|
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
|
||||||
if (gst_scheduler_interrupt (gst_pad_get_scheduler (queue->srcpad),
|
|
||||||
GST_ELEMENT (queue)))
|
|
||||||
return GST_DATA (gst_event_new (GST_EVENT_INTERRUPT));
|
|
||||||
goto restart;
|
|
||||||
}
|
|
||||||
if (GST_STATE (queue) != GST_STATE_PLAYING) {
|
|
||||||
/* this means the other end is shut down */
|
|
||||||
if (!queue->may_deadlock) {
|
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
|
||||||
GST_ELEMENT_ERROR (queue, CORE, THREAD, (NULL),
|
|
||||||
("deadlock found, shutting down sink pad elements"));
|
|
||||||
goto restart;
|
|
||||||
} else {
|
|
||||||
GST_CAT_WARNING_OBJECT (queue_dataflow, queue,
|
|
||||||
"%s: waiting for the app to restart "
|
|
||||||
"source pad elements", GST_ELEMENT_NAME (queue));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
STATUS (queue, "waiting for item_add");
|
STATUS (queue, "waiting for item_add");
|
||||||
|
|
||||||
if (queue->block_timeout != GST_CLOCK_TIME_NONE) {
|
GST_LOG_OBJECT (queue, "doing g_cond_wait using qlock from thread %p",
|
||||||
GTimeVal timeout;
|
g_thread_self ());
|
||||||
|
g_cond_wait (queue->item_add, queue->qlock);
|
||||||
g_get_current_time (&timeout);
|
GST_LOG_OBJECT (queue, "done g_cond_wait using qlock from thread %p",
|
||||||
g_time_val_add (&timeout, queue->block_timeout / 1000);
|
g_thread_self ());
|
||||||
GST_LOG_OBJECT (queue, "g_cond_time_wait using qlock from thread %p",
|
|
||||||
g_thread_self ());
|
|
||||||
if (!g_cond_timed_wait (queue->item_add, queue->qlock, &timeout)) {
|
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
|
||||||
GST_CAT_WARNING_OBJECT (queue_dataflow, queue,
|
|
||||||
"Sending filler event");
|
|
||||||
return GST_DATA (gst_event_new_filler ());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
GST_LOG_OBJECT (queue, "doing g_cond_wait using qlock from thread %p",
|
|
||||||
g_thread_self ());
|
|
||||||
g_cond_wait (queue->item_add, queue->qlock);
|
|
||||||
GST_LOG_OBJECT (queue, "done g_cond_wait using qlock from thread %p",
|
|
||||||
g_thread_self ());
|
|
||||||
}
|
|
||||||
STATUS (queue, "got item_add signal");
|
STATUS (queue, "got item_add signal");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -788,120 +689,68 @@ restart:
|
||||||
GST_CAT_LOG_OBJECT (queue_dataflow, queue,
|
GST_CAT_LOG_OBJECT (queue_dataflow, queue,
|
||||||
"retrieved data %p from queue", data);
|
"retrieved data %p from queue", data);
|
||||||
|
|
||||||
if (data == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (GST_IS_BUFFER (data)) {
|
if (GST_IS_BUFFER (data)) {
|
||||||
/* Update statistics */
|
/* Update statistics */
|
||||||
queue->cur_level.buffers--;
|
queue->cur_level.buffers--;
|
||||||
queue->cur_level.bytes -= GST_BUFFER_SIZE (data);
|
queue->cur_level.bytes -= GST_BUFFER_SIZE (data);
|
||||||
if (GST_BUFFER_DURATION (data) != GST_CLOCK_TIME_NONE)
|
if (GST_BUFFER_DURATION (data) != GST_CLOCK_TIME_NONE)
|
||||||
queue->cur_level.time -= GST_BUFFER_DURATION (data);
|
queue->cur_level.time -= GST_BUFFER_DURATION (data);
|
||||||
|
|
||||||
|
*buffer = GST_BUFFER (data);
|
||||||
|
} else {
|
||||||
|
if (GST_EVENT_TYPE (data) == GST_EVENT_EOS) {
|
||||||
|
result = GST_FLOW_WRONG_STATE;
|
||||||
|
}
|
||||||
|
gst_pad_push_event (queue->srcpad, GST_EVENT (data));
|
||||||
|
if (result == GST_FLOW_OK)
|
||||||
|
goto restart;
|
||||||
|
else
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now that we're done, we can lose our own reference to
|
/* Now that we're done, we can lose our own reference to
|
||||||
* the item, since we're no longer in danger. */
|
* the item, since we're no longer in danger. */
|
||||||
gst_data_unref (data);
|
gst_data_unref (data);
|
||||||
|
|
||||||
|
done:
|
||||||
STATUS (queue, "after _get()");
|
STATUS (queue, "after _get()");
|
||||||
|
|
||||||
GST_CAT_LOG_OBJECT (queue_dataflow, queue, "signalling item_del");
|
GST_CAT_LOG_OBJECT (queue_dataflow, queue, "signalling item_del");
|
||||||
g_cond_signal (queue->item_del);
|
g_cond_signal (queue->item_del);
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
GST_QUEUE_MUTEX_UNLOCK;
|
||||||
|
|
||||||
/* FIXME: I suppose this needs to be locked, since the EOS
|
return result;
|
||||||
* bit affects the pipeline state. However, that bit is
|
|
||||||
* locked too so it'd cause a deadlock. */
|
|
||||||
if (GST_IS_EVENT (data)) {
|
|
||||||
GstEvent *event = GST_EVENT (data);
|
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
|
||||||
case GST_EVENT_EOS:
|
|
||||||
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue,
|
|
||||||
"queue \"%s\" eos", GST_ELEMENT_NAME (queue));
|
|
||||||
gst_element_set_eos (GST_ELEMENT (queue));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_queue_handle_src_event (GstPad * pad, GstEvent * event)
|
gst_queue_handle_src_event (GstPad * pad, GstEvent * event)
|
||||||
{
|
{
|
||||||
GstQueue *queue = GST_QUEUE (gst_pad_get_parent (pad));
|
GstQueue *queue = GST_QUEUE (gst_object_get_parent (GST_OBJECT (pad)));
|
||||||
gboolean res;
|
gboolean res = TRUE;
|
||||||
|
|
||||||
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue, "got event %p (%d)",
|
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue, "got event %p (%d)",
|
||||||
event, GST_EVENT_TYPE (event));
|
event, GST_EVENT_TYPE (event));
|
||||||
|
|
||||||
|
gst_event_ref (event);
|
||||||
|
res = gst_pad_event_default (pad, event);
|
||||||
GST_QUEUE_MUTEX_LOCK;
|
GST_QUEUE_MUTEX_LOCK;
|
||||||
|
|
||||||
if (gst_element_get_state (GST_ELEMENT (queue)) == GST_STATE_PLAYING) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
GstQueueEventResponse er;
|
case GST_EVENT_FLUSH:
|
||||||
|
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue,
|
||||||
/* push the event to the queue and wait for upstream consumption */
|
"FLUSH event, flushing queue\n");
|
||||||
er.event = event;
|
gst_queue_locked_flush (queue);
|
||||||
er.handled = FALSE;
|
break;
|
||||||
g_mutex_lock (queue->event_lock);
|
case GST_EVENT_SEEK:
|
||||||
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue,
|
if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) {
|
||||||
"putting event %p (%d) on internal queue", event,
|
|
||||||
GST_EVENT_TYPE (event));
|
|
||||||
g_queue_push_tail (queue->events, &er);
|
|
||||||
g_mutex_unlock (queue->event_lock);
|
|
||||||
GST_CAT_WARNING_OBJECT (queue_dataflow, queue,
|
|
||||||
"Preparing for loop for event handler");
|
|
||||||
/* see the chain function on why this is here - it prevents a deadlock */
|
|
||||||
g_cond_signal (queue->item_del);
|
|
||||||
while (!er.handled) {
|
|
||||||
GTimeVal timeout;
|
|
||||||
|
|
||||||
g_get_current_time (&timeout);
|
|
||||||
g_time_val_add (&timeout, 500 * 1000); /* half a second */
|
|
||||||
GST_LOG_OBJECT (queue, "doing g_cond_wait using qlock from thread %p",
|
|
||||||
g_thread_self ());
|
|
||||||
if (!g_cond_timed_wait (queue->event_done, queue->qlock, &timeout) &&
|
|
||||||
!er.handled) {
|
|
||||||
GST_CAT_WARNING_OBJECT (queue_dataflow, queue,
|
|
||||||
"timeout in upstream event handling, dropping event %p (%d)",
|
|
||||||
er.event, GST_EVENT_TYPE (er.event));
|
|
||||||
g_mutex_lock (queue->event_lock);
|
|
||||||
/* since this queue is for src events (ie upstream), this thread is
|
|
||||||
* the only one that is pushing stuff on it, so we're sure that
|
|
||||||
* it's still the tail element. FIXME: But in practice, we should use
|
|
||||||
* GList instead of GQueue for this so we can remove any element in
|
|
||||||
* the list. */
|
|
||||||
g_queue_pop_tail (queue->events);
|
|
||||||
g_mutex_unlock (queue->event_lock);
|
|
||||||
gst_event_unref (er.event);
|
|
||||||
res = FALSE;
|
|
||||||
goto handled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GST_CAT_WARNING_OBJECT (queue_dataflow, queue, "Event handled");
|
|
||||||
res = er.ret;
|
|
||||||
} else {
|
|
||||||
res = gst_pad_event_default (pad, event);
|
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
|
||||||
case GST_EVENT_FLUSH:
|
|
||||||
GST_CAT_DEBUG_OBJECT (queue_dataflow, queue,
|
|
||||||
"FLUSH event, flushing queue\n");
|
|
||||||
gst_queue_locked_flush (queue);
|
gst_queue_locked_flush (queue);
|
||||||
break;
|
}
|
||||||
case GST_EVENT_SEEK:
|
default:
|
||||||
if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) {
|
break;
|
||||||
gst_queue_locked_flush (queue);
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
handled:
|
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
GST_QUEUE_MUTEX_UNLOCK;
|
||||||
|
gst_event_unref (event);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -911,10 +760,10 @@ gst_queue_handle_src_query (GstPad * pad,
|
||||||
GstQueryType type, GstFormat * fmt, gint64 * value)
|
GstQueryType type, GstFormat * fmt, gint64 * value)
|
||||||
{
|
{
|
||||||
GstQueue *queue = GST_QUEUE (gst_pad_get_parent (pad));
|
GstQueue *queue = GST_QUEUE (gst_pad_get_parent (pad));
|
||||||
gboolean res;
|
|
||||||
|
|
||||||
res = gst_pad_query (GST_PAD_PEER (queue->sinkpad), type, fmt, value);
|
if (!GST_PAD_PEER (queue->sinkpad))
|
||||||
if (!res)
|
return FALSE;
|
||||||
|
if (!gst_pad_query (GST_PAD_PEER (queue->sinkpad), type, fmt, value))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (type == GST_QUERY_POSITION) {
|
if (type == GST_QUERY_POSITION) {
|
||||||
|
@ -935,22 +784,76 @@ gst_queue_handle_src_query (GstPad * pad,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static void
|
||||||
gst_queue_release_locks (GstElement * element)
|
gst_queue_loop (GstElement * element)
|
||||||
{
|
{
|
||||||
GstQueue *queue;
|
GstQueue *queue;
|
||||||
|
GstTask *task;
|
||||||
|
GstBuffer *buffer;
|
||||||
|
GstFlowReturn ret;
|
||||||
|
|
||||||
|
g_return_if_fail (element != NULL);
|
||||||
|
g_return_if_fail (GST_IS_QUEUE (element));
|
||||||
|
|
||||||
queue = GST_QUEUE (element);
|
queue = GST_QUEUE (element);
|
||||||
|
task = queue->task;
|
||||||
|
|
||||||
GST_QUEUE_MUTEX_LOCK;
|
ret = gst_queue_get (queue->srcpad, &buffer);
|
||||||
queue->interrupt = TRUE;
|
if (ret != GST_FLOW_OK) {
|
||||||
g_cond_signal (queue->item_add);
|
GST_CAT_LOG_OBJECT (queue_dataflow, queue, "stopping, get returned %d",
|
||||||
g_cond_signal (queue->item_del);
|
ret);
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
gst_task_stop (task);
|
||||||
|
return;
|
||||||
return TRUE;
|
}
|
||||||
|
ret = gst_pad_push (queue->srcpad, buffer);
|
||||||
|
if (ret != GST_FLOW_OK) {
|
||||||
|
GST_CAT_LOG_OBJECT (queue_dataflow, queue, "stopping, push returned %d",
|
||||||
|
ret);
|
||||||
|
gst_task_stop (task);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_queue_src_activate (GstPad * pad, gboolean active)
|
||||||
|
{
|
||||||
|
gboolean result = FALSE;
|
||||||
|
GstQueue *queue;
|
||||||
|
|
||||||
|
queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
|
||||||
|
|
||||||
|
if (active) {
|
||||||
|
/* if we have a scheduler we can start the task */
|
||||||
|
if (GST_ELEMENT_MANAGER (queue)) {
|
||||||
|
GST_STREAM_LOCK (pad);
|
||||||
|
queue->task =
|
||||||
|
gst_scheduler_create_task (GST_ELEMENT_MANAGER (queue)->scheduler,
|
||||||
|
(GstTaskFunction) gst_queue_loop, queue);
|
||||||
|
|
||||||
|
gst_task_start (queue->task);
|
||||||
|
GST_STREAM_UNLOCK (pad);
|
||||||
|
result = TRUE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* step 1, unblock chain and get functions */
|
||||||
|
queue->interrupt = TRUE;
|
||||||
|
g_cond_signal (queue->item_add);
|
||||||
|
g_cond_signal (queue->item_del);
|
||||||
|
|
||||||
|
/* step 2, make sure streaming finishes */
|
||||||
|
GST_STREAM_LOCK (pad);
|
||||||
|
/* step 3, stop the task */
|
||||||
|
gst_task_stop (queue->task);
|
||||||
|
gst_object_unref (GST_OBJECT (queue->task));
|
||||||
|
GST_STREAM_UNLOCK (pad);
|
||||||
|
|
||||||
|
result = TRUE;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static GstElementStateReturn
|
static GstElementStateReturn
|
||||||
gst_queue_change_state (GstElement * element)
|
gst_queue_change_state (GstElement * element)
|
||||||
{
|
{
|
||||||
|
@ -970,53 +873,28 @@ gst_queue_change_state (GstElement * element)
|
||||||
case GST_STATE_NULL_TO_READY:
|
case GST_STATE_NULL_TO_READY:
|
||||||
gst_queue_locked_flush (queue);
|
gst_queue_locked_flush (queue);
|
||||||
break;
|
break;
|
||||||
case GST_STATE_PAUSED_TO_PLAYING:
|
case GST_STATE_READY_TO_PAUSED:
|
||||||
if (!GST_PAD_IS_LINKED (queue->sinkpad)) {
|
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, queue,
|
|
||||||
"queue %s is not linked", GST_ELEMENT_NAME (queue));
|
|
||||||
/* FIXME can this be? */
|
|
||||||
g_cond_signal (queue->item_add);
|
|
||||||
|
|
||||||
ret = GST_STATE_FAILURE;
|
|
||||||
goto unlock;
|
|
||||||
} else {
|
|
||||||
GstScheduler *src_sched, *sink_sched;
|
|
||||||
|
|
||||||
src_sched = gst_pad_get_scheduler (GST_PAD (queue->srcpad));
|
|
||||||
sink_sched = gst_pad_get_scheduler (GST_PAD (queue->sinkpad));
|
|
||||||
|
|
||||||
if (src_sched == sink_sched) {
|
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, queue,
|
|
||||||
"queue %s does not connect different schedulers",
|
|
||||||
GST_ELEMENT_NAME (queue));
|
|
||||||
|
|
||||||
g_warning ("queue %s does not connect different schedulers",
|
|
||||||
GST_ELEMENT_NAME (queue));
|
|
||||||
|
|
||||||
ret = GST_STATE_FAILURE;
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
queue->interrupt = FALSE;
|
|
||||||
break;
|
break;
|
||||||
case GST_STATE_PAUSED_TO_READY:
|
case GST_STATE_PAUSED_TO_PLAYING:
|
||||||
gst_queue_locked_flush (queue);
|
queue->interrupt = FALSE;
|
||||||
gst_caps_replace (&queue->negotiated_caps, NULL);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
|
||||||
|
|
||||||
/* this is an ugly hack to make sure our pads are always active.
|
switch (GST_STATE_TRANSITION (element)) {
|
||||||
* Reason for this is that pad activation for the queue element
|
case GST_STATE_PLAYING_TO_PAUSED:
|
||||||
* depends on 2 schedulers (ugh) */
|
break;
|
||||||
gst_pad_set_active (queue->sinkpad, TRUE);
|
case GST_STATE_PAUSED_TO_READY:
|
||||||
gst_pad_set_active (queue->srcpad, TRUE);
|
gst_queue_locked_flush (queue);
|
||||||
|
break;
|
||||||
unlock:
|
case GST_STATE_READY_TO_NULL:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
GST_QUEUE_MUTEX_UNLOCK;
|
GST_QUEUE_MUTEX_UNLOCK;
|
||||||
|
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_STATES, element, "done with state change");
|
GST_CAT_LOG_OBJECT (GST_CAT_STATES, element, "done with state change");
|
||||||
|
@ -1024,7 +902,6 @@ unlock:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_queue_set_property (GObject * object,
|
gst_queue_set_property (GObject * object,
|
||||||
guint prop_id, const GValue * value, GParamSpec * pspec)
|
guint prop_id, const GValue * value, GParamSpec * pspec)
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include <gst/gstelement.h>
|
#include <gst/gstelement.h>
|
||||||
|
#include <gst/gsttask.h>
|
||||||
|
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
@ -66,6 +67,8 @@ struct _GstQueue {
|
||||||
/* the queue of data we're keeping our grubby hands on */
|
/* the queue of data we're keeping our grubby hands on */
|
||||||
GQueue *queue;
|
GQueue *queue;
|
||||||
|
|
||||||
|
GstTask *task;
|
||||||
|
|
||||||
GstQueueSize
|
GstQueueSize
|
||||||
cur_level, /* currently in the queue */
|
cur_level, /* currently in the queue */
|
||||||
max_size, /* max. amount of data allowed in the queue */
|
max_size, /* max. amount of data allowed in the queue */
|
||||||
|
@ -80,21 +83,12 @@ struct _GstQueue {
|
||||||
|
|
||||||
/* it the queue should fail on possible deadlocks */
|
/* it the queue should fail on possible deadlocks */
|
||||||
gboolean may_deadlock;
|
gboolean may_deadlock;
|
||||||
|
|
||||||
gboolean interrupt;
|
gboolean interrupt;
|
||||||
gboolean flush;
|
gboolean flush;
|
||||||
|
|
||||||
GMutex *qlock; /* lock for queue (vs object lock) */
|
GMutex *qlock; /* lock for queue (vs object lock) */
|
||||||
GCond *item_add; /* signals buffers now available for reading */
|
GCond *item_add; /* signals buffers now available for reading */
|
||||||
GCond *item_del; /* signals space now available for writing */
|
GCond *item_del; /* signals space now available for writing */
|
||||||
GCond *event_done; /* upstream event signaller */
|
|
||||||
|
|
||||||
GTimeVal *timeval; /* the timeout for the queue locking */
|
|
||||||
GQueue *events; /* upstream events get decoupled here */
|
|
||||||
|
|
||||||
GstCaps *negotiated_caps;
|
|
||||||
|
|
||||||
GMutex *event_lock; /* lock when handling the events queue */
|
|
||||||
|
|
||||||
gpointer _gst_reserved[GST_PADDING - 1];
|
gpointer _gst_reserved[GST_PADDING - 1];
|
||||||
};
|
};
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
af az ca cs en_GB fr it nb nl sq sr sv tr uk
|
af az ca cs en_GB fr nb nl sq sr sv tr uk
|
||||||
|
|
|
@ -17,50 +17,80 @@
|
||||||
* Boston, MA 02111-1307, USA.
|
* Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "unistd.h"
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
message_received (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
|
||||||
|
{
|
||||||
|
g_print ("message %p\n", message);
|
||||||
|
|
||||||
|
if (message->type == GST_MESSAGE_EOS) {
|
||||||
|
g_print ("EOS!!\n");
|
||||||
|
gst_main_quit ();
|
||||||
|
}
|
||||||
|
gst_message_unref (message);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
gint
|
gint
|
||||||
main (gint argc, gchar * argv[])
|
main (gint argc, gchar * argv[])
|
||||||
{
|
{
|
||||||
GstElement *pipeline;
|
GstElement *pipeline;
|
||||||
GstElement *fakesrc1, *fakesink1;
|
GstElement *fakesrc1, *fakesink1;
|
||||||
GstElement *fakesrc2, *fakesink2;
|
GstElement *fakesrc2, *fakesink2;
|
||||||
|
GstBus *bus;
|
||||||
|
|
||||||
gst_init (&argc, &argv);
|
gst_init (&argc, &argv);
|
||||||
|
|
||||||
pipeline = gst_pipeline_new ("pipeline");
|
pipeline = gst_pipeline_new ("pipeline");
|
||||||
|
|
||||||
|
bus = GST_PIPELINE (pipeline)->bus;
|
||||||
|
gst_bus_add_watch (bus, (GstBusHandler) message_received, pipeline);
|
||||||
|
|
||||||
fakesrc1 = gst_element_factory_make ("fakesrc", "fakesrc1");
|
fakesrc1 = gst_element_factory_make ("fakesrc", "fakesrc1");
|
||||||
g_object_set (G_OBJECT (fakesrc1), "num_buffers", 5, NULL);
|
g_object_set (G_OBJECT (fakesrc1), "num_buffers", 5, NULL);
|
||||||
fakesink1 = gst_element_factory_make ("fakesink", "fakesink1");
|
fakesink1 = gst_element_factory_make ("fakesink", "fakesink1");
|
||||||
|
|
||||||
gst_bin_add_many (GST_BIN (pipeline), fakesrc1, fakesink1, NULL);
|
gst_bin_add (GST_BIN (pipeline), fakesrc1);
|
||||||
gst_element_link_pads (fakesrc1, "src", fakesink1, "sink");
|
gst_bin_add (GST_BIN (pipeline), fakesink1);
|
||||||
|
gst_pad_link (gst_element_get_pad (fakesrc1, "src"),
|
||||||
|
gst_element_get_pad (fakesink1, "sink"));
|
||||||
|
|
||||||
fakesrc2 = gst_element_factory_make ("fakesrc", "fakesrc2");
|
fakesrc2 = gst_element_factory_make ("fakesrc", "fakesrc2");
|
||||||
g_object_set (G_OBJECT (fakesrc2), "num_buffers", 5, NULL);
|
g_object_set (G_OBJECT (fakesrc2), "num_buffers", 5, NULL);
|
||||||
fakesink2 = gst_element_factory_make ("fakesink", "fakesink2");
|
fakesink2 = gst_element_factory_make ("fakesink", "fakesink2");
|
||||||
|
|
||||||
gst_bin_add_many (GST_BIN (pipeline), fakesrc2, fakesink2, NULL);
|
gst_bin_add (GST_BIN (pipeline), fakesrc2);
|
||||||
gst_element_link_pads (fakesrc2, "src", fakesink2, "sink");
|
gst_bin_add (GST_BIN (pipeline), fakesink2);
|
||||||
|
gst_pad_link (gst_element_get_pad (fakesrc2, "src"),
|
||||||
|
gst_element_get_pad (fakesink2, "sink"));
|
||||||
|
|
||||||
g_signal_connect (G_OBJECT (pipeline), "deep_notify",
|
g_signal_connect (G_OBJECT (pipeline), "deep_notify",
|
||||||
G_CALLBACK (gst_element_default_deep_notify), NULL);
|
G_CALLBACK (gst_object_default_deep_notify), NULL);
|
||||||
|
|
||||||
GST_FLAG_SET (fakesrc2, GST_ELEMENT_LOCKED_STATE);
|
GST_FLAG_SET (fakesrc2, GST_ELEMENT_LOCKED_STATE);
|
||||||
GST_FLAG_SET (fakesink2, GST_ELEMENT_LOCKED_STATE);
|
GST_FLAG_SET (fakesink2, GST_ELEMENT_LOCKED_STATE);
|
||||||
|
|
||||||
|
g_print ("play..\n");
|
||||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||||
while (gst_bin_iterate (GST_BIN (pipeline)));
|
|
||||||
gst_element_set_state (pipeline, GST_STATE_READY);
|
gst_main ();
|
||||||
|
|
||||||
g_object_set (G_OBJECT (fakesrc1), "num_buffers", 5, NULL);
|
g_object_set (G_OBJECT (fakesrc1), "num_buffers", 5, NULL);
|
||||||
|
|
||||||
|
gst_element_set_state (pipeline, GST_STATE_READY);
|
||||||
|
|
||||||
GST_FLAG_UNSET (fakesrc2, GST_ELEMENT_LOCKED_STATE);
|
GST_FLAG_UNSET (fakesrc2, GST_ELEMENT_LOCKED_STATE);
|
||||||
GST_FLAG_UNSET (fakesink2, GST_ELEMENT_LOCKED_STATE);
|
GST_FLAG_UNSET (fakesink2, GST_ELEMENT_LOCKED_STATE);
|
||||||
|
|
||||||
|
g_print ("play..\n");
|
||||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||||
while (gst_bin_iterate (GST_BIN (pipeline)));
|
|
||||||
|
gst_main ();
|
||||||
|
|
||||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||||
|
|
||||||
gst_object_unref (GST_OBJECT (pipeline));
|
gst_object_unref (GST_OBJECT (pipeline));
|
||||||
|
|
|
@ -17,50 +17,80 @@
|
||||||
* Boston, MA 02111-1307, USA.
|
* Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "unistd.h"
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
message_received (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
|
||||||
|
{
|
||||||
|
g_print ("message %p\n", message);
|
||||||
|
|
||||||
|
if (message->type == GST_MESSAGE_EOS) {
|
||||||
|
g_print ("EOS!!\n");
|
||||||
|
gst_main_quit ();
|
||||||
|
}
|
||||||
|
gst_message_unref (message);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
gint
|
gint
|
||||||
main (gint argc, gchar * argv[])
|
main (gint argc, gchar * argv[])
|
||||||
{
|
{
|
||||||
GstElement *pipeline;
|
GstElement *pipeline;
|
||||||
GstElement *fakesrc1, *fakesink1;
|
GstElement *fakesrc1, *fakesink1;
|
||||||
GstElement *fakesrc2, *fakesink2;
|
GstElement *fakesrc2, *fakesink2;
|
||||||
|
GstBus *bus;
|
||||||
|
|
||||||
gst_init (&argc, &argv);
|
gst_init (&argc, &argv);
|
||||||
|
|
||||||
pipeline = gst_pipeline_new ("pipeline");
|
pipeline = gst_pipeline_new ("pipeline");
|
||||||
|
|
||||||
|
bus = GST_PIPELINE (pipeline)->bus;
|
||||||
|
gst_bus_add_watch (bus, (GstBusHandler) message_received, pipeline);
|
||||||
|
|
||||||
fakesrc1 = gst_element_factory_make ("fakesrc", "fakesrc1");
|
fakesrc1 = gst_element_factory_make ("fakesrc", "fakesrc1");
|
||||||
g_object_set (G_OBJECT (fakesrc1), "num_buffers", 5, NULL);
|
g_object_set (G_OBJECT (fakesrc1), "num_buffers", 5, NULL);
|
||||||
fakesink1 = gst_element_factory_make ("fakesink", "fakesink1");
|
fakesink1 = gst_element_factory_make ("fakesink", "fakesink1");
|
||||||
|
|
||||||
gst_bin_add_many (GST_BIN (pipeline), fakesrc1, fakesink1, NULL);
|
gst_bin_add (GST_BIN (pipeline), fakesrc1);
|
||||||
gst_element_link_pads (fakesrc1, "src", fakesink1, "sink");
|
gst_bin_add (GST_BIN (pipeline), fakesink1);
|
||||||
|
gst_pad_link (gst_element_get_pad (fakesrc1, "src"),
|
||||||
|
gst_element_get_pad (fakesink1, "sink"));
|
||||||
|
|
||||||
fakesrc2 = gst_element_factory_make ("fakesrc", "fakesrc2");
|
fakesrc2 = gst_element_factory_make ("fakesrc", "fakesrc2");
|
||||||
g_object_set (G_OBJECT (fakesrc2), "num_buffers", 5, NULL);
|
g_object_set (G_OBJECT (fakesrc2), "num_buffers", 5, NULL);
|
||||||
fakesink2 = gst_element_factory_make ("fakesink", "fakesink2");
|
fakesink2 = gst_element_factory_make ("fakesink", "fakesink2");
|
||||||
|
|
||||||
gst_bin_add_many (GST_BIN (pipeline), fakesrc2, fakesink2, NULL);
|
gst_bin_add (GST_BIN (pipeline), fakesrc2);
|
||||||
gst_element_link_pads (fakesrc2, "src", fakesink2, "sink");
|
gst_bin_add (GST_BIN (pipeline), fakesink2);
|
||||||
|
gst_pad_link (gst_element_get_pad (fakesrc2, "src"),
|
||||||
|
gst_element_get_pad (fakesink2, "sink"));
|
||||||
|
|
||||||
g_signal_connect (G_OBJECT (pipeline), "deep_notify",
|
g_signal_connect (G_OBJECT (pipeline), "deep_notify",
|
||||||
G_CALLBACK (gst_element_default_deep_notify), NULL);
|
G_CALLBACK (gst_object_default_deep_notify), NULL);
|
||||||
|
|
||||||
GST_FLAG_SET (fakesrc2, GST_ELEMENT_LOCKED_STATE);
|
GST_FLAG_SET (fakesrc2, GST_ELEMENT_LOCKED_STATE);
|
||||||
GST_FLAG_SET (fakesink2, GST_ELEMENT_LOCKED_STATE);
|
GST_FLAG_SET (fakesink2, GST_ELEMENT_LOCKED_STATE);
|
||||||
|
|
||||||
|
g_print ("play..\n");
|
||||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||||
while (gst_bin_iterate (GST_BIN (pipeline)));
|
|
||||||
gst_element_set_state (pipeline, GST_STATE_READY);
|
gst_main ();
|
||||||
|
|
||||||
g_object_set (G_OBJECT (fakesrc1), "num_buffers", 5, NULL);
|
g_object_set (G_OBJECT (fakesrc1), "num_buffers", 5, NULL);
|
||||||
|
|
||||||
|
gst_element_set_state (pipeline, GST_STATE_READY);
|
||||||
|
|
||||||
GST_FLAG_UNSET (fakesrc2, GST_ELEMENT_LOCKED_STATE);
|
GST_FLAG_UNSET (fakesrc2, GST_ELEMENT_LOCKED_STATE);
|
||||||
GST_FLAG_UNSET (fakesink2, GST_ELEMENT_LOCKED_STATE);
|
GST_FLAG_UNSET (fakesink2, GST_ELEMENT_LOCKED_STATE);
|
||||||
|
|
||||||
|
g_print ("play..\n");
|
||||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||||
while (gst_bin_iterate (GST_BIN (pipeline)));
|
|
||||||
|
gst_main ();
|
||||||
|
|
||||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||||
|
|
||||||
gst_object_unref (GST_OBJECT (pipeline));
|
gst_object_unref (GST_OBJECT (pipeline));
|
||||||
|
|
|
@ -505,40 +505,12 @@ print_element_flag_info (GstElement * element)
|
||||||
n_print ("\n");
|
n_print ("\n");
|
||||||
n_print ("Element Flags:\n");
|
n_print ("Element Flags:\n");
|
||||||
|
|
||||||
if (GST_FLAG_IS_SET (element, GST_ELEMENT_COMPLEX)) {
|
|
||||||
n_print (" GST_ELEMENT_COMPLEX\n");
|
|
||||||
have_flags = TRUE;
|
|
||||||
}
|
|
||||||
if (GST_FLAG_IS_SET (element, GST_ELEMENT_DECOUPLED)) {
|
|
||||||
n_print (" GST_ELEMENT_DECOUPLED\n");
|
|
||||||
have_flags = TRUE;
|
|
||||||
}
|
|
||||||
if (GST_FLAG_IS_SET (element, GST_ELEMENT_THREAD_SUGGESTED)) {
|
|
||||||
n_print (" GST_ELEMENT_THREADSUGGESTED\n");
|
|
||||||
have_flags = TRUE;
|
|
||||||
}
|
|
||||||
if (GST_FLAG_IS_SET (element, GST_ELEMENT_EVENT_AWARE)) {
|
|
||||||
n_print (" GST_ELEMENT_EVENT_AWARE\n");
|
|
||||||
have_flags = TRUE;
|
|
||||||
}
|
|
||||||
if (!have_flags)
|
if (!have_flags)
|
||||||
n_print (" no flags set\n");
|
n_print (" no flags set\n");
|
||||||
|
|
||||||
if (GST_IS_BIN (element)) {
|
if (GST_IS_BIN (element)) {
|
||||||
n_print ("\n");
|
n_print ("\n");
|
||||||
n_print ("Bin Flags:\n");
|
n_print ("Bin Flags:\n");
|
||||||
if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) {
|
|
||||||
n_print (" GST_BIN_FLAG_MANAGER\n");
|
|
||||||
have_flags = TRUE;
|
|
||||||
}
|
|
||||||
if (GST_FLAG_IS_SET (element, GST_BIN_SELF_SCHEDULABLE)) {
|
|
||||||
n_print (" GST_BIN_SELF_SCHEDULABLE\n");
|
|
||||||
have_flags = TRUE;
|
|
||||||
}
|
|
||||||
if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_PREFER_COTHREADS)) {
|
|
||||||
n_print (" GST_BIN_FLAG_PREFER_COTHREADS\n");
|
|
||||||
have_flags = TRUE;
|
|
||||||
}
|
|
||||||
if (!have_flags)
|
if (!have_flags)
|
||||||
n_print (" no flags set\n");
|
n_print (" no flags set\n");
|
||||||
}
|
}
|
||||||
|
@ -556,11 +528,7 @@ print_implementation_info (GstElement * element)
|
||||||
n_print ("\n");
|
n_print ("\n");
|
||||||
n_print ("Element Implementation:\n");
|
n_print ("Element Implementation:\n");
|
||||||
|
|
||||||
if (element->loopfunc)
|
n_print (" No loopfunc(), must be chain-based or not configured yet\n");
|
||||||
n_print (" loopfunc()-based element: %s\n",
|
|
||||||
GST_DEBUG_FUNCPTR_NAME (element->loopfunc));
|
|
||||||
else
|
|
||||||
n_print (" No loopfunc(), must be chain-based or not configured yet\n");
|
|
||||||
|
|
||||||
n_print (" Has change_state() function: %s\n",
|
n_print (" Has change_state() function: %s\n",
|
||||||
GST_DEBUG_FUNCPTR_NAME (gstelement_class->change_state));
|
GST_DEBUG_FUNCPTR_NAME (gstelement_class->change_state));
|
||||||
|
@ -854,7 +822,8 @@ print_children_info (GstElement * element)
|
||||||
if (!GST_IS_BIN (element))
|
if (!GST_IS_BIN (element))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
children = (GList *) gst_bin_get_list (GST_BIN (element));
|
//children = (GList *) gst_bin_get_list (GST_BIN (element));
|
||||||
|
children = (GList *) GST_BIN (element)->children;
|
||||||
if (children) {
|
if (children) {
|
||||||
n_print ("\n");
|
n_print ("\n");
|
||||||
g_print ("Children:\n");
|
g_print ("Children:\n");
|
||||||
|
|
|
@ -59,63 +59,12 @@ static void sigint_restore (void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static gint max_iterations = 0;
|
static gint max_iterations = 0;
|
||||||
static guint64 iterations = 0;
|
|
||||||
static guint64 sum = 0;
|
|
||||||
static guint64 min = G_MAXINT64;
|
|
||||||
static guint64 max = 0;
|
|
||||||
static GstClock *s_clock;
|
|
||||||
static GstElement *pipeline;
|
static GstElement *pipeline;
|
||||||
gboolean caught_intr = FALSE;
|
gboolean caught_intr = FALSE;
|
||||||
gboolean caught_error = FALSE;
|
gboolean caught_error = FALSE;
|
||||||
|
gboolean tags = FALSE;
|
||||||
|
GMainLoop *loop;
|
||||||
|
|
||||||
gboolean
|
|
||||||
idle_func (gpointer data)
|
|
||||||
{
|
|
||||||
gboolean busy;
|
|
||||||
GTimeVal tfthen, tfnow;
|
|
||||||
GstClockTimeDiff diff;
|
|
||||||
|
|
||||||
g_get_current_time (&tfthen);
|
|
||||||
busy = gst_bin_iterate (GST_BIN (data));
|
|
||||||
iterations++;
|
|
||||||
g_get_current_time (&tfnow);
|
|
||||||
|
|
||||||
diff = GST_TIMEVAL_TO_TIME (tfnow) - GST_TIMEVAL_TO_TIME (tfthen);
|
|
||||||
|
|
||||||
sum += diff;
|
|
||||||
min = MIN (min, diff);
|
|
||||||
max = MAX (max, diff);
|
|
||||||
|
|
||||||
if (!busy || caught_intr || caught_error ||
|
|
||||||
(max_iterations > 0 && iterations >= max_iterations)) {
|
|
||||||
char *s_iterations;
|
|
||||||
char *s_sum;
|
|
||||||
char *s_ave;
|
|
||||||
char *s_min;
|
|
||||||
char *s_max;
|
|
||||||
|
|
||||||
gst_main_quit ();
|
|
||||||
|
|
||||||
/* We write these all to strings first because
|
|
||||||
* G_GUINT64_FORMAT and gettext mix very poorly */
|
|
||||||
s_iterations = g_strdup_printf ("%" G_GUINT64_FORMAT, iterations);
|
|
||||||
s_sum = g_strdup_printf ("%" G_GUINT64_FORMAT, sum);
|
|
||||||
s_ave = g_strdup_printf ("%" G_GUINT64_FORMAT, sum / iterations);
|
|
||||||
s_min = g_strdup_printf ("%" G_GUINT64_FORMAT, min);
|
|
||||||
s_max = g_strdup_printf ("%" G_GUINT64_FORMAT, max);
|
|
||||||
|
|
||||||
g_print (_("Execution ended after %s iterations (sum %s ns, "
|
|
||||||
"average %s ns, min %s ns, max %s ns).\n"),
|
|
||||||
s_iterations, s_sum, s_ave, s_min, s_max);
|
|
||||||
g_free (s_iterations);
|
|
||||||
g_free (s_sum);
|
|
||||||
g_free (s_ave);
|
|
||||||
g_free (s_min);
|
|
||||||
g_free (s_max);
|
|
||||||
}
|
|
||||||
|
|
||||||
return busy;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef GST_DISABLE_LOADSAVE
|
#ifndef GST_DISABLE_LOADSAVE
|
||||||
static GstElement *
|
static GstElement *
|
||||||
|
@ -310,21 +259,6 @@ print_tag (const GstTagList * list, const gchar * tag, gpointer unused)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
found_tag (GObject * pipeline, GstElement * source, GstTagList * tags)
|
|
||||||
{
|
|
||||||
g_print (_("FOUND TAG : found by element \"%s\".\n"),
|
|
||||||
GST_STR_NULL (GST_ELEMENT_NAME (source)));
|
|
||||||
gst_tag_list_foreach (tags, print_tag, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
error_cb (GObject * object, GstObject * source, GError * error, gchar * debug)
|
|
||||||
{
|
|
||||||
gst_element_default_error (object, source, error, debug);
|
|
||||||
caught_error = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef DISABLE_FAULT_HANDLER
|
#ifndef DISABLE_FAULT_HANDLER
|
||||||
/* we only use sighandler here because the registers are not important */
|
/* we only use sighandler here because the registers are not important */
|
||||||
static void
|
static void
|
||||||
|
@ -386,6 +320,38 @@ play_signal_setup (void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
message_received (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
|
||||||
|
{
|
||||||
|
switch (GST_MESSAGE_TYPE (message)) {
|
||||||
|
case GST_MESSAGE_EOS:
|
||||||
|
if (g_main_loop_is_running (loop))
|
||||||
|
g_main_loop_quit (loop);
|
||||||
|
break;
|
||||||
|
case GST_MESSAGE_TAG:
|
||||||
|
if (tags) {
|
||||||
|
g_print (_("FOUND TAG : found by element \"%s\".\n"),
|
||||||
|
GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message))));
|
||||||
|
gst_tag_list_foreach (GST_MESSAGE_TAG_LIST (message), print_tag, NULL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GST_MESSAGE_ERROR:
|
||||||
|
gst_object_default_error (GST_MESSAGE_SRC (message),
|
||||||
|
GST_MESSAGE_ERROR_ERROR (message), GST_MESSAGE_ERROR_DEBUG (message));
|
||||||
|
caught_error = TRUE;
|
||||||
|
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
|
||||||
|
if (g_main_loop_is_running (loop))
|
||||||
|
g_main_loop_quit (loop);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gst_message_unref (message);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char *argv[])
|
main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
@ -393,7 +359,6 @@ main (int argc, char *argv[])
|
||||||
|
|
||||||
/* options */
|
/* options */
|
||||||
gboolean verbose = FALSE;
|
gboolean verbose = FALSE;
|
||||||
gboolean tags = FALSE;
|
|
||||||
gboolean no_fault = FALSE;
|
gboolean no_fault = FALSE;
|
||||||
gboolean trace = FALSE;
|
gboolean trace = FALSE;
|
||||||
gchar *savefile = NULL;
|
gchar *savefile = NULL;
|
||||||
|
@ -501,12 +466,13 @@ main (int argc, char *argv[])
|
||||||
gchar **exclude_list =
|
gchar **exclude_list =
|
||||||
exclude_args ? g_strsplit (exclude_args, ",", 0) : NULL;
|
exclude_args ? g_strsplit (exclude_args, ",", 0) : NULL;
|
||||||
g_signal_connect (pipeline, "deep_notify",
|
g_signal_connect (pipeline, "deep_notify",
|
||||||
G_CALLBACK (gst_element_default_deep_notify), exclude_list);
|
G_CALLBACK (gst_object_default_deep_notify), exclude_list);
|
||||||
}
|
}
|
||||||
if (tags) {
|
|
||||||
g_signal_connect (pipeline, "found-tag", G_CALLBACK (found_tag), NULL);
|
loop = g_main_loop_new (NULL, FALSE);
|
||||||
}
|
gst_bus_add_watch (GST_PIPELINE (pipeline)->bus,
|
||||||
g_signal_connect (pipeline, "error", G_CALLBACK (error_cb), NULL);
|
(GstBusHandler) message_received, pipeline);
|
||||||
|
|
||||||
|
|
||||||
#ifndef GST_DISABLE_LOADSAVE
|
#ifndef GST_DISABLE_LOADSAVE
|
||||||
if (savefile) {
|
if (savefile) {
|
||||||
|
@ -515,6 +481,7 @@ main (int argc, char *argv[])
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!savefile) {
|
if (!savefile) {
|
||||||
|
GstElementState state, pending;
|
||||||
|
|
||||||
if (!GST_IS_BIN (pipeline)) {
|
if (!GST_IS_BIN (pipeline)) {
|
||||||
GstElement *real_pipeline = gst_element_factory_make ("pipeline", NULL);
|
GstElement *real_pipeline = gst_element_factory_make ("pipeline", NULL);
|
||||||
|
@ -527,28 +494,38 @@ main (int argc, char *argv[])
|
||||||
pipeline = real_pipeline;
|
pipeline = real_pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf (stderr, _("RUNNING pipeline ...\n"));
|
fprintf (stderr, _("PREROLL pipeline ...\n"));
|
||||||
if (gst_element_set_state (pipeline,
|
if (gst_element_set_state (pipeline, GST_STATE_PAUSED) == GST_STATE_FAILURE) {
|
||||||
GST_STATE_PLAYING) == GST_STATE_FAILURE) {
|
fprintf (stderr, _("ERROR: pipeline doesn't want to pause.\n"));
|
||||||
fprintf (stderr, _("ERROR: pipeline doesn't want to play.\n"));
|
|
||||||
res = -1;
|
res = -1;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
gst_element_get_state (pipeline, &state, &pending, NULL);
|
||||||
|
/* see if we got any messages */
|
||||||
|
while (g_main_context_iteration (NULL, FALSE));
|
||||||
|
|
||||||
s_clock = gst_bin_get_clock (GST_BIN (pipeline));
|
if (caught_error) {
|
||||||
|
fprintf (stderr, _("ERROR: pipeline doesn't want to preroll.\n"));
|
||||||
if (!GST_FLAG_IS_SET (GST_OBJECT (pipeline), GST_BIN_SELF_SCHEDULABLE)) {
|
|
||||||
g_idle_add (idle_func, pipeline);
|
|
||||||
gst_main ();
|
|
||||||
} else {
|
} else {
|
||||||
g_print ("Waiting for the state change... ");
|
GTimeVal tfthen, tfnow;
|
||||||
gst_element_wait_state_change (pipeline);
|
GstClockTimeDiff diff;
|
||||||
g_print ("got the state change.\n");
|
|
||||||
|
fprintf (stderr, _("RUNNING pipeline ...\n"));
|
||||||
|
if (gst_element_set_state (pipeline,
|
||||||
|
GST_STATE_PLAYING) == GST_STATE_FAILURE) {
|
||||||
|
fprintf (stderr, _("ERROR: pipeline doesn't want to play.\n"));
|
||||||
|
res = -1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_get_current_time (&tfthen);
|
||||||
|
g_main_loop_run (loop);
|
||||||
|
g_get_current_time (&tfnow);
|
||||||
|
|
||||||
|
diff = GST_TIMEVAL_TO_TIME (tfnow) - GST_TIMEVAL_TO_TIME (tfthen);
|
||||||
|
|
||||||
|
g_print (_("Execution ended after %" G_GUINT64_FORMAT " ns.\n"), diff);
|
||||||
}
|
}
|
||||||
if (caught_intr)
|
|
||||||
res = 2;
|
|
||||||
if (caught_error)
|
|
||||||
res = 3;
|
|
||||||
|
|
||||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,8 @@ idle_func (gpointer data)
|
||||||
}
|
}
|
||||||
|
|
||||||
g_get_current_time (&tfthen);
|
g_get_current_time (&tfthen);
|
||||||
busy = gst_bin_iterate (GST_BIN (data));
|
//busy = gst_bin_iterate (GST_BIN (data));
|
||||||
|
busy = FALSE;
|
||||||
iterations++;
|
iterations++;
|
||||||
g_get_current_time (&tfnow);
|
g_get_current_time (&tfnow);
|
||||||
|
|
||||||
|
@ -36,7 +37,7 @@ idle_func (gpointer data)
|
||||||
max = MAX (max, diff);
|
max = MAX (max, diff);
|
||||||
|
|
||||||
if (!busy) {
|
if (!busy) {
|
||||||
gst_main_quit ();
|
//gst_main_quit ();
|
||||||
/*
|
/*
|
||||||
g_print ("execution ended after %llu iterations (sum %llu ns, average %llu ns, min %llu ns, max %llu ns)\n",
|
g_print ("execution ended after %llu iterations (sum %llu ns, average %llu ns, min %llu ns, max %llu ns)\n",
|
||||||
iterations, sum, sum/iterations, min, max);
|
iterations, sum, sum/iterations, min, max);
|
||||||
|
@ -76,7 +77,7 @@ main (int argc, char *argv[])
|
||||||
|
|
||||||
/* Check if we have an element already that is called md5sink0
|
/* Check if we have an element already that is called md5sink0
|
||||||
in the pipeline; if not, add one */
|
in the pipeline; if not, add one */
|
||||||
pipeline = (GstElement *) gst_parse_launchv ((const gchar **) argvn, &error);
|
//pipeline = (GstElement *) gst_parse_launchv ((const gchar **) argvn, &error);
|
||||||
if (!pipeline) {
|
if (!pipeline) {
|
||||||
if (error) {
|
if (error) {
|
||||||
g_warning ("pipeline could not be constructed: %s\n", error->message);
|
g_warning ("pipeline could not be constructed: %s\n", error->message);
|
||||||
|
@ -115,22 +116,17 @@ main (int argc, char *argv[])
|
||||||
: NULL;
|
: NULL;
|
||||||
|
|
||||||
g_signal_connect (pipeline, "deep_notify",
|
g_signal_connect (pipeline, "deep_notify",
|
||||||
G_CALLBACK (gst_element_default_deep_notify), exclude_list);
|
G_CALLBACK (gst_object_default_deep_notify), exclude_list);
|
||||||
}
|
}
|
||||||
g_signal_connect (pipeline, "error",
|
//g_signal_connect (pipeline, "error",
|
||||||
G_CALLBACK (gst_element_default_error), NULL);
|
// G_CALLBACK (gst_object_default_error), NULL);
|
||||||
|
|
||||||
if (gst_element_set_state (pipeline, GST_STATE_PLAYING) != GST_STATE_SUCCESS) {
|
if (gst_element_set_state (pipeline, GST_STATE_PLAYING) != GST_STATE_SUCCESS) {
|
||||||
g_warning ("pipeline doesn't want to play\n");
|
g_warning ("pipeline doesn't want to play\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!GST_FLAG_IS_SET (GST_OBJECT (pipeline), GST_BIN_SELF_SCHEDULABLE)) {
|
gst_main ();
|
||||||
g_idle_add (idle_func, pipeline);
|
|
||||||
gst_main ();
|
|
||||||
} else {
|
|
||||||
gst_element_wait_state_change (pipeline);
|
|
||||||
}
|
|
||||||
|
|
||||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||||
|
|
||||||
|
|
|
@ -52,8 +52,10 @@ main (int argc, char *argv[])
|
||||||
g_assert (GST_IS_ELEMENT (source));
|
g_assert (GST_IS_ELEMENT (source));
|
||||||
typefind = gst_element_factory_make ("typefind", "typefind");
|
typefind = gst_element_factory_make ("typefind", "typefind");
|
||||||
g_assert (GST_IS_ELEMENT (typefind));
|
g_assert (GST_IS_ELEMENT (typefind));
|
||||||
gst_bin_add_many (GST_BIN (pipeline), source, typefind, NULL);
|
gst_bin_add (GST_BIN (pipeline), source);
|
||||||
gst_element_link (source, typefind);
|
gst_bin_add (GST_BIN (pipeline), typefind);
|
||||||
|
gst_pad_link (gst_element_get_pad (source, "src"),
|
||||||
|
gst_element_get_pad (typefind, "sink"));
|
||||||
g_signal_connect (G_OBJECT (typefind), "have-type",
|
g_signal_connect (G_OBJECT (typefind), "have-type",
|
||||||
G_CALLBACK (have_type_handler), NULL);
|
G_CALLBACK (have_type_handler), NULL);
|
||||||
|
|
||||||
|
@ -66,8 +68,6 @@ main (int argc, char *argv[])
|
||||||
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
|
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
|
||||||
|
|
||||||
while (!FOUND) {
|
while (!FOUND) {
|
||||||
if (!gst_bin_iterate (GST_BIN (pipeline)))
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (!FOUND) {
|
if (!FOUND) {
|
||||||
g_print ("%s - No type found\n", argv[i]);
|
g_print ("%s - No type found\n", argv[i]);
|
||||||
|
|
|
@ -472,8 +472,6 @@ print_element_info (GstElementFactory * factory)
|
||||||
GstPad *pad;
|
GstPad *pad;
|
||||||
GstRealPad *realpad;
|
GstRealPad *realpad;
|
||||||
GstPadTemplate *padtemplate;
|
GstPadTemplate *padtemplate;
|
||||||
GList *children;
|
|
||||||
GstElement *child;
|
|
||||||
gint maxlevel = 0;
|
gint maxlevel = 0;
|
||||||
|
|
||||||
element = gst_element_factory_create (factory, "element");
|
element = gst_element_factory_create (factory, "element");
|
||||||
|
@ -533,40 +531,16 @@ print_element_info (GstElementFactory * factory)
|
||||||
PUT_END_TAG (1, "pad-templates");
|
PUT_END_TAG (1, "pad-templates");
|
||||||
|
|
||||||
PUT_START_TAG (1, "element-flags");
|
PUT_START_TAG (1, "element-flags");
|
||||||
if (GST_FLAG_IS_SET (element, GST_ELEMENT_COMPLEX)) {
|
|
||||||
PUT_ESCAPED (2, "flag", "GST_ELEMENT_COMPLEX");
|
|
||||||
}
|
|
||||||
if (GST_FLAG_IS_SET (element, GST_ELEMENT_DECOUPLED)) {
|
|
||||||
PUT_ESCAPED (2, "flag", "GST_ELEMENT_DECOUPLED");
|
|
||||||
}
|
|
||||||
if (GST_FLAG_IS_SET (element, GST_ELEMENT_THREAD_SUGGESTED)) {
|
|
||||||
PUT_ESCAPED (2, "flag", "GST_ELEMENT_THREADSUGGESTED");
|
|
||||||
}
|
|
||||||
if (GST_FLAG_IS_SET (element, GST_ELEMENT_EVENT_AWARE)) {
|
|
||||||
PUT_ESCAPED (2, "flag", "GST_ELEMENT_EVENT_AWARE");
|
|
||||||
}
|
|
||||||
PUT_END_TAG (1, "element-flags");
|
PUT_END_TAG (1, "element-flags");
|
||||||
|
|
||||||
if (GST_IS_BIN (element)) {
|
if (GST_IS_BIN (element)) {
|
||||||
PUT_START_TAG (1, "bin-flags");
|
PUT_START_TAG (1, "bin-flags");
|
||||||
|
|
||||||
if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) {
|
|
||||||
PUT_ESCAPED (2, "flag", "GST_BIN_FLAG_MANAGER");
|
|
||||||
}
|
|
||||||
if (GST_FLAG_IS_SET (element, GST_BIN_SELF_SCHEDULABLE)) {
|
|
||||||
PUT_ESCAPED (2, "flag", "GST_BIN_SELF_SCHEDULABLE");
|
|
||||||
}
|
|
||||||
if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_PREFER_COTHREADS)) {
|
|
||||||
PUT_ESCAPED (2, "flag", "GST_BIN_FLAG_PREFER_COTHREADS");
|
|
||||||
}
|
|
||||||
PUT_END_TAG (1, "bin-flags");
|
PUT_END_TAG (1, "bin-flags");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PUT_START_TAG (1, "element-implementation");
|
PUT_START_TAG (1, "element-implementation");
|
||||||
if (element->loopfunc)
|
|
||||||
PUT_STRING (2, "<loop-based function=\"%s\"/>",
|
|
||||||
GST_DEBUG_FUNCPTR_NAME (element->loopfunc));
|
|
||||||
|
|
||||||
PUT_STRING (2, "<state-change function=\"%s\"/>",
|
PUT_STRING (2, "<state-change function=\"%s\"/>",
|
||||||
GST_DEBUG_FUNCPTR_NAME (gstelement_class->change_state));
|
GST_DEBUG_FUNCPTR_NAME (gstelement_class->change_state));
|
||||||
|
@ -681,17 +655,21 @@ print_element_info (GstElementFactory * factory)
|
||||||
print_element_signals (element, 1);
|
print_element_signals (element, 1);
|
||||||
|
|
||||||
/* for compound elements */
|
/* for compound elements */
|
||||||
if (GST_IS_BIN (element)) {
|
/* FIXME: gst_bin_get_list does not exist anymore
|
||||||
PUT_START_TAG (1, "children");
|
if (GST_IS_BIN (element)) {
|
||||||
children = (GList *) gst_bin_get_list (GST_BIN (element));
|
GList *children;
|
||||||
while (children) {
|
GstElement *child;
|
||||||
child = GST_ELEMENT (children->data);
|
PUT_START_TAG (1, "children");
|
||||||
children = g_list_next (children);
|
children = (GList *) gst_bin_get_list (GST_BIN (element));
|
||||||
|
while (children) {
|
||||||
|
child = GST_ELEMENT (children->data);
|
||||||
|
children = g_list_next (children);
|
||||||
|
|
||||||
PUT_ESCAPED (2, "child", GST_ELEMENT_NAME (child));
|
PUT_ESCAPED (2, "child", GST_ELEMENT_NAME (child));
|
||||||
}
|
}
|
||||||
PUT_END_TAG (1, "children");
|
PUT_END_TAG (1, "children");
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
PUT_END_TAG (0, "element");
|
PUT_END_TAG (0, "element");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in a new issue