mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 02:01:12 +00:00
merge TYPEFIND branch. Major changes:
Original commit message from CVS: merge TYPEFIND branch. Major changes: - totally reworked type(find) system - bytestream is out of the core again - typefind element is now part of gstelements
This commit is contained in:
parent
208c0e3089
commit
3235f1d4c0
54 changed files with 5090 additions and 913 deletions
|
@ -372,8 +372,6 @@ GST_SUBSYSTEM_DISABLE(GST_DEBUG,[debugging subsystem])
|
||||||
|
|
||||||
translit(dnm, m, l) AM_CONDITIONAL(GST_DISABLE_LOADSAVE, true)
|
translit(dnm, m, l) AM_CONDITIONAL(GST_DISABLE_LOADSAVE, true)
|
||||||
GST_SUBSYSTEM_DISABLE(LOADSAVE,[pipeline XML load/save])
|
GST_SUBSYSTEM_DISABLE(LOADSAVE,[pipeline XML load/save])
|
||||||
translit(dnm, m, l) AM_CONDITIONAL(GST_DISABLE_TYPEFIND, true)
|
|
||||||
GST_SUBSYSTEM_DISABLE(TYPEFIND,[typefind plugin],)
|
|
||||||
translit(dnm, m, l) AM_CONDITIONAL(GST_DISABLE_AUTOPLUG, true)
|
translit(dnm, m, l) AM_CONDITIONAL(GST_DISABLE_AUTOPLUG, true)
|
||||||
GST_SUBSYSTEM_DISABLE(AUTOPLUG,[autoplugger subsystem])
|
GST_SUBSYSTEM_DISABLE(AUTOPLUG,[autoplugger subsystem])
|
||||||
translit(dnm, m, l) AM_CONDITIONAL(GST_DISABLE_PARSE, true)
|
translit(dnm, m, l) AM_CONDITIONAL(GST_DISABLE_PARSE, true)
|
||||||
|
@ -562,12 +560,12 @@ gst/indexers/Makefile
|
||||||
gst/elements/Makefile
|
gst/elements/Makefile
|
||||||
gst/parse/Makefile
|
gst/parse/Makefile
|
||||||
gst/schedulers/Makefile
|
gst/schedulers/Makefile
|
||||||
gst/types/Makefile
|
|
||||||
gst/registries/Makefile
|
gst/registries/Makefile
|
||||||
libs/Makefile
|
libs/Makefile
|
||||||
libs/gst/Makefile
|
libs/gst/Makefile
|
||||||
libs/gst/getbits/Makefile
|
libs/gst/bytestream/Makefile
|
||||||
libs/gst/control/Makefile
|
libs/gst/control/Makefile
|
||||||
|
libs/gst/getbits/Makefile
|
||||||
libs/ext/Makefile
|
libs/ext/Makefile
|
||||||
po/Makefile.in
|
po/Makefile.in
|
||||||
tests/Makefile
|
tests/Makefile
|
||||||
|
|
|
@ -29,8 +29,8 @@
|
||||||
<!ENTITY GstRegistryPool SYSTEM "xml/gstregistrypool.xml">
|
<!ENTITY GstRegistryPool SYSTEM "xml/gstregistrypool.xml">
|
||||||
<!ENTITY GstScheduler SYSTEM "xml/gstscheduler.xml">
|
<!ENTITY GstScheduler SYSTEM "xml/gstscheduler.xml">
|
||||||
<!ENTITY GstTrace SYSTEM "xml/gsttrace.xml">
|
<!ENTITY GstTrace SYSTEM "xml/gsttrace.xml">
|
||||||
<!ENTITY GstType SYSTEM "xml/gsttype.xml">
|
<!ENTITY GstTypeFind SYSTEM "xml/gsttypefind.xml">
|
||||||
<!ENTITY GstTypeFactory SYSTEM "xml/gsttype.xml">
|
<!ENTITY GstTypeFindFactory SYSTEM "xml/gsttypefindfactory.xml">
|
||||||
<!ENTITY GstCaps SYSTEM "xml/gstcaps.xml">
|
<!ENTITY GstCaps SYSTEM "xml/gstcaps.xml">
|
||||||
<!ENTITY GstProps SYSTEM "xml/gstprops.xml">
|
<!ENTITY GstProps SYSTEM "xml/gstprops.xml">
|
||||||
<!ENTITY GstClock SYSTEM "xml/gstclock.xml">
|
<!ENTITY GstClock SYSTEM "xml/gstclock.xml">
|
||||||
|
@ -40,7 +40,6 @@
|
||||||
<!ENTITY GstXML SYSTEM "xml/gstxml.xml">
|
<!ENTITY GstXML SYSTEM "xml/gstxml.xml">
|
||||||
<!-- these are elements without API docs
|
<!-- these are elements without API docs
|
||||||
<!ENTITY GstQueue SYSTEM "xml/gstqueue.xml">
|
<!ENTITY GstQueue SYSTEM "xml/gstqueue.xml">
|
||||||
<!ENTITY GstTypeFind SYSTEM "xml/gsttypefind.xml">
|
|
||||||
-->
|
-->
|
||||||
<!ENTITY GstIndex SYSTEM "xml/gstindex.xml">
|
<!ENTITY GstIndex SYSTEM "xml/gstindex.xml">
|
||||||
<!ENTITY cothreads SYSTEM "xml/cothreads.xml">
|
<!ENTITY cothreads SYSTEM "xml/cothreads.xml">
|
||||||
|
@ -118,9 +117,8 @@ with some more specialized elements.</para>
|
||||||
&GstScheduler;
|
&GstScheduler;
|
||||||
&GstSystemClock;
|
&GstSystemClock;
|
||||||
&GstThread;
|
&GstThread;
|
||||||
&GstType;
|
&GstTypeFind;
|
||||||
<!-- no API docs
|
&GstTypeFindFactory;
|
||||||
&GstTypeFind; -->
|
|
||||||
&GstUri;
|
&GstUri;
|
||||||
&GstUtils;
|
&GstUtils;
|
||||||
&GstXML;
|
&GstXML;
|
||||||
|
|
|
@ -1254,38 +1254,33 @@ gst_alloc_trace_flags_get_type
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<FILE>gsttype</FILE>
|
<FILE>gsttypefind</FILE>
|
||||||
<TITLE>GstType</TITLE>
|
<TITLE>Writing typefind functions</TITLE>
|
||||||
GstType
|
GstTypeFind
|
||||||
gst_type_register
|
GstTypeFindFunction
|
||||||
gst_type_find_by_mime
|
gst_type_find_peek
|
||||||
gst_type_find_by_ext
|
gst_type_find_suggest
|
||||||
gst_type_find_by_id
|
gst_type_find_get_length
|
||||||
gst_type_get_list
|
gst_type_find_factory_register
|
||||||
<SUBSECTION Standard>
|
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<FILE>gsttypefactory</FILE>
|
<FILE>gsttypefindfactory</FILE>
|
||||||
<TITLE>GstTypeFactory</TITLE>
|
<TITLE>GstTypeFindFactory</TITLE>
|
||||||
GstTypeFactory
|
GstTypeFindFactory
|
||||||
GstTypeDefinition
|
GstTypeFindFactoryClass
|
||||||
GstTypeFindFunc
|
gst_type_find_factory_get_list
|
||||||
gst_type_factory_new
|
gst_type_find_factory_get_extensions
|
||||||
gst_type_factory_find
|
gst_type_find_factory_get_caps
|
||||||
|
gst_type_find_factory_call_function
|
||||||
<SUBSECTION Standard>
|
<SUBSECTION Standard>
|
||||||
GstTypeFind
|
GST_TYPE_FIND_FACTORY
|
||||||
GstTypeFindClass
|
GST_IS_TYPE_FIND_FACTORY
|
||||||
GST_TYPE_FACTORY
|
GST_TYPE_TYPE_FIND_FACTORY
|
||||||
GST_IS_TYPE_FACTORY
|
gst_type_find_factory_get_type
|
||||||
GST_TYPE_TYPE_FACTORY
|
GST_TYPE_FIND_FACTORY_CLASS
|
||||||
gst_type_factory_get_type
|
GST_IS_TYPE_FIND_FACTORY_CLASS
|
||||||
GST_TYPE_FACTORY_CLASS
|
GST_TYPE_FIND_FACTORY_GET_CLASS
|
||||||
GST_IS_TYPE_FACTORY_CLASS
|
|
||||||
GST_IS_TYPE_FIND
|
|
||||||
GST_IS_TYPE_FIND_CLASS
|
|
||||||
GST_TYPE_FACTORY_GET_CLASS
|
|
||||||
GstTypeFactoryClass
|
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
|
@ -1325,8 +1320,6 @@ gst_caps_replace_sink
|
||||||
gst_caps_sink
|
gst_caps_sink
|
||||||
gst_caps_set_name
|
gst_caps_set_name
|
||||||
gst_caps_get_name
|
gst_caps_get_name
|
||||||
gst_caps_set_type_id
|
|
||||||
gst_caps_get_type_id
|
|
||||||
gst_caps_set_mime
|
gst_caps_set_mime
|
||||||
gst_caps_get_mime
|
gst_caps_get_mime
|
||||||
gst_caps_set_props
|
gst_caps_set_props
|
||||||
|
|
|
@ -13,7 +13,7 @@ gst_thread_get_type
|
||||||
gst_plugin_feature_get_type
|
gst_plugin_feature_get_type
|
||||||
gst_autoplug_get_type
|
gst_autoplug_get_type
|
||||||
gst_autoplug_factory_get_type
|
gst_autoplug_factory_get_type
|
||||||
gst_type_factory_get_type
|
gst_type_find_factory_get_type
|
||||||
gst_element_factory_get_type
|
gst_element_factory_get_type
|
||||||
gst_scheduler_factory_get_type
|
gst_scheduler_factory_get_type
|
||||||
gst_scheduler_get_type
|
gst_scheduler_get_type
|
||||||
|
|
|
@ -1,108 +0,0 @@
|
||||||
<!-- ##### SECTION Title ##### -->
|
|
||||||
GstType
|
|
||||||
|
|
||||||
<!-- ##### SECTION Short_Description ##### -->
|
|
||||||
Identifies the data
|
|
||||||
|
|
||||||
<!-- ##### SECTION Long_Description ##### -->
|
|
||||||
<para>
|
|
||||||
GstTypes exist to try to make sure data eveyrone is talking about the
|
|
||||||
right kind of data. They aid quite a bit in autoplugging, in fact make it
|
|
||||||
possible. Each well-formed type includes a function (typefind) that will
|
|
||||||
take one or more buffers and determine whether or not it is indeed a
|
|
||||||
stream of that type, and possible a metadata to go with it. It may
|
|
||||||
provide related metadata structure IDs (and must if it provides metadata
|
|
||||||
from the typefind function).
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Because multiple elements and plugins are very likely to be using the same
|
|
||||||
types, the process of creating/finding types is designed to be done with a
|
|
||||||
single function call. All operations on GstTypes occur via their guint16
|
|
||||||
ID numbers, with the GstType structure "private" to the GST library. A
|
|
||||||
plugin wishing to use a give type would contain a static struct of type
|
|
||||||
GstTypeFactory, which lists the MIME type, possible extensions (which may
|
|
||||||
overlap the mime-types file), a typefind function, and any other cruft I
|
|
||||||
decide to add.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
A plugin init function would take this typefactory and hand it to the
|
|
||||||
gst_type_new() (FIXME: badly named) function, which would first search for
|
|
||||||
that same MIME type in the current list. If it found one, it would
|
|
||||||
compare the two to see if the new one is "better". Better is defined as
|
|
||||||
having more extentions (to be merged) or a typefind function verses none.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The point of returning an existing MIME type is a result of the goal of
|
|
||||||
unifying types enough to guarantee that, for instance, all MP3 decoders
|
|
||||||
will work interchangably. If MP3 decoder A says "MIME type 'audio/mpeg'
|
|
||||||
with extensions 'mpeg3'" and decoder B says "MIME type 'audio/mpeg' with
|
|
||||||
extensions 'mp3'", we don't want to have two types defined, possibly with
|
|
||||||
two typefind functions. If we did, it's not obvious which of the two would
|
|
||||||
be tried first (luck) and if both would really identify streams as mp3
|
|
||||||
correctly in all cases. And whichever wins, we're stuck using the
|
|
||||||
associated decoder to play that stream. We lose the choice between any
|
|
||||||
valid mp3 decoder, and thus the whole point of the type system.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<!-- ##### SECTION See_Also ##### -->
|
|
||||||
<para>
|
|
||||||
#GstTypeFactory
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<!-- ##### STRUCT GstType ##### -->
|
|
||||||
<para>
|
|
||||||
A type.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@id:
|
|
||||||
@mime:
|
|
||||||
@exts:
|
|
||||||
@factories:
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION gst_type_register ##### -->
|
|
||||||
<para>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@factory:
|
|
||||||
@Returns:
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION gst_type_find_by_mime ##### -->
|
|
||||||
<para>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@mime:
|
|
||||||
@Returns:
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION gst_type_find_by_ext ##### -->
|
|
||||||
<para>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@ext:
|
|
||||||
@Returns:
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION gst_type_find_by_id ##### -->
|
|
||||||
<para>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@id:
|
|
||||||
@Returns:
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION gst_type_get_list ##### -->
|
|
||||||
<para>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@Returns:
|
|
||||||
|
|
||||||
|
|
|
@ -1,101 +0,0 @@
|
||||||
<!-- ##### SECTION Title ##### -->
|
|
||||||
GstTypeFactory
|
|
||||||
|
|
||||||
<!-- ##### SECTION Short_Description ##### -->
|
|
||||||
Add types to plugins.
|
|
||||||
|
|
||||||
<!-- ##### SECTION Long_Description ##### -->
|
|
||||||
<para>
|
|
||||||
A GstTypeFactory is used to add a new type and a typedetection function
|
|
||||||
to a plugin. Typefactories are named so they can be found with
|
|
||||||
gst_type_factory_find().
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
gst_type_factory_new() is used to create a new typefactory from the given
|
|
||||||
#GstTypeDefinition. A typefactory is added to a #GstPlugin with
|
|
||||||
gst_plugin_add_feature() as shown in the example:
|
|
||||||
<programlisting>
|
|
||||||
static GstCaps*
|
|
||||||
avi_type_find (GstBuffer *buf, gpointer private)
|
|
||||||
{
|
|
||||||
gchar *data = GST_BUFFER_DATA (buf);
|
|
||||||
|
|
||||||
if (strncmp (&data[0], "RIFF", 4)) return NULL;
|
|
||||||
if (strncmp (&data[8], "AVI ", 4)) return NULL;
|
|
||||||
|
|
||||||
return gst_caps_new ("avi_type_find","video/avi", NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* typedefinition for 'avi' */
|
|
||||||
static GstTypeDefinition avidefinition = {
|
|
||||||
"avidecoder_video/avi", /* the name of this definition */
|
|
||||||
"video/avi", /* the mime type */
|
|
||||||
".avi", /* the file extensions */
|
|
||||||
avi_type_find, /* a pointer to a GstTypeFindFunc function */
|
|
||||||
};
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
plugin_init (GModule *module, GstPlugin *plugin)
|
|
||||||
{
|
|
||||||
GstTypeFactory *type;
|
|
||||||
...
|
|
||||||
type = gst_type_factory_new (&avidefinition);
|
|
||||||
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (type));
|
|
||||||
...
|
|
||||||
}
|
|
||||||
</programlisting>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<!-- ##### SECTION See_Also ##### -->
|
|
||||||
<para>
|
|
||||||
#GstPluginFeature, #GstPlugin
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<!-- ##### STRUCT GstTypeFactory ##### -->
|
|
||||||
<para>
|
|
||||||
The struct with the typefactory information.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### STRUCT GstTypeDefinition ##### -->
|
|
||||||
<para>
|
|
||||||
The typedefinition structure.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@name: The name of this factory
|
|
||||||
@mime: The mime type of the new type.
|
|
||||||
@exts: The extensions of this type.
|
|
||||||
@typefindfunc: An optional typefind function.
|
|
||||||
|
|
||||||
<!-- ##### USER_FUNCTION GstTypeFindFunc ##### -->
|
|
||||||
<para>
|
|
||||||
This is the function that will be called when a typefind has to be
|
|
||||||
performed by a plugin.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@bs:
|
|
||||||
@priv: private; don't touch
|
|
||||||
@Returns: A #GstCaps structure describing the type or NULL if the
|
|
||||||
type was not recognized by this function;
|
|
||||||
<!-- # Unused Parameters # -->
|
|
||||||
@buf: the buffer with media on which to perform the typefind
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION gst_type_factory_new ##### -->
|
|
||||||
<para>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@definition:
|
|
||||||
@Returns:
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION gst_type_factory_find ##### -->
|
|
||||||
<para>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
|
|
||||||
@name:
|
|
||||||
@Returns:
|
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,114 @@
|
||||||
<!-- ##### SECTION Title ##### -->
|
<!-- ##### SECTION Title ##### -->
|
||||||
GstTypeFind
|
Writing typefind functions
|
||||||
|
|
||||||
<!-- ##### SECTION Short_Description ##### -->
|
<!-- ##### SECTION Short_Description ##### -->
|
||||||
Detect the mime type of a media stream
|
Using the type finding subsystem from plugins
|
||||||
|
|
||||||
<!-- ##### SECTION Long_Description ##### -->
|
<!-- ##### SECTION Long_Description ##### -->
|
||||||
<para>
|
<para>
|
||||||
This element can be added to the pipeline and will notify the listener of
|
The typefinding subsystem in GStreamer is used to find the matching #GstCaps
|
||||||
the detected mime type of the stream. It is used in autoplugging.
|
for an unidentified stream. This works similar to the unix <emphasis>file
|
||||||
|
</emphasis> command.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
There are a number of elements which output unidentified data streams, such as
|
||||||
|
a file source. Some other elements such as an autoplugger require a proper
|
||||||
|
identification of the data, so they can create the right pipeline. To find the
|
||||||
|
right type, they use typefinding elements, the most notable being the typefind
|
||||||
|
element. These elements take a list of all registered typefind functions and
|
||||||
|
try them on the data to see if any of these functions can identify the data.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The functions in this section provide the simple framework for writing these
|
||||||
|
typefind functions. The job of a typefind function is to identify the type of
|
||||||
|
the data good enough so that plugins using this type can understand them while
|
||||||
|
make sure no other type is misidentified.
|
||||||
|
<example>
|
||||||
|
<title>a typefind function for Ogg data</title>
|
||||||
|
<programlisting>
|
||||||
|
static void
|
||||||
|
ogg_type_find (GstTypeFind *tf, gpointer unused)
|
||||||
|
{
|
||||||
|
guint8 *data = gst_type_find_peek (tf, 0, 4);
|
||||||
|
|
||||||
|
if (data && memcmp (data, "OggS", 4) == 0) {
|
||||||
|
gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM,
|
||||||
|
gst_caps_new ("ogg_type_find", "application/ogg", NULL));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</programlisting>
|
||||||
|
</example>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<!-- ##### SECTION See_Also ##### -->
|
<!-- ##### SECTION See_Also ##### -->
|
||||||
<para>
|
<para>
|
||||||
|
<link linkend="GstTypeFindFactory">GstTypeFactory - querying registered typefind
|
||||||
|
functions</link>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<!-- ##### VARIABLE gst_type_find_details ##### -->
|
<!-- ##### STRUCT GstTypeFind ##### -->
|
||||||
|
<para>
|
||||||
|
This structure is filled by the caller of the typefind function. Typefind
|
||||||
|
functions must treat this as an opaque structure.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
@peek: function called to get data. See gst_type_find_peek()
|
||||||
|
@suggest: function called to suggest a caps. See gst_type_find_suggest()
|
||||||
|
@data: caller defined data, that is passed when calling the functions
|
||||||
|
@get_length: function called to query the length of the stream. See
|
||||||
|
gst_type_find_get_length(). Providing this function is optional.
|
||||||
|
|
||||||
|
<!-- ##### USER_FUNCTION GstTypeFindFunction ##### -->
|
||||||
|
<para>
|
||||||
|
This is the prototype for a typefind function.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
@find: The #GstTypeFind data
|
||||||
|
@data: the user defined data that was provided on
|
||||||
|
gst_type_find_factory_register()
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ##### FUNCTION gst_type_find_peek ##### -->
|
||||||
<para>
|
<para>
|
||||||
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
@find:
|
||||||
|
@offset:
|
||||||
|
@size:
|
||||||
|
@Returns:
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ##### FUNCTION gst_type_find_suggest ##### -->
|
||||||
|
<para>
|
||||||
|
|
||||||
|
</para>
|
||||||
|
|
||||||
|
@find:
|
||||||
|
@probability:
|
||||||
|
@caps:
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ##### FUNCTION gst_type_find_get_length ##### -->
|
||||||
|
<para>
|
||||||
|
|
||||||
|
</para>
|
||||||
|
|
||||||
|
@find:
|
||||||
|
@Returns:
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ##### FUNCTION gst_type_find_factory_register ##### -->
|
||||||
|
<para>
|
||||||
|
|
||||||
|
</para>
|
||||||
|
|
||||||
|
@plugin:
|
||||||
|
@name:
|
||||||
|
@rank:
|
||||||
|
@func:
|
||||||
|
@extensions:
|
||||||
|
@possible_caps:
|
||||||
|
@data:
|
||||||
|
|
||||||
|
|
||||||
|
|
117
docs/gst/tmpl/gsttypefindfactory.sgml
Normal file
117
docs/gst/tmpl/gsttypefindfactory.sgml
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
<!-- ##### SECTION Title ##### -->
|
||||||
|
GstTypeFindFactory
|
||||||
|
|
||||||
|
<!-- ##### SECTION Short_Description ##### -->
|
||||||
|
information about registered typefind functions
|
||||||
|
|
||||||
|
<!-- ##### SECTION Long_Description ##### -->
|
||||||
|
<para>
|
||||||
|
These functions allow querying informations about registered typefind
|
||||||
|
functions. How to create and register these functions is described in
|
||||||
|
the section <link linkend="gstreamer-Writing-typefind-functions">
|
||||||
|
"Writing typefind functions"</link>.
|
||||||
|
</para>
|
||||||
|
<example>
|
||||||
|
<title>how to write a simple typefinder</title>
|
||||||
|
<programlisting>
|
||||||
|
/* FIXME: compile this? ;) */
|
||||||
|
typedef struct {
|
||||||
|
guint8 *data;
|
||||||
|
guint size;
|
||||||
|
guint probability;
|
||||||
|
GstCaps *data;
|
||||||
|
} MyTypeFind;
|
||||||
|
static void
|
||||||
|
my_peek (gpointer data, gint64 offset, guint size)
|
||||||
|
{
|
||||||
|
MyTypeFind *find = (MyTypeFind *) data;
|
||||||
|
if (offset >= 0 && offset + size <= find->size) {
|
||||||
|
return find->data + offset;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
my_suggest (gpointer data, guint probability, GstCaps *caps)
|
||||||
|
{
|
||||||
|
MyTypeFind *find = (MyTypeFind *) data;
|
||||||
|
if (probability > find->probability) {
|
||||||
|
find->probability = probability;
|
||||||
|
gst_caps_replace (&find->caps, caps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static GstCaps *
|
||||||
|
find_type (guint8 *data, guint size)
|
||||||
|
{
|
||||||
|
GList *walk, *type_list;
|
||||||
|
MyTypeFind find = {data, size, 0, NULL};
|
||||||
|
GstTypeFind gst_find = {my_peek, my_suggest, &find, };
|
||||||
|
|
||||||
|
walk = type_list = gst_type_find_factory_get_list ();
|
||||||
|
while (walk) {
|
||||||
|
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (walk->data);
|
||||||
|
walk = g_list_next (walk)
|
||||||
|
gst_type_find_factory_call_function (factory, &gst_find);
|
||||||
|
}
|
||||||
|
g_list_free (type_list);
|
||||||
|
return find.caps;
|
||||||
|
};
|
||||||
|
</programlisting>
|
||||||
|
</example>
|
||||||
|
<para>
|
||||||
|
The above example shows how to write a very simple typefinder that identifies
|
||||||
|
the given data. You can get quite a bit more complicated than that though.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<!-- ##### SECTION See_Also ##### -->
|
||||||
|
<para>
|
||||||
|
<link linkend="gstreamer-Writing-typefind-functions">Writing typefind functions</link>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<!-- ##### STRUCT GstTypeFindFactory ##### -->
|
||||||
|
<para>
|
||||||
|
Object that stores information about a typefind function
|
||||||
|
</para>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ##### STRUCT GstTypeFindFactoryClass ##### -->
|
||||||
|
<para>
|
||||||
|
Class belonging to #GstTypeFindFactory.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
@parent:
|
||||||
|
|
||||||
|
<!-- ##### FUNCTION gst_type_find_factory_get_list ##### -->
|
||||||
|
<para>
|
||||||
|
|
||||||
|
</para>
|
||||||
|
|
||||||
|
@Returns:
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ##### FUNCTION gst_type_find_factory_get_extensions ##### -->
|
||||||
|
<para>
|
||||||
|
|
||||||
|
</para>
|
||||||
|
|
||||||
|
@factory:
|
||||||
|
@Returns:
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ##### FUNCTION gst_type_find_factory_get_caps ##### -->
|
||||||
|
<para>
|
||||||
|
|
||||||
|
</para>
|
||||||
|
|
||||||
|
@factory:
|
||||||
|
@Returns:
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ##### FUNCTION gst_type_find_factory_call_function ##### -->
|
||||||
|
<para>
|
||||||
|
|
||||||
|
</para>
|
||||||
|
|
||||||
|
@factory:
|
||||||
|
@find:
|
||||||
|
|
||||||
|
|
|
@ -15,12 +15,6 @@ else
|
||||||
GST_LOADSAVE_SRC = gstxml.c
|
GST_LOADSAVE_SRC = gstxml.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if GST_DISABLE_TYPEFIND
|
|
||||||
GST_TYPEFIND_SRC =
|
|
||||||
else
|
|
||||||
GST_TYPEFIND_SRC = gsttypefind.c
|
|
||||||
endif
|
|
||||||
|
|
||||||
if GST_DISABLE_AUTOPLUG
|
if GST_DISABLE_AUTOPLUG
|
||||||
GST_AUTOPLUG_SRC =
|
GST_AUTOPLUG_SRC =
|
||||||
GST_AUTOPLUG_DIRS =
|
GST_AUTOPLUG_DIRS =
|
||||||
|
@ -81,10 +75,10 @@ else
|
||||||
GST_URI_SRC = gsturi.c
|
GST_URI_SRC = gsturi.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
EXTRA_libgstreamer_@GST_MAJORMINOR@_la_SOURCES = gstcpuid_i386.s gstmarshal.list gstxml.c gsttypefind.c gstparse.c gstautoplug.c gsttrace.c
|
EXTRA_libgstreamer_@GST_MAJORMINOR@_la_SOURCES = gstcpuid_i386.s gstmarshal.list gstxml.c gstparse.c gstautoplug.c gsttrace.c
|
||||||
|
|
||||||
SUBDIRS = $(GST_PARSE_DIRS) $(GST_REGISTRY_DIRS) . $(GST_AUTOPLUG_DIRS) elements schedulers types $(GST_INDEX_DIRS)
|
SUBDIRS = $(GST_PARSE_DIRS) $(GST_REGISTRY_DIRS) . $(GST_AUTOPLUG_DIRS) elements schedulers $(GST_INDEX_DIRS)
|
||||||
DIST_SUBDIRS = autoplug elements parse registries schedulers types indexers
|
DIST_SUBDIRS = autoplug elements parse registries schedulers indexers
|
||||||
|
|
||||||
libgstreamer_@GST_MAJORMINOR@_la_SOURCES = \
|
libgstreamer_@GST_MAJORMINOR@_la_SOURCES = \
|
||||||
gst.c \
|
gst.c \
|
||||||
|
@ -96,7 +90,6 @@ libgstreamer_@GST_MAJORMINOR@_la_SOURCES = \
|
||||||
gstbin.c \
|
gstbin.c \
|
||||||
gstbuffer.c \
|
gstbuffer.c \
|
||||||
gstbufferpool-default.c \
|
gstbufferpool-default.c \
|
||||||
gstbytestream.c \
|
|
||||||
gstcaps.c \
|
gstcaps.c \
|
||||||
gstclock.c \
|
gstclock.c \
|
||||||
gstcpu.c \
|
gstcpu.c \
|
||||||
|
@ -124,8 +117,7 @@ libgstreamer_@GST_MAJORMINOR@_la_SOURCES = \
|
||||||
gstthreaddummy.c \
|
gstthreaddummy.c \
|
||||||
$(GST_TRACE_SRC) \
|
$(GST_TRACE_SRC) \
|
||||||
gsttrashstack.c \
|
gsttrashstack.c \
|
||||||
gsttype.c \
|
gsttypefind.c \
|
||||||
$(GST_TYPEFIND_SRC) \
|
|
||||||
$(GST_URI_SRC) \
|
$(GST_URI_SRC) \
|
||||||
gsturitype.c \
|
gsturitype.c \
|
||||||
gstutils.c \
|
gstutils.c \
|
||||||
|
@ -153,12 +145,10 @@ gst_headers = \
|
||||||
gst.h \
|
gst.h \
|
||||||
gstatomic.h \
|
gstatomic.h \
|
||||||
gstobject.h \
|
gstobject.h \
|
||||||
gsttypes.h \
|
|
||||||
gstautoplug.h \
|
gstautoplug.h \
|
||||||
gstbin.h \
|
gstbin.h \
|
||||||
gstbuffer.h \
|
gstbuffer.h \
|
||||||
gstbufferpool-default.h \
|
gstbufferpool-default.h \
|
||||||
gstbytestream.h \
|
|
||||||
gstcaps.h \
|
gstcaps.h \
|
||||||
gstclock.h \
|
gstclock.h \
|
||||||
gstcompat.h \
|
gstcompat.h \
|
||||||
|
@ -187,8 +177,8 @@ gst_headers = \
|
||||||
gstthread.h \
|
gstthread.h \
|
||||||
gsttrace.h \
|
gsttrace.h \
|
||||||
gsttrashstack.h \
|
gsttrashstack.h \
|
||||||
gsttype.h \
|
|
||||||
gsttypefind.h \
|
gsttypefind.h \
|
||||||
|
gsttypes.h \
|
||||||
gsturi.h \
|
gsturi.h \
|
||||||
gsturitype.h \
|
gsturitype.h \
|
||||||
gstutils.h \
|
gstutils.h \
|
||||||
|
|
|
@ -410,82 +410,105 @@ gst_spider_identity_src_loop (GstSpiderIdentity *ident)
|
||||||
}
|
}
|
||||||
/* This loop function is only needed when typefinding.
|
/* This loop function is only needed when typefinding.
|
||||||
*/
|
*/
|
||||||
|
typedef struct {
|
||||||
|
GstBuffer *buffer;
|
||||||
|
guint best_probability;
|
||||||
|
GstCaps *caps;
|
||||||
|
} SpiderTypeFind;
|
||||||
|
guint8 *
|
||||||
|
spider_find_peek (gpointer data, gint64 offset, guint size)
|
||||||
|
{
|
||||||
|
SpiderTypeFind *find = (SpiderTypeFind *) data;
|
||||||
|
gint64 buffer_offset = GST_BUFFER_OFFSET_IS_VALID (find->buffer) ?
|
||||||
|
GST_BUFFER_OFFSET (find->buffer) : 0;
|
||||||
|
|
||||||
|
if (offset >= buffer_offset && offset + size <= buffer_offset + GST_BUFFER_SIZE (find->buffer)) {
|
||||||
|
GST_LOG ("peek %"G_GINT64_FORMAT", %u successful", offset, size);
|
||||||
|
return GST_BUFFER_DATA (find->buffer) + offset - buffer_offset;
|
||||||
|
} else {
|
||||||
|
GST_LOG ("peek %"G_GINT64_FORMAT", %u failed", offset, size);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
spider_find_suggest (gpointer data, guint probability, GstCaps *caps)
|
||||||
|
{
|
||||||
|
SpiderTypeFind *find = (SpiderTypeFind *) data;
|
||||||
|
G_GNUC_UNUSED gchar *caps_str;
|
||||||
|
|
||||||
|
caps_str = gst_caps_to_string (caps);
|
||||||
|
GST_INFO ("suggest %u, %s", probability, caps_str);
|
||||||
|
g_free (caps_str);
|
||||||
|
if (probability > find->best_probability) {
|
||||||
|
gst_caps_replace (&find->caps, caps);
|
||||||
|
find->best_probability = probability;
|
||||||
|
}
|
||||||
|
}
|
||||||
static void
|
static void
|
||||||
gst_spider_identity_sink_loop_type_finding (GstSpiderIdentity *ident)
|
gst_spider_identity_sink_loop_type_finding (GstSpiderIdentity *ident)
|
||||||
{
|
{
|
||||||
GstBuffer *buf = NULL;
|
GstData *data;
|
||||||
GList *type_list;
|
GstTypeFind gst_find;
|
||||||
GstCaps *caps;
|
SpiderTypeFind find;
|
||||||
GstByteStream *bs;
|
GList *walk, *type_list = NULL;
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_SPIDER_IDENTITY (ident));
|
g_return_if_fail (GST_IS_SPIDER_IDENTITY (ident));
|
||||||
|
|
||||||
/* get a bytestream object */
|
data = gst_pad_pull (ident->sink);
|
||||||
bs = gst_bytestream_new (ident->sink);
|
while (!GST_IS_BUFFER (data)) {
|
||||||
if (gst_bytestream_peek (bs, &buf, 1) != 1 || !buf) {
|
gst_spider_identity_chain (ident->sink, GST_BUFFER (data));
|
||||||
buf = NULL;
|
data = gst_pad_pull (ident->sink);
|
||||||
g_warning ("Failed to read fake buffer - serious idiocy going on here");
|
|
||||||
goto end;
|
|
||||||
} else {
|
|
||||||
gst_buffer_unref (buf);
|
|
||||||
buf = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
find.buffer = GST_BUFFER (data);
|
||||||
/* maybe there are already valid caps now? */
|
/* maybe there are already valid caps now? */
|
||||||
if ((caps = gst_pad_get_caps (ident->sink)) != NULL) {
|
if ((find.caps = gst_pad_get_caps (ident->sink)) != NULL) {
|
||||||
|
gst_caps_ref (find.caps); /* it's unrefed later below */
|
||||||
goto plug;
|
goto plug;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* now do the actual typefinding with the supplied buffer */
|
/* now do the actual typefinding with the supplied buffer */
|
||||||
type_list = (GList *) gst_type_get_list ();
|
walk = type_list = gst_type_find_factory_get_list ();
|
||||||
|
|
||||||
while (type_list) {
|
find.best_probability = 0;
|
||||||
GstType *type = (GstType *) type_list->data;
|
find.caps = NULL;
|
||||||
GSList *factories = type->factories;
|
gst_find.data = &find;
|
||||||
|
gst_find.peek = spider_find_peek;
|
||||||
|
gst_find.suggest = spider_find_suggest;
|
||||||
|
while (walk) {
|
||||||
|
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (walk->data);
|
||||||
|
|
||||||
while (factories) {
|
GST_DEBUG ("trying typefind function %s", GST_PLUGIN_FEATURE_NAME (factory));
|
||||||
GstTypeFactory *factory = GST_TYPE_FACTORY (factories->data);
|
gst_type_find_factory_call_function (factory, &gst_find);
|
||||||
GstTypeFindFunc typefindfunc = (GstTypeFindFunc)factory->typefindfunc;
|
if (find.best_probability >= GST_TYPE_FIND_MAXIMUM)
|
||||||
|
goto plug;
|
||||||
GST_DEBUG ("trying typefind function %s", GST_PLUGIN_FEATURE_NAME (factory));
|
walk = g_list_next (walk);
|
||||||
if (typefindfunc && (caps = typefindfunc (bs, factory))) {
|
|
||||||
GST_INFO ("typefind function %s found caps", GST_PLUGIN_FEATURE_NAME (factory));
|
|
||||||
if (gst_pad_try_set_caps (ident->src, caps) <= 0) {
|
|
||||||
g_warning ("typefind: found type but peer didn't accept it");
|
|
||||||
gst_caps_sink (caps);
|
|
||||||
} else {
|
|
||||||
goto plug;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
factories = g_slist_next (factories);
|
|
||||||
}
|
|
||||||
type_list = g_list_next (type_list);
|
|
||||||
}
|
}
|
||||||
|
if (find.best_probability > 0)
|
||||||
|
goto plug;
|
||||||
gst_element_error(GST_ELEMENT(ident), "Could not find media type", NULL);
|
gst_element_error(GST_ELEMENT(ident), "Could not find media type", NULL);
|
||||||
buf = GST_BUFFER (gst_event_new (GST_EVENT_EOS));
|
find.buffer = GST_BUFFER (gst_event_new (GST_EVENT_EOS));
|
||||||
|
|
||||||
end:
|
end:
|
||||||
|
|
||||||
/* remove loop function */
|
/* remove loop function */
|
||||||
gst_element_set_loop_function (GST_ELEMENT (ident),
|
gst_element_set_loop_function (GST_ELEMENT (ident),
|
||||||
(GstElementLoopFunction) GST_DEBUG_FUNCPTR (gst_spider_identity_dumb_loop));
|
(GstElementLoopFunction) GST_DEBUG_FUNCPTR (gst_spider_identity_dumb_loop));
|
||||||
|
|
||||||
/* push the buffer */
|
/* push the buffer */
|
||||||
gst_spider_identity_chain (ident->sink, buf);
|
gst_spider_identity_chain (ident->sink, find.buffer);
|
||||||
|
|
||||||
/* bytestream no longer needed */
|
|
||||||
gst_bytestream_destroy (bs);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
plug:
|
plug:
|
||||||
gst_caps_debug (caps, "spider starting caps");
|
GST_INFO ("typefind function found caps");
|
||||||
gst_caps_sink (caps);
|
g_assert (gst_pad_try_set_caps (ident->src, find.caps) > 0);
|
||||||
|
gst_caps_debug (find.caps, "spider starting caps");
|
||||||
|
gst_caps_unref (find.caps);
|
||||||
|
if (type_list)
|
||||||
|
g_list_free (type_list);
|
||||||
|
|
||||||
gst_spider_identity_plug (ident);
|
gst_spider_identity_plug (ident);
|
||||||
|
|
||||||
gst_bytestream_read (bs, &buf, bs->listavail);
|
|
||||||
|
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,40 +1,51 @@
|
||||||
|
# FIXME:
|
||||||
|
# need to get gstbufferstore.[ch] into its own lib, preferrably
|
||||||
|
# libs/gst/buifferstore
|
||||||
|
# This requires building libs/gst before this dir, which we currently don't
|
||||||
|
# do.
|
||||||
|
|
||||||
plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@
|
plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@
|
||||||
|
|
||||||
plugin_LTLIBRARIES = libgstelements.la
|
plugin_LTLIBRARIES = libgstelements.la
|
||||||
|
|
||||||
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 \
|
gstelements.c \
|
||||||
gstfakesrc.c \
|
|
||||||
gstidentity.c \
|
|
||||||
gstfakesink.c \
|
gstfakesink.c \
|
||||||
gstfilesrc.c \
|
gstfakesrc.c \
|
||||||
gstfilesink.c \
|
gstfilesink.c \
|
||||||
gstfdsrc.c \
|
gstfilesrc.c \
|
||||||
gstfdsink.c \
|
gstfdsink.c \
|
||||||
|
gstfdsrc.c \
|
||||||
|
gstidentity.c \
|
||||||
|
gstmd5sink.c \
|
||||||
gstmultidisksrc.c \
|
gstmultidisksrc.c \
|
||||||
gstpipefilter.c \
|
gstpipefilter.c \
|
||||||
gsttee.c \
|
|
||||||
gstaggregator.c \
|
|
||||||
gstshaper.c \
|
gstshaper.c \
|
||||||
gststatistics.c \
|
gststatistics.c \
|
||||||
gstmd5sink.c
|
gsttee.c \
|
||||||
|
gsttypefindelement.c
|
||||||
|
|
||||||
libgstelements_la_CFLAGS = $(GST_CFLAGS)
|
libgstelements_la_CFLAGS = $(GST_CFLAGS)
|
||||||
libgstelements_la_LIBADD =
|
libgstelements_la_LIBADD =
|
||||||
libgstelements_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
libgstelements_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||||
|
|
||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
gstfakesrc.h \
|
|
||||||
gstidentity.h \
|
|
||||||
gstfakesink.h \
|
|
||||||
gstfilesink.h \
|
|
||||||
gstfdsrc.h \
|
|
||||||
gstmultidisksrc.h \
|
|
||||||
gstfdsink.h \
|
|
||||||
gstpipefilter.h \
|
|
||||||
gsttee.h \
|
|
||||||
gstaggregator.h \
|
gstaggregator.h \
|
||||||
gstshaper.h \
|
gstbufferstore.h \
|
||||||
gststatistics.h \
|
gstfakesink.h \
|
||||||
|
gstfakesrc.h \
|
||||||
|
gstfdsink.h \
|
||||||
|
gstfdsrc.h \
|
||||||
|
gstfilesink.h \
|
||||||
gstfilesrc.h \
|
gstfilesrc.h \
|
||||||
gstmd5sink.h
|
gstidentity.h \
|
||||||
|
gstmd5sink.h \
|
||||||
|
gstmultidisksrc.h \
|
||||||
|
gstpipefilter.h \
|
||||||
|
gstshaper.h \
|
||||||
|
gststatistics.h \
|
||||||
|
gsttee.h \
|
||||||
|
gsttypefindelement.h
|
||||||
|
|
465
gst/elements/gstbufferstore.c
Normal file
465
gst/elements/gstbufferstore.c
Normal file
|
@ -0,0 +1,465 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
|
*
|
||||||
|
* gstbufferstore.c: keep an easily accessible list of all buffers
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
#endif
|
||||||
|
#include "gstbufferstore.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY (gst_buffer_store_debug);
|
||||||
|
#define GST_CAT_DEFAULT gst_buffer_store_debug
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CLEARED,
|
||||||
|
BUFFER_ADDED,
|
||||||
|
LAST_SIGNAL
|
||||||
|
};
|
||||||
|
enum {
|
||||||
|
ARG_0
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void gst_buffer_store_class_init (gpointer g_class,
|
||||||
|
gpointer class_data);
|
||||||
|
static void gst_buffer_store_init (GTypeInstance * instance,
|
||||||
|
gpointer g_class);
|
||||||
|
static void gst_buffer_store_dispose (GObject * object);
|
||||||
|
|
||||||
|
static gboolean gst_buffer_store_add_buffer_func (GstBufferStore * store,
|
||||||
|
GstBuffer * buffer);
|
||||||
|
static void gst_buffer_store_cleared_func (GstBufferStore * store);
|
||||||
|
|
||||||
|
static GObjectClass *parent_class = NULL;
|
||||||
|
static guint gst_buffer_store_signals[LAST_SIGNAL] = { 0 };
|
||||||
|
|
||||||
|
G_GNUC_UNUSED static void
|
||||||
|
debug_buffers (GstBufferStore *store)
|
||||||
|
{
|
||||||
|
GList *walk = store->buffers;
|
||||||
|
|
||||||
|
g_printerr ("BUFFERS in store:\n");
|
||||||
|
while (walk) {
|
||||||
|
g_print ("%15"G_GUINT64_FORMAT" - %7u\n", GST_BUFFER_OFFSET (walk->data), GST_BUFFER_SIZE (walk->data));
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
}
|
||||||
|
g_printerr ("\n");
|
||||||
|
}
|
||||||
|
GType
|
||||||
|
gst_buffer_store_get_type (void)
|
||||||
|
{
|
||||||
|
static GType store_type = 0;
|
||||||
|
|
||||||
|
if (!store_type) {
|
||||||
|
static const GTypeInfo store_info = {
|
||||||
|
sizeof (GstBufferStoreClass),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
gst_buffer_store_class_init,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
sizeof (GstBufferStore),
|
||||||
|
0,
|
||||||
|
gst_buffer_store_init,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
store_type = g_type_register_static (G_TYPE_OBJECT,
|
||||||
|
"GstBufferStore",
|
||||||
|
&store_info, 0);
|
||||||
|
|
||||||
|
/* FIXME: better description anyone? */
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_buffer_store_debug, "bufferstore", 0, "store all data");
|
||||||
|
}
|
||||||
|
return store_type;
|
||||||
|
}
|
||||||
|
static gboolean
|
||||||
|
continue_accu (GSignalInvocationHint *ihint, GValue *return_accu,
|
||||||
|
const GValue *handler_return, gpointer data)
|
||||||
|
{
|
||||||
|
gboolean do_continue = g_value_get_boolean (handler_return);
|
||||||
|
g_value_set_boolean (return_accu, do_continue);
|
||||||
|
|
||||||
|
return do_continue;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_buffer_store_class_init (gpointer g_class, gpointer class_data)
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class;
|
||||||
|
GstBufferStoreClass *store_class;
|
||||||
|
|
||||||
|
gobject_class = G_OBJECT_CLASS (g_class);
|
||||||
|
store_class = GST_BUFFER_STORE_CLASS (g_class);
|
||||||
|
|
||||||
|
parent_class = g_type_class_peek_parent (g_class);
|
||||||
|
|
||||||
|
gobject_class->dispose = gst_buffer_store_dispose;
|
||||||
|
|
||||||
|
gst_buffer_store_signals[CLEARED] = g_signal_new ("cleared",
|
||||||
|
G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_LAST,
|
||||||
|
G_STRUCT_OFFSET (GstBufferStoreClass, cleared), NULL, NULL,
|
||||||
|
gst_marshal_VOID__VOID, G_TYPE_NONE, 0);
|
||||||
|
gst_buffer_store_signals[BUFFER_ADDED] = g_signal_new ("buffer-added",
|
||||||
|
G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_LAST,
|
||||||
|
G_STRUCT_OFFSET (GstBufferStoreClass, buffer_added), continue_accu, NULL,
|
||||||
|
gst_marshal_BOOLEAN__POINTER, G_TYPE_BOOLEAN, 1, G_TYPE_POINTER);
|
||||||
|
|
||||||
|
store_class->cleared = gst_buffer_store_cleared_func;
|
||||||
|
store_class->buffer_added = gst_buffer_store_add_buffer_func;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_buffer_store_init (GTypeInstance *instance, gpointer g_class)
|
||||||
|
{
|
||||||
|
GstBufferStore *store = GST_BUFFER_STORE (instance);
|
||||||
|
|
||||||
|
store->buffers = NULL;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_buffer_store_dispose (GObject *object)
|
||||||
|
{
|
||||||
|
GstBufferStore *store = GST_BUFFER_STORE (object);
|
||||||
|
|
||||||
|
gst_buffer_store_clear (store);
|
||||||
|
|
||||||
|
parent_class->dispose (object);
|
||||||
|
}
|
||||||
|
static gboolean
|
||||||
|
gst_buffer_store_add_buffer_func (GstBufferStore *store, GstBuffer *buffer)
|
||||||
|
{
|
||||||
|
g_assert (buffer != NULL);
|
||||||
|
|
||||||
|
if (!GST_BUFFER_OFFSET_IS_VALID (buffer) &&
|
||||||
|
store->buffers &&
|
||||||
|
GST_BUFFER_OFFSET_IS_VALID (store->buffers->data)) {
|
||||||
|
/* we assumed valid offsets, but suddenly they are not anymore */
|
||||||
|
GST_DEBUG_OBJECT (store, "attempting to add buffer %p with invalid offset to store with valid offset, abort",
|
||||||
|
buffer);
|
||||||
|
return FALSE;
|
||||||
|
} else if (!store->buffers || !GST_BUFFER_OFFSET_IS_VALID (store->buffers->data)) {
|
||||||
|
/* the starting buffer had an invalid offset, in that case we assume continuous buffers */
|
||||||
|
GST_LOG_OBJECT (store, "adding buffer %p with invalid offset and size %u",
|
||||||
|
buffer, GST_BUFFER_SIZE (buffer));
|
||||||
|
gst_data_ref (GST_DATA (buffer));
|
||||||
|
store->buffers = g_list_append (store->buffers, buffer);
|
||||||
|
return TRUE;
|
||||||
|
} else {
|
||||||
|
/* both list and buffer have valid offsets, we can really go wild */
|
||||||
|
GList *walk, *current_list = NULL;
|
||||||
|
GstBuffer *current;
|
||||||
|
|
||||||
|
g_assert (GST_BUFFER_OFFSET_IS_VALID (buffer));
|
||||||
|
GST_LOG_OBJECT (store, "attempting to add buffer %p with offset %"G_GUINT64_FORMAT" and size %u",
|
||||||
|
buffer, GST_BUFFER_OFFSET (buffer), GST_BUFFER_SIZE (buffer));
|
||||||
|
/* we keep a sorted list of non-overlapping buffers */
|
||||||
|
walk = store->buffers;
|
||||||
|
while (walk) {
|
||||||
|
current = GST_BUFFER (walk->data);
|
||||||
|
current_list = walk;
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
if (GST_BUFFER_OFFSET (current) < GST_BUFFER_OFFSET (buffer)) {
|
||||||
|
continue;
|
||||||
|
} else if (GST_BUFFER_OFFSET (current) == GST_BUFFER_OFFSET (buffer)) {
|
||||||
|
guint needed_size;
|
||||||
|
if (walk) {
|
||||||
|
needed_size = MIN (GST_BUFFER_SIZE (buffer),
|
||||||
|
GST_BUFFER_OFFSET (walk->data) - GST_BUFFER_OFFSET (current));
|
||||||
|
} else {
|
||||||
|
needed_size = GST_BUFFER_SIZE (buffer);
|
||||||
|
}
|
||||||
|
if (needed_size <= GST_BUFFER_SIZE (current)) {
|
||||||
|
buffer = NULL;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (needed_size < GST_BUFFER_SIZE (buffer)) {
|
||||||
|
/* need to create subbuffer to not have overlapping data */
|
||||||
|
GstBuffer *sub = gst_buffer_create_sub (buffer, 0, needed_size);
|
||||||
|
g_assert (sub);
|
||||||
|
buffer = sub;
|
||||||
|
} else {
|
||||||
|
gst_data_ref (GST_DATA (buffer));
|
||||||
|
}
|
||||||
|
/* replace current buffer with new one */
|
||||||
|
GST_INFO_OBJECT (store, "replacing buffer %p with buffer %p with offset %"G_GINT64_FORMAT" and size %u",
|
||||||
|
current_list->data, buffer, GST_BUFFER_OFFSET (buffer), GST_BUFFER_SIZE (buffer));
|
||||||
|
gst_data_unref (GST_DATA (current_list->data));
|
||||||
|
current_list->data = buffer;
|
||||||
|
buffer = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (GST_BUFFER_OFFSET (current) > GST_BUFFER_OFFSET (buffer)) {
|
||||||
|
GList *previous = g_list_previous (current_list);
|
||||||
|
guint64 start_offset = previous ?
|
||||||
|
GST_BUFFER_OFFSET (previous->data) + GST_BUFFER_SIZE (previous->data) : 0;
|
||||||
|
|
||||||
|
if (start_offset == GST_BUFFER_OFFSET (current)) {
|
||||||
|
buffer = NULL;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
/* we have data to insert */
|
||||||
|
if (start_offset > GST_BUFFER_OFFSET (buffer) ||
|
||||||
|
GST_BUFFER_OFFSET (buffer) + GST_BUFFER_SIZE (buffer) > GST_BUFFER_OFFSET (current)) {
|
||||||
|
/* need a subbuffer */
|
||||||
|
start_offset = GST_BUFFER_OFFSET (buffer) > start_offset ? 0 :
|
||||||
|
start_offset - GST_BUFFER_OFFSET (buffer);
|
||||||
|
GstBuffer* sub = gst_buffer_create_sub (buffer, start_offset,
|
||||||
|
MIN (GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (current) - start_offset - GST_BUFFER_OFFSET (buffer)));
|
||||||
|
g_assert (sub);
|
||||||
|
GST_BUFFER_OFFSET (sub) = start_offset + GST_BUFFER_OFFSET (buffer);
|
||||||
|
buffer = sub;
|
||||||
|
} else {
|
||||||
|
gst_data_ref (GST_DATA (buffer));
|
||||||
|
}
|
||||||
|
GST_INFO_OBJECT (store, "adding buffer %p with offset %"G_GINT64_FORMAT" and size %u",
|
||||||
|
buffer, GST_BUFFER_OFFSET (buffer), GST_BUFFER_SIZE (buffer));
|
||||||
|
store->buffers = g_list_insert_before (store->buffers, current_list, buffer);
|
||||||
|
buffer = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (buffer) {
|
||||||
|
gst_data_ref (GST_DATA (buffer));
|
||||||
|
GST_INFO_OBJECT (store, "adding buffer %p with offset %"G_GINT64_FORMAT" and size %u",
|
||||||
|
buffer, GST_BUFFER_OFFSET (buffer), GST_BUFFER_SIZE (buffer));
|
||||||
|
if (current_list) {
|
||||||
|
g_list_append (current_list, buffer);
|
||||||
|
} else {
|
||||||
|
g_assert (store->buffers == NULL);
|
||||||
|
store->buffers = g_list_prepend (NULL, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_buffer_store_cleared_func (GstBufferStore *store)
|
||||||
|
{
|
||||||
|
g_list_foreach (store->buffers, (GFunc) gst_data_unref, NULL);
|
||||||
|
g_list_free (store->buffers);
|
||||||
|
store->buffers = NULL;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* gst_buffer_store_new:
|
||||||
|
*
|
||||||
|
* Creates a new bufferstore.
|
||||||
|
*
|
||||||
|
* Returns: the new bufferstore.
|
||||||
|
*/
|
||||||
|
GstBufferStore *
|
||||||
|
gst_buffer_store_new (void)
|
||||||
|
{
|
||||||
|
return GST_BUFFER_STORE (g_object_new (GST_TYPE_BUFFER_STORE, NULL));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* gst_buffer_store_clear:
|
||||||
|
* @store: a bufferstore
|
||||||
|
*
|
||||||
|
* Clears the buffer store. All buffers are removed and the buffer store
|
||||||
|
* behaves like it was just created.
|
||||||
|
*/
|
||||||
|
/* FIXME: call this function _reset ? */
|
||||||
|
void
|
||||||
|
gst_buffer_store_clear (GstBufferStore *store)
|
||||||
|
{
|
||||||
|
g_return_if_fail (GST_IS_BUFFER_STORE (store));
|
||||||
|
|
||||||
|
g_signal_emit (store, gst_buffer_store_signals [CLEARED], 0, NULL);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* gst_buffer_store_add_buffer:
|
||||||
|
* @store: a bufferstore
|
||||||
|
* @buffer: the buffer to add
|
||||||
|
*
|
||||||
|
* Adds a buffer to the buffer store.
|
||||||
|
*
|
||||||
|
* Returns: TRUE, if the buffer was added, FALSE if an error occured.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
gst_buffer_store_add_buffer (GstBufferStore *store, GstBuffer *buffer)
|
||||||
|
{
|
||||||
|
gboolean ret;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_BUFFER_STORE (store), FALSE);
|
||||||
|
g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
|
||||||
|
|
||||||
|
if (store->buffers &&
|
||||||
|
GST_BUFFER_OFFSET_IS_VALID (store->buffers->data) &&
|
||||||
|
!GST_BUFFER_OFFSET_IS_VALID (buffer))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
g_signal_emit (store, gst_buffer_store_signals [BUFFER_ADDED], 0, buffer, &ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* gst_buffer_store_get_buffer:
|
||||||
|
* @store: a bufferstore
|
||||||
|
* @offset: starting offset of returned buffer
|
||||||
|
* @size: size of returned buffer
|
||||||
|
*
|
||||||
|
* Returns a buffer that corresponds to the given area of data. If part of the
|
||||||
|
* data is not available inside the store, NULL is returned. You have to unref
|
||||||
|
* the buffer after use.
|
||||||
|
*
|
||||||
|
* Returns: a buffer with the requested data or NULL if the data was not
|
||||||
|
* available.
|
||||||
|
*/
|
||||||
|
GstBuffer *
|
||||||
|
gst_buffer_store_get_buffer (GstBufferStore *store, guint64 offset, guint size)
|
||||||
|
{
|
||||||
|
GstBuffer *current;
|
||||||
|
GList *walk;
|
||||||
|
guint8 *data;
|
||||||
|
guint tmp;
|
||||||
|
guint64 cur_offset;
|
||||||
|
gboolean have_offset;
|
||||||
|
GstBuffer *ret = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_BUFFER_STORE (store), NULL);
|
||||||
|
|
||||||
|
walk = store->buffers;
|
||||||
|
if (!walk)
|
||||||
|
return NULL;
|
||||||
|
if (GST_BUFFER_OFFSET_IS_VALID (walk->data)) {
|
||||||
|
have_offset = TRUE;
|
||||||
|
} else {
|
||||||
|
have_offset = FALSE;
|
||||||
|
cur_offset = 0;
|
||||||
|
}
|
||||||
|
while (walk) {
|
||||||
|
current = GST_BUFFER (walk->data);
|
||||||
|
if (have_offset) {
|
||||||
|
cur_offset = GST_BUFFER_OFFSET (current);
|
||||||
|
}
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
if (cur_offset > offset) {
|
||||||
|
/* #include <windows.h>
|
||||||
|
do_nothing_loop (); */
|
||||||
|
} else if (cur_offset == offset &&
|
||||||
|
GST_BUFFER_SIZE (current) == size) {
|
||||||
|
GST_LOG_OBJECT (store, "found matching buffer %p for offset %"G_GUINT64_FORMAT" and size %u",
|
||||||
|
current, offset, size);
|
||||||
|
ret = current;
|
||||||
|
gst_data_ref (GST_DATA (ret));
|
||||||
|
GST_LOG_OBJECT (store, "refcount %d",
|
||||||
|
GST_DATA_REFCOUNT_VALUE(ret));
|
||||||
|
break;
|
||||||
|
} else if (cur_offset + GST_BUFFER_SIZE (current) > offset) {
|
||||||
|
if (cur_offset + GST_BUFFER_SIZE (current) >= offset + size) {
|
||||||
|
ret = gst_buffer_create_sub (current, offset - cur_offset, size);
|
||||||
|
GST_LOG_OBJECT (store, "created subbuffer %p from buffer %p for offset %llu and size %u",
|
||||||
|
ret, current, offset, size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* uh, the requested data spans some buffers */
|
||||||
|
ret = gst_buffer_new_and_alloc (size);
|
||||||
|
GST_LOG_OBJECT (store, "created buffer %p for offset %"G_GUINT64_FORMAT
|
||||||
|
" and size %u, will fill with data now",
|
||||||
|
ret, offset, size);
|
||||||
|
data = GST_BUFFER_DATA (ret);
|
||||||
|
tmp = GST_BUFFER_SIZE (current) - offset + cur_offset;
|
||||||
|
memcpy (data, GST_BUFFER_DATA (current) + offset - cur_offset, tmp);
|
||||||
|
data += tmp;
|
||||||
|
size -= tmp;
|
||||||
|
while (size) {
|
||||||
|
if (walk == NULL ||
|
||||||
|
(have_offset &&
|
||||||
|
GST_BUFFER_OFFSET (current) + GST_BUFFER_SIZE (current) != GST_BUFFER_OFFSET (walk->data))) {
|
||||||
|
GST_DEBUG_OBJECT (store, "not all data for offset %"G_GUINT64_FORMAT" and remaining size %u available, aborting",
|
||||||
|
offset, size);
|
||||||
|
gst_data_unref (GST_DATA (ret));
|
||||||
|
ret = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
current = GST_BUFFER (walk->data);
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
tmp = MIN (GST_BUFFER_SIZE (current), size);
|
||||||
|
memcpy (data, GST_BUFFER_DATA (current), tmp);
|
||||||
|
size -= tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!have_offset) {
|
||||||
|
cur_offset += GST_BUFFER_SIZE (current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* gst_buffer_store_get_size:
|
||||||
|
* @store: a bufferstore
|
||||||
|
* @offset: desired offset
|
||||||
|
*
|
||||||
|
* Calculates the number of bytes available starting from offset. This allows
|
||||||
|
* to query a buffer with the returned size.
|
||||||
|
*
|
||||||
|
* Returns: the number of continuous bytes in the bufferstore starting at
|
||||||
|
* offset.
|
||||||
|
*/
|
||||||
|
guint
|
||||||
|
gst_buffer_store_get_size (GstBufferStore *store, guint64 offset)
|
||||||
|
{
|
||||||
|
GList *walk;
|
||||||
|
guint64 cur_offset;
|
||||||
|
gboolean have_offset;
|
||||||
|
gboolean counting = FALSE;
|
||||||
|
GstBuffer *current;
|
||||||
|
guint ret = 0;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_BUFFER_STORE (store), 0);
|
||||||
|
|
||||||
|
walk = store->buffers;
|
||||||
|
if (!walk)
|
||||||
|
return 0;
|
||||||
|
if (GST_BUFFER_OFFSET_IS_VALID (walk->data)) {
|
||||||
|
have_offset = TRUE;
|
||||||
|
} else {
|
||||||
|
have_offset = FALSE;
|
||||||
|
cur_offset = 0;
|
||||||
|
}
|
||||||
|
while (walk) {
|
||||||
|
if (have_offset && counting &&
|
||||||
|
cur_offset + GST_BUFFER_SIZE (current) != GST_BUFFER_OFFSET (walk->data)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
current = GST_BUFFER (walk->data);
|
||||||
|
if (have_offset) {
|
||||||
|
cur_offset = GST_BUFFER_OFFSET (current);
|
||||||
|
}
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
if (counting) {
|
||||||
|
ret += GST_BUFFER_SIZE (current);
|
||||||
|
} else {
|
||||||
|
if (cur_offset > offset)
|
||||||
|
return 0;
|
||||||
|
if (cur_offset + GST_BUFFER_SIZE (current) > offset) {
|
||||||
|
/* we have at least some bytes */
|
||||||
|
ret = cur_offset + GST_BUFFER_SIZE (current) - offset;
|
||||||
|
counting = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!have_offset) {
|
||||||
|
cur_offset += GST_BUFFER_SIZE (current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
73
gst/elements/gstbufferstore.h
Normal file
73
gst/elements/gstbufferstore.h
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
|
*
|
||||||
|
* gsttypefind.h: keep an easily accessible list of all buffers
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __GST_BUFFER_STORE_H__
|
||||||
|
#define __GST_BUFFER_STORE_H__
|
||||||
|
|
||||||
|
#include <gst/gstbuffer.h>
|
||||||
|
#include <gst/gstinfo.h>
|
||||||
|
#include <gst/gstmarshal.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define GST_TYPE_BUFFER_STORE (gst_buffer_store_get_type ())
|
||||||
|
#define GST_BUFFER_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_BUFFER_STORE, GstBufferStore))
|
||||||
|
#define GST_IS_BUFFER_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_BUFFER_STORE))
|
||||||
|
#define GST_BUFFER_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_BUFFER_STORE, GstBufferStoreClass))
|
||||||
|
#define GST_IS_BUFFER_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_BUFFER_STORE))
|
||||||
|
#define GST_BUFFER_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_BUFFER_STORE, GstBufferStoreClass))
|
||||||
|
|
||||||
|
typedef struct _GstBufferStore GstBufferStore;
|
||||||
|
typedef struct _GstBufferStoreClass GstBufferStoreClass;
|
||||||
|
|
||||||
|
struct _GstBufferStore {
|
||||||
|
GObject object;
|
||||||
|
|
||||||
|
GList * buffers;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GstBufferStoreClass {
|
||||||
|
GObjectClass parent_class;
|
||||||
|
|
||||||
|
/* signals */
|
||||||
|
void (* cleared) (GstBufferStore * store);
|
||||||
|
gboolean (* buffer_added) (GstBufferStore * store,
|
||||||
|
GstBuffer * buffer);
|
||||||
|
};
|
||||||
|
|
||||||
|
GType gst_buffer_store_get_type (void);
|
||||||
|
|
||||||
|
GstBufferStore * gst_buffer_store_new (void);
|
||||||
|
void gst_buffer_store_clear (GstBufferStore * store);
|
||||||
|
|
||||||
|
gboolean gst_buffer_store_add_buffer (GstBufferStore * store,
|
||||||
|
GstBuffer * buffer);
|
||||||
|
|
||||||
|
GstBuffer * gst_buffer_store_get_buffer (GstBufferStore * store,
|
||||||
|
guint64 offset,
|
||||||
|
guint size);
|
||||||
|
guint gst_buffer_store_get_size (GstBufferStore * store,
|
||||||
|
guint64 offset);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __GST_BUFFER_STORE_H__ */
|
|
@ -27,20 +27,21 @@
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
|
||||||
#include "gstfilesrc.h"
|
#include "gstaggregator.h"
|
||||||
#include "gstfilesink.h"
|
|
||||||
#include "gstidentity.h"
|
|
||||||
#include "gstfakesink.h"
|
#include "gstfakesink.h"
|
||||||
#include "gstfakesrc.h"
|
#include "gstfakesrc.h"
|
||||||
#include "gstfdsink.h"
|
#include "gstfdsink.h"
|
||||||
#include "gstfdsrc.h"
|
#include "gstfdsrc.h"
|
||||||
|
#include "gstfilesink.h"
|
||||||
|
#include "gstfilesrc.h"
|
||||||
|
#include "gstidentity.h"
|
||||||
|
#include "gstmd5sink.h"
|
||||||
#include "gstmultidisksrc.h"
|
#include "gstmultidisksrc.h"
|
||||||
#include "gstpipefilter.h"
|
#include "gstpipefilter.h"
|
||||||
#include "gsttee.h"
|
|
||||||
#include "gstaggregator.h"
|
|
||||||
#include "gstshaper.h"
|
#include "gstshaper.h"
|
||||||
#include "gststatistics.h"
|
#include "gststatistics.h"
|
||||||
#include "gstmd5sink.h"
|
#include "gsttee.h"
|
||||||
|
#include "gsttypefindelement.h"
|
||||||
|
|
||||||
|
|
||||||
struct _elements_entry {
|
struct _elements_entry {
|
||||||
|
@ -55,20 +56,21 @@ 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_aggregator_get_type, &gst_aggregator_details, gst_aggregator_factory_init },
|
||||||
{ "fakesrc", gst_fakesrc_get_type, &gst_fakesrc_details, gst_fakesrc_factory_init },
|
{ "fakesrc", gst_fakesrc_get_type, &gst_fakesrc_details, gst_fakesrc_factory_init },
|
||||||
{ "fakesink", gst_fakesink_get_type, &gst_fakesink_details, gst_fakesink_factory_init },
|
{ "fakesink", gst_fakesink_get_type, &gst_fakesink_details, gst_fakesink_factory_init },
|
||||||
|
{ "fdsink", gst_fdsink_get_type, &gst_fdsink_details, NULL },
|
||||||
|
{ "fdsrc", gst_fdsrc_get_type, &gst_fdsrc_details, NULL },
|
||||||
{ "filesrc", gst_filesrc_get_type, &gst_filesrc_details, NULL },
|
{ "filesrc", gst_filesrc_get_type, &gst_filesrc_details, NULL },
|
||||||
{ "filesink", gst_filesink_get_type, &gst_filesink_details, NULL },
|
{ "filesink", gst_filesink_get_type, &gst_filesink_details, NULL },
|
||||||
{ "identity", gst_identity_get_type, &gst_identity_details, NULL },
|
{ "identity", gst_identity_get_type, &gst_identity_details, NULL },
|
||||||
{ "fdsink", gst_fdsink_get_type, &gst_fdsink_details, NULL },
|
{ "md5sink", gst_md5sink_get_type, &gst_md5sink_details, gst_md5sink_factory_init },
|
||||||
{ "fdsrc", gst_fdsrc_get_type, &gst_fdsrc_details, NULL },
|
|
||||||
{ "multidisksrc", gst_multidisksrc_get_type, &gst_multidisksrc_details, NULL },
|
{ "multidisksrc", gst_multidisksrc_get_type, &gst_multidisksrc_details, NULL },
|
||||||
{ "pipefilter", gst_pipefilter_get_type, &gst_pipefilter_details, NULL },
|
{ "pipefilter", gst_pipefilter_get_type, &gst_pipefilter_details, NULL },
|
||||||
{ "tee", gst_tee_get_type, &gst_tee_details, gst_tee_factory_init },
|
|
||||||
{ "aggregator", gst_aggregator_get_type, &gst_aggregator_details, gst_aggregator_factory_init },
|
|
||||||
{ "shaper", gst_shaper_get_type, &gst_shaper_details, gst_shaper_factory_init },
|
{ "shaper", gst_shaper_get_type, &gst_shaper_details, gst_shaper_factory_init },
|
||||||
{ "statistics", gst_statistics_get_type, &gst_statistics_details, NULL },
|
{ "statistics", gst_statistics_get_type, &gst_statistics_details, NULL },
|
||||||
{ "md5sink", gst_md5sink_get_type, &gst_md5sink_details, gst_md5sink_factory_init },
|
{ "tee", gst_tee_get_type, &gst_tee_details, gst_tee_factory_init },
|
||||||
|
{ "typefind", gst_type_find_element_get_type, &gst_type_find_element_details, NULL },
|
||||||
{ NULL, 0 },
|
{ NULL, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -80,20 +82,21 @@ plugin_init (GModule *module, GstPlugin *plugin)
|
||||||
|
|
||||||
gst_plugin_set_longname (plugin, "Standard GST Elements");
|
gst_plugin_set_longname (plugin, "Standard GST Elements");
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_fakesrc_debug, "fakesrc", 0, "fakesrc element");
|
GST_DEBUG_CATEGORY_INIT (gst_aggregator_debug, "aggregator", 0, "aggregator element");
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_fakesink_debug, "fakesink", 0, "fakesink element");
|
GST_DEBUG_CATEGORY_INIT (gst_fakesink_debug, "fakesink", 0, "fakesink element");
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_filesrc_debug, "filesrc", 0, "filesrc element");
|
GST_DEBUG_CATEGORY_INIT (gst_fakesrc_debug, "fakesrc", 0, "fakesrc element");
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_filesink_debug, "fakesink", 0, "filesink element");
|
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_identity_debug, "identity", 0, "identity element");
|
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_fdsrc_debug, "fdsrc", 0, "fdsrc element");
|
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_fdsink_debug, "fdsink", 0, "fdsink element");
|
GST_DEBUG_CATEGORY_INIT (gst_fdsink_debug, "fdsink", 0, "fdsink element");
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_fdsrc_debug, "fdsrc", 0, "fdsrc element");
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_filesink_debug, "filesink", 0, "filesink element");
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_filesrc_debug, "filesrc", 0, "filesrc element");
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_identity_debug, "identity", 0, "identity element");
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_md5sink_debug, "md5sink", 0, "md5sink element");
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_multidisksrc_debug, "multidisksrc", 0, "multidisksrc element");
|
GST_DEBUG_CATEGORY_INIT (gst_multidisksrc_debug, "multidisksrc", 0, "multidisksrc element");
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_pipefilter_debug, "pipefilter", 0, "pipefilter element");
|
GST_DEBUG_CATEGORY_INIT (gst_pipefilter_debug, "pipefilter", 0, "pipefilter element");
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_tee_debug, "tee", 0, "tee element");
|
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_aggregator_debug, "aggregator", 0, "aggregator element");
|
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_shaper_debug, "shaper", 0, "shaper element");
|
GST_DEBUG_CATEGORY_INIT (gst_shaper_debug, "shaper", 0, "shaper element");
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_statistics_debug, "statistics", 0, "statistics element");
|
GST_DEBUG_CATEGORY_INIT (gst_statistics_debug, "statistics", 0, "statistics element");
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_md5sink_debug, "md5sink", 0, "md5sink element");
|
GST_DEBUG_CATEGORY_INIT (gst_tee_debug, "tee", 0, "tee element");
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_type_find_element_debug, "typefind", GST_DEBUG_BG_YELLOW | GST_DEBUG_FG_GREEN, "typefind element");
|
||||||
|
|
||||||
while (_elements[i].name) {
|
while (_elements[i].name) {
|
||||||
factory = gst_element_factory_new (_elements[i].name,
|
factory = gst_element_factory_new (_elements[i].name,
|
||||||
|
@ -112,12 +115,10 @@ plugin_init (GModule *module, GstPlugin *plugin)
|
||||||
_elements[i].factoryinit (factory);
|
_elements[i].factoryinit (factory);
|
||||||
}
|
}
|
||||||
/* g_print("added factory '%s'\n",_elements[i].name); */
|
/* g_print("added factory '%s'\n",_elements[i].name); */
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* INFO (GST_INFO_PLUGIN_LOAD,"gstelements: loaded %d standard elements", i);*/
|
/* INFO (GST_INFO_PLUGIN_LOAD,"gstelements: loaded %d standard elements", i);*/
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -487,7 +487,7 @@ gst_fakesrc_set_property (GObject *object, guint prop_id, const GValue *value, G
|
||||||
src->pool = gst_buffer_pool_get_default (src->sizemax, 10);
|
src->pool = gst_buffer_pool_get_default (src->sizemax, 10);
|
||||||
} else {
|
} else {
|
||||||
if (src->pool) {
|
if (src->pool) {
|
||||||
gst_buffer_pool_free (src->pool);
|
gst_buffer_pool_unref (src->pool);
|
||||||
src->pool = NULL;
|
src->pool = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,18 +88,6 @@ GstElementDetails gst_filesrc_details = {
|
||||||
#define DEFAULT_BLOCKSIZE 4*1024
|
#define DEFAULT_BLOCKSIZE 4*1024
|
||||||
#define DEFAULT_MMAPSIZE 4*1024*1024
|
#define DEFAULT_MMAPSIZE 4*1024*1024
|
||||||
|
|
||||||
#ifdef G_HAVE_ISO_VARARGS
|
|
||||||
|
|
||||||
/* #define fs_print(...) g_print(__VA_ARGS__) */
|
|
||||||
#define fs_print(...)
|
|
||||||
|
|
||||||
#elif defined(G_HAVE_GNUC_VARARGS)
|
|
||||||
|
|
||||||
/* #define fs_print(format,args...) g_print(format, ## args) */
|
|
||||||
#define fs_print(format,args...)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* FileSrc signals and args */
|
/* FileSrc signals and args */
|
||||||
enum {
|
enum {
|
||||||
/* FILL ME */
|
/* FILL ME */
|
||||||
|
@ -305,7 +293,7 @@ gst_filesrc_set_property (GObject *object, guint prop_id, const GValue *value, G
|
||||||
src->mapsize = g_value_get_ulong (value);
|
src->mapsize = g_value_get_ulong (value);
|
||||||
g_object_notify (G_OBJECT (src), "mmapsize");
|
g_object_notify (G_OBJECT (src), "mmapsize");
|
||||||
} else {
|
} else {
|
||||||
GST_INFO ( "invalid mapsize, must a multiple of pagesize, which is %d",
|
GST_INFO_OBJECT (src, "invalid mapsize, must a multiple of pagesize, which is %d",
|
||||||
src->pagesize);
|
src->pagesize);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -355,8 +343,8 @@ gst_filesrc_free_parent_mmap (GstBuffer *buf)
|
||||||
{
|
{
|
||||||
GstFileSrc *src = GST_FILESRC (GST_BUFFER_POOL_PRIVATE (buf));
|
GstFileSrc *src = GST_FILESRC (GST_BUFFER_POOL_PRIVATE (buf));
|
||||||
|
|
||||||
fs_print ("freeing mmap()d buffer at %d+%d\n",
|
GST_LOG_OBJECT (src, "freeing mmap()d buffer at %"G_GUINT64_FORMAT"+%u",
|
||||||
GST_BUFFER_OFFSET (buf), GST_BUFFER_SIZE (buf));
|
GST_BUFFER_OFFSET (buf), GST_BUFFER_SIZE (buf));
|
||||||
|
|
||||||
/* remove the buffer from the list of available mmap'd regions */
|
/* remove the buffer from the list of available mmap'd regions */
|
||||||
g_mutex_lock (src->map_regions_lock);
|
g_mutex_lock (src->map_regions_lock);
|
||||||
|
@ -375,13 +363,14 @@ gst_filesrc_free_parent_mmap (GstBuffer *buf)
|
||||||
munmap (GST_BUFFER_DATA (buf), GST_BUFFER_MAXSIZE (buf));
|
munmap (GST_BUFFER_DATA (buf), GST_BUFFER_MAXSIZE (buf));
|
||||||
/* cast to unsigned long, since there's no gportable way to print
|
/* cast to unsigned long, since there's no gportable way to print
|
||||||
* guint64 as hex */
|
* guint64 as hex */
|
||||||
GST_DEBUG ( "unmapped region %08lx+%08lx at %p",
|
GST_LOG_OBJECT (src, "unmapped region %08lx+%08lx at %p",
|
||||||
(unsigned long) GST_BUFFER_OFFSET (buf),
|
(unsigned long) GST_BUFFER_OFFSET (buf),
|
||||||
(unsigned long) GST_BUFFER_MAXSIZE (buf),
|
(unsigned long) GST_BUFFER_MAXSIZE (buf),
|
||||||
GST_BUFFER_DATA (buf));
|
GST_BUFFER_DATA (buf));
|
||||||
|
|
||||||
GST_BUFFER_DATA (buf) = NULL;
|
GST_BUFFER_DATA (buf) = NULL;
|
||||||
|
|
||||||
|
g_object_unref (src);
|
||||||
gst_buffer_default_free (buf);
|
gst_buffer_default_free (buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,7 +383,7 @@ gst_filesrc_map_region (GstFileSrc *src, off_t offset, size_t size)
|
||||||
|
|
||||||
g_return_val_if_fail (offset >= 0, NULL);
|
g_return_val_if_fail (offset >= 0, NULL);
|
||||||
|
|
||||||
fs_print ("mapping region %08llx+%08lx from file into memory\n",offset,(unsigned long)size);
|
GST_LOG_OBJECT (src, "mapping region %08llx+%08lx from file into memory",offset,(unsigned long)size);
|
||||||
mmapregion = mmap (NULL, size, PROT_READ, MAP_SHARED, src->fd, offset);
|
mmapregion = mmap (NULL, size, PROT_READ, MAP_SHARED, src->fd, offset);
|
||||||
|
|
||||||
if (mmapregion == NULL) {
|
if (mmapregion == NULL) {
|
||||||
|
@ -402,11 +391,11 @@ gst_filesrc_map_region (GstFileSrc *src, off_t offset, size_t size)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else if (mmapregion == MAP_FAILED) {
|
else if (mmapregion == MAP_FAILED) {
|
||||||
GST_DEBUG ("mmap (0x%08lx, %d, 0x%llx) : %s",
|
GST_WARNING_OBJECT (src, "mmap (0x%08lx, %d, 0x%llx) failed: %s",
|
||||||
(unsigned long)size, src->fd, offset, strerror (errno));
|
(unsigned long)size, src->fd, offset, strerror (errno));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
GST_DEBUG ( "mapped region %08lx+%08lx from file into memory at %p",
|
GST_LOG_OBJECT (src, "mapped region %08lx+%08lx from file into memory at %p",
|
||||||
(unsigned long)offset, (unsigned long)size, mmapregion);
|
(unsigned long)offset, (unsigned long)size, mmapregion);
|
||||||
|
|
||||||
/* time to allocate a new mapbuf */
|
/* time to allocate a new mapbuf */
|
||||||
|
@ -426,6 +415,7 @@ gst_filesrc_map_region (GstFileSrc *src, off_t offset, size_t size)
|
||||||
GST_BUFFER_OFFSET (buf) = offset;
|
GST_BUFFER_OFFSET (buf) = offset;
|
||||||
GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE;
|
GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE;
|
||||||
GST_BUFFER_POOL_PRIVATE (buf) = src;
|
GST_BUFFER_POOL_PRIVATE (buf) = src;
|
||||||
|
g_object_ref (src);
|
||||||
GST_BUFFER_FREE_FUNC (buf) = (GstDataFreeFunction) gst_filesrc_free_parent_mmap;
|
GST_BUFFER_FREE_FUNC (buf) = (GstDataFreeFunction) gst_filesrc_free_parent_mmap;
|
||||||
|
|
||||||
g_mutex_lock (src->map_regions_lock);
|
g_mutex_lock (src->map_regions_lock);
|
||||||
|
@ -522,7 +512,7 @@ gst_filesrc_get_mmap (GstFileSrc *src)
|
||||||
/* if the end is before the mapend, the buffer is in current mmap region... */
|
/* if the end is before the mapend, the buffer is in current mmap region... */
|
||||||
/* ('cause by definition if readend is in the buffer, so's readstart) */
|
/* ('cause by definition if readend is in the buffer, so's readstart) */
|
||||||
if (readend <= mapend) {
|
if (readend <= mapend) {
|
||||||
fs_print ("read buf %llu+%d lives in current mapbuf %lld+%d, creating subbuffer of mapbuf\n",
|
GST_LOG_OBJECT (src, "read buf %llu+%d lives in current mapbuf %lld+%d, creating subbuffer of mapbuf",
|
||||||
src->curoffset, readsize, mapstart, mapsize);
|
src->curoffset, readsize, mapstart, mapsize);
|
||||||
buf = gst_buffer_create_sub (src->mapbuf, src->curoffset - mapstart,
|
buf = gst_buffer_create_sub (src->mapbuf, src->curoffset - mapstart,
|
||||||
readsize);
|
readsize);
|
||||||
|
@ -530,8 +520,8 @@ gst_filesrc_get_mmap (GstFileSrc *src)
|
||||||
|
|
||||||
/* if the start actually is within the current mmap region, map an overlap buffer */
|
/* if the start actually is within the current mmap region, map an overlap buffer */
|
||||||
} else if (src->curoffset < mapend) {
|
} else if (src->curoffset < mapend) {
|
||||||
fs_print ("read buf %llu+%d starts in mapbuf %d+%d but ends outside, creating new mmap\n",
|
GST_LOG_OBJECT (src, "read buf %llu+%d starts in mapbuf %d+%d but ends outside, creating new mmap",
|
||||||
src->curoffset, readsize, mapstart, mapsize);
|
(unsigned long long) src->curoffset, (gint) readsize, (gint) mapstart, (gint) mapsize);
|
||||||
buf = gst_filesrc_map_small_region (src, src->curoffset, readsize);
|
buf = gst_filesrc_map_small_region (src, src->curoffset, readsize);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -545,8 +535,8 @@ gst_filesrc_get_mmap (GstFileSrc *src)
|
||||||
/* either the read buffer overlaps the start of the mmap region */
|
/* either the read buffer overlaps the start of the mmap region */
|
||||||
/* or the read buffer fully contains the current mmap region */
|
/* or the read buffer fully contains the current mmap region */
|
||||||
/* either way, it's really not relevant, we just create a new region anyway*/
|
/* either way, it's really not relevant, we just create a new region anyway*/
|
||||||
fs_print ("read buf %llu+%d starts before mapbuf %d+%d, but overlaps it\n",
|
GST_LOG_OBJECT (src, "read buf %llu+%d starts before mapbuf %d+%d, but overlaps it",
|
||||||
src->curoffset,readsize, mapstart, mapsize);
|
(unsigned long long) src->curoffset, (gint) readsize, (gint) mapstart, (gint) mapsize);
|
||||||
buf = gst_filesrc_map_small_region (src, src->curoffset, readsize);
|
buf = gst_filesrc_map_small_region (src, src->curoffset, readsize);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -555,7 +545,7 @@ gst_filesrc_get_mmap (GstFileSrc *src)
|
||||||
/* then deal with the case where the read buffer is totally outside */
|
/* then deal with the case where the read buffer is totally outside */
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
/* first check to see if there's a map that covers the right region already */
|
/* first check to see if there's a map that covers the right region already */
|
||||||
fs_print ("searching for mapbuf to cover %llu+%d\n",src->curoffset,readsize);
|
GST_LOG_OBJECT (src, "searching for mapbuf to cover %llu+%d",src->curoffset,readsize);
|
||||||
region.offset = src->curoffset;
|
region.offset = src->curoffset;
|
||||||
region.size = readsize;
|
region.size = readsize;
|
||||||
map = g_tree_search (src->map_regions,
|
map = g_tree_search (src->map_regions,
|
||||||
|
@ -564,7 +554,8 @@ gst_filesrc_get_mmap (GstFileSrc *src)
|
||||||
|
|
||||||
/* if we found an exact match, subbuffer it */
|
/* if we found an exact match, subbuffer it */
|
||||||
if (map != NULL) {
|
if (map != NULL) {
|
||||||
fs_print ("found mapbuf at %d+%d, creating subbuffer\n",GST_BUFFER_OFFSET(map),GST_BUFFER_SIZE(map));
|
GST_LOG_OBJECT (src, "found mapbuf at %"G_GUINT64_FORMAT"+%u, creating subbuffer",
|
||||||
|
GST_BUFFER_OFFSET (map), GST_BUFFER_SIZE (map));
|
||||||
buf = gst_buffer_create_sub (map, src->curoffset - GST_BUFFER_OFFSET(map), readsize);
|
buf = gst_buffer_create_sub (map, src->curoffset - GST_BUFFER_OFFSET(map), readsize);
|
||||||
GST_BUFFER_OFFSET (buf) = src->curoffset;
|
GST_BUFFER_OFFSET (buf) = src->curoffset;
|
||||||
|
|
||||||
|
@ -572,7 +563,7 @@ gst_filesrc_get_mmap (GstFileSrc *src)
|
||||||
} else {
|
} else {
|
||||||
/* if the read buffer crosses a mmap region boundary, create a one-off region */
|
/* if the read buffer crosses a mmap region boundary, create a one-off region */
|
||||||
if ((src->curoffset / src->mapsize) != (readend / src->mapsize)) {
|
if ((src->curoffset / src->mapsize) != (readend / src->mapsize)) {
|
||||||
fs_print ("read buf %llu+%d crosses a %d-byte boundary, creating a one-off\n",
|
GST_LOG_OBJECT (src, "read buf %llu+%d crosses a %d-byte boundary, creating a one-off",
|
||||||
src->curoffset,readsize,src->mapsize);
|
src->curoffset,readsize,src->mapsize);
|
||||||
buf = gst_filesrc_map_small_region (src, src->curoffset, readsize);
|
buf = gst_filesrc_map_small_region (src, src->curoffset, readsize);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
|
@ -583,7 +574,7 @@ gst_filesrc_get_mmap (GstFileSrc *src)
|
||||||
size_t mapsize;
|
size_t mapsize;
|
||||||
|
|
||||||
off_t nextmap = src->curoffset - (src->curoffset % src->mapsize);
|
off_t nextmap = src->curoffset - (src->curoffset % src->mapsize);
|
||||||
fs_print ("read buf %llu+%d in new mapbuf at %llu+%d, mapping and subbuffering\n",
|
GST_LOG_OBJECT (src, "read buf %llu+%d in new mapbuf at %llu+%d, mapping and subbuffering",
|
||||||
src->curoffset, readsize, nextmap, src->mapsize);
|
src->curoffset, readsize, nextmap, src->mapsize);
|
||||||
/* first, we're done with the old mapbuf */
|
/* first, we're done with the old mapbuf */
|
||||||
gst_buffer_unref(src->mapbuf);
|
gst_buffer_unref(src->mapbuf);
|
||||||
|
@ -591,7 +582,7 @@ gst_filesrc_get_mmap (GstFileSrc *src)
|
||||||
|
|
||||||
/* double the mapsize as long as the readsize is smaller */
|
/* double the mapsize as long as the readsize is smaller */
|
||||||
while (readsize - (src->curoffset - nextmap) > mapsize) {
|
while (readsize - (src->curoffset - nextmap) > mapsize) {
|
||||||
fs_print ("readsize smaller then mapsize %08x %d\n", readsize, mapsize);
|
GST_LOG_OBJECT (src, "readsize smaller then mapsize %08x %d", readsize, mapsize);
|
||||||
mapsize <<=1;
|
mapsize <<=1;
|
||||||
}
|
}
|
||||||
/* create a new one */
|
/* create a new one */
|
||||||
|
@ -664,7 +655,7 @@ gst_filesrc_get (GstPad *pad)
|
||||||
GstEvent *event;
|
GstEvent *event;
|
||||||
|
|
||||||
src->seek_happened = FALSE;
|
src->seek_happened = FALSE;
|
||||||
GST_DEBUG ("filesrc sending discont");
|
GST_DEBUG_OBJECT (src, "sending discont");
|
||||||
event = gst_event_new_discontinuous (FALSE, GST_FORMAT_BYTES, src->curoffset, NULL);
|
event = gst_event_new_discontinuous (FALSE, GST_FORMAT_BYTES, src->curoffset, NULL);
|
||||||
src->need_flush = FALSE;
|
src->need_flush = FALSE;
|
||||||
return GST_DATA (event);
|
return GST_DATA (event);
|
||||||
|
@ -672,13 +663,13 @@ gst_filesrc_get (GstPad *pad)
|
||||||
/* check for flush */
|
/* check for flush */
|
||||||
if (src->need_flush) {
|
if (src->need_flush) {
|
||||||
src->need_flush = FALSE;
|
src->need_flush = FALSE;
|
||||||
GST_DEBUG ("filesrc sending flush");
|
GST_DEBUG_OBJECT (src, "sending flush");
|
||||||
return GST_DATA (gst_event_new_flush ());
|
return GST_DATA (gst_event_new_flush ());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check for EOF */
|
/* check for EOF */
|
||||||
if (src->curoffset == src->filelen) {
|
if (src->curoffset == src->filelen) {
|
||||||
GST_DEBUG ("filesrc 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));
|
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
||||||
|
@ -697,7 +688,7 @@ gst_filesrc_open_file (GstFileSrc *src)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (!GST_FLAG_IS_SET (src ,GST_FILESRC_OPEN), FALSE);
|
g_return_val_if_fail (!GST_FLAG_IS_SET (src ,GST_FILESRC_OPEN), FALSE);
|
||||||
|
|
||||||
GST_DEBUG ( "opening file %s",src->filename);
|
GST_INFO_OBJECT (src, "opening file %s",src->filename);
|
||||||
|
|
||||||
/* open the file */
|
/* open the file */
|
||||||
src->fd = open (src->filename, O_RDONLY);
|
src->fd = open (src->filename, O_RDONLY);
|
||||||
|
@ -829,7 +820,7 @@ gst_filesrc_srcpad_event (GstPad *pad, GstEvent *event)
|
||||||
{
|
{
|
||||||
GstFileSrc *src = GST_FILESRC (GST_PAD_PARENT (pad));
|
GstFileSrc *src = GST_FILESRC (GST_PAD_PARENT (pad));
|
||||||
|
|
||||||
GST_DEBUG ( "event %d", GST_EVENT_TYPE (event));
|
GST_DEBUG_OBJECT (src, "event %d", GST_EVENT_TYPE (event));
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
case GST_EVENT_SEEK:
|
case GST_EVENT_SEEK:
|
||||||
|
@ -847,19 +838,19 @@ gst_filesrc_srcpad_event (GstPad *pad, GstEvent *event)
|
||||||
if (offset > src->filelen)
|
if (offset > src->filelen)
|
||||||
goto error;
|
goto error;
|
||||||
src->curoffset = offset;
|
src->curoffset = offset;
|
||||||
GST_DEBUG ( "seek set pending to %" G_GINT64_FORMAT, src->curoffset);
|
GST_DEBUG_OBJECT (src, "seek set pending to %" G_GINT64_FORMAT, src->curoffset);
|
||||||
break;
|
break;
|
||||||
case GST_SEEK_METHOD_CUR:
|
case GST_SEEK_METHOD_CUR:
|
||||||
if (offset + src->curoffset > src->filelen)
|
if (offset + src->curoffset > src->filelen)
|
||||||
goto error;
|
goto error;
|
||||||
src->curoffset += offset;
|
src->curoffset += offset;
|
||||||
GST_DEBUG ( "seek cur pending to %" G_GINT64_FORMAT, src->curoffset);
|
GST_DEBUG_OBJECT (src, "seek cur pending to %" G_GINT64_FORMAT, src->curoffset);
|
||||||
break;
|
break;
|
||||||
case GST_SEEK_METHOD_END:
|
case GST_SEEK_METHOD_END:
|
||||||
if (ABS (offset) > src->filelen)
|
if (ABS (offset) > src->filelen)
|
||||||
goto error;
|
goto error;
|
||||||
src->curoffset = src->filelen - ABS (offset);
|
src->curoffset = src->filelen - ABS (offset);
|
||||||
GST_DEBUG ( "seek end pending to %" G_GINT64_FORMAT, src->curoffset);
|
GST_DEBUG_OBJECT (src, "seek end pending to %" G_GINT64_FORMAT, src->curoffset);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto error;
|
goto error;
|
||||||
|
|
669
gst/elements/gsttypefind.c
Normal file
669
gst/elements/gsttypefind.c
Normal file
|
@ -0,0 +1,669 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
|
*
|
||||||
|
* gsttypefind.c: element that detects type of stream
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* FIXME: need a better solution for non-seekable streams */
|
||||||
|
|
||||||
|
/* way of operation:
|
||||||
|
* 1) get a list of all typefind functions sorted best to worst
|
||||||
|
* 2) if all elements have been called with all requested data goto 8
|
||||||
|
* 3) call all functions once with all available data
|
||||||
|
* 4) if a function returns a value >= ARG_MAXIMUM goto 8
|
||||||
|
* 5) all functions with a result > ARG_MINIMUM or functions that did not get
|
||||||
|
* all requested data (where peek returned NULL) stay in list
|
||||||
|
* 6) seek to requested offset of best function that still has open data
|
||||||
|
* requests
|
||||||
|
* 7) goto 2
|
||||||
|
* 8) take best available result and use its caps
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "gsttypefindelement.h"
|
||||||
|
#include "gst/gst_private.h"
|
||||||
|
|
||||||
|
#include <gst/gsttypefind.h>
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY (gst_type_find_element_debug);
|
||||||
|
#define GST_CAT_DEFAULT gst_type_find_element_debug
|
||||||
|
|
||||||
|
GstElementDetails gst_type_find_element_details = {
|
||||||
|
"TypeFind",
|
||||||
|
"Generic",
|
||||||
|
"LGPL",
|
||||||
|
"Finds the media type of a stream",
|
||||||
|
VERSION,
|
||||||
|
"Benjamin Otte <in7y118@public.uni-hamburg.de>",
|
||||||
|
"(C) 2003",
|
||||||
|
};
|
||||||
|
|
||||||
|
/* generic templates */
|
||||||
|
GST_PAD_TEMPLATE_FACTORY (type_find_element_sink_factory,
|
||||||
|
"sink",
|
||||||
|
GST_PAD_SINK,
|
||||||
|
GST_PAD_ALWAYS,
|
||||||
|
GST_CAPS_ANY
|
||||||
|
);
|
||||||
|
GST_PAD_TEMPLATE_FACTORY (type_find_element_src_factory,
|
||||||
|
"src",
|
||||||
|
GST_PAD_SRC,
|
||||||
|
GST_PAD_ALWAYS,
|
||||||
|
GST_CAPS_ANY
|
||||||
|
);
|
||||||
|
|
||||||
|
/* TypeFind signals and args */
|
||||||
|
enum {
|
||||||
|
HAVE_TYPE,
|
||||||
|
LAST_SIGNAL
|
||||||
|
};
|
||||||
|
enum {
|
||||||
|
ARG_0,
|
||||||
|
ARG_CAPS,
|
||||||
|
ARG_MINIMUM,
|
||||||
|
ARG_MAXIMUM
|
||||||
|
};
|
||||||
|
enum {
|
||||||
|
MODE_NORMAL, /* act as identity */
|
||||||
|
MODE_TYPEFIND, /* do typefinding */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void gst_type_find_element_class_init (gpointer g_class,
|
||||||
|
gpointer class_data);
|
||||||
|
static void gst_type_find_element_init (GTypeInstance *instance,
|
||||||
|
gpointer g_class);
|
||||||
|
static void gst_type_find_element_dispose (GObject * object);
|
||||||
|
static void gst_type_find_element_set_property (GObject * object,
|
||||||
|
guint prop_id,
|
||||||
|
const GValue * value,
|
||||||
|
GParamSpec * pspec);
|
||||||
|
static void gst_type_find_element_get_property (GObject * object,
|
||||||
|
guint prop_id,
|
||||||
|
GValue * value,
|
||||||
|
GParamSpec * pspec);
|
||||||
|
|
||||||
|
static const GstEventMask *
|
||||||
|
gst_type_find_element_src_event_mask (GstPad * pad);
|
||||||
|
static gboolean gst_type_find_element_src_event (GstPad * pad,
|
||||||
|
GstEvent * event);
|
||||||
|
|
||||||
|
static void gst_type_find_element_chain (GstPad * sinkpad,
|
||||||
|
GstData * data);
|
||||||
|
static GstElementStateReturn
|
||||||
|
gst_type_find_element_change_state (GstElement * element);
|
||||||
|
|
||||||
|
static GstElementClass *parent_class = NULL;
|
||||||
|
static guint gst_type_find_element_signals[LAST_SIGNAL] = { 0 };
|
||||||
|
|
||||||
|
GType
|
||||||
|
gst_type_find_element_get_type (void)
|
||||||
|
{
|
||||||
|
static GType typefind_type = 0;
|
||||||
|
|
||||||
|
if (!typefind_type) {
|
||||||
|
static const GTypeInfo typefind_info = {
|
||||||
|
sizeof (GstTypeFindElementClass),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
gst_type_find_element_class_init,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
sizeof (GstTypeFindElement),
|
||||||
|
0,
|
||||||
|
gst_type_find_element_init,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
typefind_type = g_type_register_static (GST_TYPE_ELEMENT,
|
||||||
|
"GstTypeFindElement",
|
||||||
|
&typefind_info, 0);
|
||||||
|
}
|
||||||
|
return typefind_type;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_have_type (GstTypeFindElement *typefind, guint probability, GstCaps *caps)
|
||||||
|
{
|
||||||
|
gchar *caps_str;
|
||||||
|
|
||||||
|
g_assert (typefind->caps == NULL);
|
||||||
|
g_assert (caps != NULL);
|
||||||
|
|
||||||
|
caps_str = gst_caps_to_string (caps);
|
||||||
|
GST_INFO_OBJECT (typefind, "found caps %s", caps_str);
|
||||||
|
g_free (caps_str);
|
||||||
|
gst_caps_replace (&typefind->caps, caps);
|
||||||
|
if (gst_pad_try_set_caps (typefind->src, caps) < GST_PAD_LINK_OK) {
|
||||||
|
gst_element_error (GST_ELEMENT (typefind), "could not set caps on source pad");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_class_init (gpointer g_class, gpointer class_data)
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class;
|
||||||
|
GstElementClass *gstelement_class;
|
||||||
|
GstTypeFindElementClass *typefind_class;
|
||||||
|
|
||||||
|
gobject_class = G_OBJECT_CLASS (g_class);
|
||||||
|
gstelement_class = GST_ELEMENT_CLASS (g_class);
|
||||||
|
typefind_class = GST_TYPE_FIND_ELEMENT_CLASS (g_class);
|
||||||
|
|
||||||
|
parent_class = g_type_class_peek_parent (g_class);
|
||||||
|
|
||||||
|
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_type_find_element_set_property);
|
||||||
|
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_type_find_element_get_property);
|
||||||
|
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_type_find_element_dispose);
|
||||||
|
|
||||||
|
typefind_class->have_type = gst_type_find_element_have_type;
|
||||||
|
|
||||||
|
g_object_class_install_property (gobject_class, ARG_CAPS,
|
||||||
|
g_param_spec_boxed ("caps", _("caps"), _("detected capabilities in stream"),
|
||||||
|
GST_TYPE_CAPS, G_PARAM_READABLE));
|
||||||
|
g_object_class_install_property (gobject_class, ARG_MINIMUM,
|
||||||
|
g_param_spec_uint ("minimum", _("minimum"), "minimum probability required to accept caps",
|
||||||
|
GST_TYPE_FIND_MINIMUM, GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MINIMUM, G_PARAM_READWRITE));
|
||||||
|
g_object_class_install_property (gobject_class, ARG_MINIMUM,
|
||||||
|
g_param_spec_uint ("maximum", _("maximum"), "probability to stop typefinding",
|
||||||
|
GST_TYPE_FIND_MINIMUM, GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MAXIMUM, G_PARAM_READWRITE));
|
||||||
|
|
||||||
|
gst_type_find_element_signals[HAVE_TYPE] = g_signal_new ("have_type",
|
||||||
|
G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_LAST,
|
||||||
|
G_STRUCT_OFFSET (GstTypeFindElementClass, have_type), NULL, NULL,
|
||||||
|
gst_marshal_VOID__UINT_BOXED, G_TYPE_NONE, 2,
|
||||||
|
G_TYPE_UINT, GST_TYPE_CAPS);
|
||||||
|
|
||||||
|
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_type_find_element_change_state);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_init (GTypeInstance *instance, gpointer g_class)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (instance);
|
||||||
|
|
||||||
|
/* sinkpad */
|
||||||
|
typefind->sink = gst_pad_new_from_template (
|
||||||
|
GST_PAD_TEMPLATE_GET (type_find_element_sink_factory), "sink");
|
||||||
|
gst_pad_set_chain_function (typefind->sink,
|
||||||
|
gst_type_find_element_chain);
|
||||||
|
gst_element_add_pad (GST_ELEMENT (typefind), typefind->sink);
|
||||||
|
/* srcpad */
|
||||||
|
typefind->src = gst_pad_new_from_template (
|
||||||
|
GST_PAD_TEMPLATE_GET (type_find_element_src_factory), "src");
|
||||||
|
gst_pad_set_event_function (typefind->src, gst_type_find_element_src_event);
|
||||||
|
gst_pad_set_event_mask_function (typefind->src, gst_type_find_element_src_event_mask);
|
||||||
|
gst_element_add_pad (GST_ELEMENT (typefind), typefind->src);
|
||||||
|
|
||||||
|
typefind->caps = NULL;
|
||||||
|
typefind->min_probability = 1;
|
||||||
|
typefind->max_probability = GST_TYPE_FIND_MAXIMUM;
|
||||||
|
|
||||||
|
typefind->store = gst_buffer_store_new ();
|
||||||
|
|
||||||
|
GST_FLAG_SET (typefind, GST_ELEMENT_EVENT_AWARE);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_dispose (GObject *object)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (object);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||||
|
|
||||||
|
if (typefind->store) {
|
||||||
|
g_object_unref (typefind->store);
|
||||||
|
typefind->store = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_set_property (GObject *object, guint prop_id,
|
||||||
|
const GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind;
|
||||||
|
|
||||||
|
g_return_if_fail (GST_IS_TYPE_FIND_ELEMENT (object));
|
||||||
|
|
||||||
|
typefind = GST_TYPE_FIND_ELEMENT (object);
|
||||||
|
|
||||||
|
switch (prop_id) {
|
||||||
|
case ARG_MINIMUM:
|
||||||
|
typefind->min_probability = g_value_get_uint (value);
|
||||||
|
g_object_notify (object, "minimum");
|
||||||
|
break;
|
||||||
|
case ARG_MAXIMUM:
|
||||||
|
typefind->max_probability = g_value_get_uint (value);
|
||||||
|
g_object_notify (object, "maximum");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_get_property (GObject *object, guint prop_id,
|
||||||
|
GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind;
|
||||||
|
|
||||||
|
g_return_if_fail (GST_IS_TYPE_FIND_ELEMENT (object));
|
||||||
|
|
||||||
|
typefind = GST_TYPE_FIND_ELEMENT (object);
|
||||||
|
|
||||||
|
switch (prop_id) {
|
||||||
|
case ARG_CAPS:
|
||||||
|
g_value_set_boxed (value, typefind->caps);
|
||||||
|
break;
|
||||||
|
case ARG_MINIMUM:
|
||||||
|
g_value_set_uint (value, typefind->min_probability);
|
||||||
|
break;
|
||||||
|
case ARG_MAXIMUM:
|
||||||
|
g_value_set_uint (value, typefind->max_probability);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static const GstEventMask *
|
||||||
|
gst_type_find_element_src_event_mask (GstPad *pad)
|
||||||
|
{
|
||||||
|
static const GstEventMask mask[] = {
|
||||||
|
{ GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_END | GST_SEEK_FLAG_FLUSH},
|
||||||
|
/* add more if you want, event masks suck and need to die anyway */
|
||||||
|
{ 0, }
|
||||||
|
};
|
||||||
|
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
static gboolean
|
||||||
|
gst_type_find_element_src_event (GstPad *pad, GstEvent *event)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
|
||||||
|
|
||||||
|
if (typefind->mode == MODE_TYPEFIND) {
|
||||||
|
/* need to do more? */
|
||||||
|
gst_data_unref (GST_DATA (event));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return gst_pad_event_default (pad, event);
|
||||||
|
}
|
||||||
|
typedef struct {
|
||||||
|
GstTypeFindFactory * factory;
|
||||||
|
gint probability;
|
||||||
|
GstCaps * caps;
|
||||||
|
gint64 requested_offset;
|
||||||
|
guint requested_size;
|
||||||
|
|
||||||
|
GList * buffers;
|
||||||
|
GstTypeFindElement * self;
|
||||||
|
} TypeFindEntry;
|
||||||
|
static void
|
||||||
|
free_entry_buffers (TypeFindEntry *entry)
|
||||||
|
{
|
||||||
|
g_list_foreach (entry->buffers, (GFunc) gst_data_unref, NULL);
|
||||||
|
g_list_free (entry->buffers);
|
||||||
|
entry->buffers = NULL;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
free_entry (TypeFindEntry *entry)
|
||||||
|
{
|
||||||
|
free_entry_buffers (entry);
|
||||||
|
|
||||||
|
if (entry->caps)
|
||||||
|
gst_caps_unref (entry->caps);
|
||||||
|
g_free (entry);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
start_typefinding (GstTypeFindElement *typefind)
|
||||||
|
{
|
||||||
|
g_assert (typefind->caps == NULL);
|
||||||
|
g_assert (typefind->possibilities == NULL);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (typefind, "starting typefinding");
|
||||||
|
typefind->mode = MODE_TYPEFIND;
|
||||||
|
typefind->stream_length_available = TRUE;
|
||||||
|
typefind->stream_length = 0;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
stop_typefinding (GstTypeFindElement *typefind)
|
||||||
|
{
|
||||||
|
/* stop all typefinding and set mode back to normal */
|
||||||
|
gboolean push_cached_buffers = gst_element_get_state (GST_ELEMENT (typefind)) == GST_STATE_PLAYING;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (typefind, "stopping typefinding%s", push_cached_buffers ? " and pushing cached buffers" : "");
|
||||||
|
if (typefind->possibilities != NULL) {
|
||||||
|
/* this should only happen on PAUSED => READY or EOS */
|
||||||
|
GST_LOG_OBJECT (typefind, "freeing remaining %u typefind functions", g_list_length (typefind->possibilities));
|
||||||
|
g_list_foreach (typefind->possibilities, (GFunc) free_entry, NULL);
|
||||||
|
g_list_free (typefind->possibilities);
|
||||||
|
typefind->possibilities = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
typefind->mode = MODE_NORMAL;
|
||||||
|
|
||||||
|
if (push_cached_buffers) {
|
||||||
|
GstBuffer *buffer;
|
||||||
|
guint size = gst_buffer_store_get_size (typefind->store, 0);
|
||||||
|
if (size && (buffer = gst_buffer_store_get_buffer (typefind->store, 0, size))) {
|
||||||
|
gst_pad_push (typefind->src, GST_DATA (buffer));
|
||||||
|
} else {
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
GST_LOG_OBJECT (typefind, "seeking back to current position %u", size);
|
||||||
|
if (!gst_pad_send_event (GST_PAD_PEER (typefind->sink),
|
||||||
|
gst_event_new_seek (GST_SEEK_METHOD_SET | GST_FORMAT_BYTES, size))) {
|
||||||
|
GST_WARNING_OBJECT (typefind, "could not seek to required position %u, hope for the best", size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gst_buffer_store_clear (typefind->store);
|
||||||
|
}
|
||||||
|
static guint64
|
||||||
|
find_element_get_length (gpointer data)
|
||||||
|
{
|
||||||
|
TypeFindEntry *entry = (TypeFindEntry *) data;
|
||||||
|
GstTypeFindElement *typefind = entry->self;
|
||||||
|
GstFormat format = GST_FORMAT_BYTES;
|
||||||
|
|
||||||
|
if (!typefind->stream_length_available) {
|
||||||
|
GST_LOG_OBJECT (entry->self, "'%s' called get_length () but we know it's not available",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (entry->self->stream_length == 0) {
|
||||||
|
typefind->stream_length_available = gst_pad_query (GST_PAD_PEER (entry->self->sink), GST_QUERY_TOTAL,
|
||||||
|
&format, &entry->self->stream_length);
|
||||||
|
if (format != GST_FORMAT_BYTES)
|
||||||
|
typefind->stream_length_available = FALSE;
|
||||||
|
if (!typefind->stream_length_available) {
|
||||||
|
GST_DEBUG_OBJECT (entry->self, "'%s' called get_length () but it's not available",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory));
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
GST_DEBUG_OBJECT (entry->self, "'%s' called get_length () and it's %"G_GUINT64_FORMAT" bytes",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), entry->self->stream_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry->self->stream_length;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_handle_event (GstPad *pad, GstEvent *event)
|
||||||
|
{
|
||||||
|
TypeFindEntry *entry;
|
||||||
|
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
|
||||||
|
|
||||||
|
if (typefind->mode == MODE_TYPEFIND) {
|
||||||
|
/* need to do more? */
|
||||||
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_EOS:
|
||||||
|
/* this should only happen when we got all available data */
|
||||||
|
entry = (TypeFindEntry *) typefind->possibilities ? typefind->possibilities->data : NULL;
|
||||||
|
if (entry && entry->probability >= typefind->min_probability) {
|
||||||
|
GST_INFO_OBJECT (typefind, "'%s' is the best typefind left after we got all data, using it now (probability %u)",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), entry->probability);
|
||||||
|
g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0, entry->probability, entry->caps);
|
||||||
|
}
|
||||||
|
stop_typefinding (typefind);
|
||||||
|
gst_pad_event_default (pad, event);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
gst_data_unref (GST_DATA (event));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
gst_pad_event_default (pad, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static guint8 *
|
||||||
|
find_peek (gpointer data, gint64 offset, guint size)
|
||||||
|
{
|
||||||
|
GstBuffer *buf;
|
||||||
|
TypeFindEntry *entry = (TypeFindEntry *) data;
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (entry->self, "'%s' called peek (%"G_GINT64_FORMAT", %u)",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), offset, size);
|
||||||
|
if (offset >= 0) {
|
||||||
|
buf = gst_buffer_store_get_buffer (entry->self->store, offset, size);
|
||||||
|
} else {
|
||||||
|
/* FIXME: can we do this easily without querying length? */
|
||||||
|
guint64 length = find_element_get_length (data);
|
||||||
|
|
||||||
|
if (length == 0) {
|
||||||
|
buf = NULL;
|
||||||
|
} else {
|
||||||
|
buf = gst_buffer_store_get_buffer (entry->self->store, length + offset, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf) {
|
||||||
|
entry->buffers = g_list_prepend (entry->buffers, buf);
|
||||||
|
return GST_BUFFER_DATA (buf);
|
||||||
|
} else {
|
||||||
|
if (entry->requested_size == 0) {
|
||||||
|
GST_LOG_OBJECT (entry->self, "setting requested peek (%"G_GINT64_FORMAT", %u) on '%s'",
|
||||||
|
offset, size, GST_PLUGIN_FEATURE_NAME (entry->factory));
|
||||||
|
entry->requested_offset = offset;
|
||||||
|
entry->requested_size = size;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
find_suggest (gpointer data, guint probability, GstCaps *caps)
|
||||||
|
{
|
||||||
|
gchar *str;
|
||||||
|
TypeFindEntry *entry = (TypeFindEntry *) data;
|
||||||
|
|
||||||
|
str = gst_caps_to_string (caps);
|
||||||
|
GST_LOG_OBJECT (entry->self, "'%s' called suggest (%u, %s)",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), probability, str);
|
||||||
|
g_free (str);
|
||||||
|
if (((gint) probability) > entry->probability) {
|
||||||
|
entry->probability = probability;
|
||||||
|
gst_caps_replace (&entry->caps, caps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static gint
|
||||||
|
compare_type_find_entry (gconstpointer a, gconstpointer b)
|
||||||
|
{
|
||||||
|
TypeFindEntry *one = (TypeFindEntry *) a;
|
||||||
|
TypeFindEntry *two = (TypeFindEntry *) b;
|
||||||
|
|
||||||
|
if (one->probability == two->probability) {
|
||||||
|
/* FIXME: can be improved by analyzing requests */
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return two->probability - one->probability;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static gint
|
||||||
|
compare_type_find_factory (gconstpointer fac1, gconstpointer fac2)
|
||||||
|
{
|
||||||
|
return GST_PLUGIN_FEATURE (fac1)->rank - GST_PLUGIN_FEATURE (fac2)->rank;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_chain (GstPad *pad, GstData *data)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind;
|
||||||
|
GList *entries;
|
||||||
|
TypeFindEntry *entry;
|
||||||
|
GList *walk;
|
||||||
|
GstTypeFind find = {find_peek, find_suggest, NULL, find_element_get_length };
|
||||||
|
|
||||||
|
typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
|
||||||
|
if (GST_IS_EVENT (data)) {
|
||||||
|
gst_type_find_element_handle_event (pad, GST_EVENT (data));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (typefind->mode) {
|
||||||
|
case MODE_NORMAL:
|
||||||
|
gst_pad_push (typefind->src, data);
|
||||||
|
return;
|
||||||
|
case MODE_TYPEFIND: {
|
||||||
|
gst_buffer_store_add_buffer (typefind->store, GST_BUFFER (data));
|
||||||
|
gst_data_unref (data);
|
||||||
|
if (typefind->possibilities == NULL) {
|
||||||
|
/* not yet started, get all typefinding functions into our "queue" */
|
||||||
|
GList *all_factories = gst_type_find_factory_get_list ();
|
||||||
|
GST_INFO_OBJECT (typefind, "starting with %u typefinding functions",
|
||||||
|
g_list_length ((GList *) all_factories));
|
||||||
|
|
||||||
|
all_factories = g_list_sort (all_factories, compare_type_find_factory);
|
||||||
|
walk = all_factories;
|
||||||
|
while (all_factories) {
|
||||||
|
entry = g_new0 (TypeFindEntry, 1);
|
||||||
|
|
||||||
|
entry->factory = GST_TYPE_FIND_FACTORY (all_factories->data);
|
||||||
|
entry->self = typefind;
|
||||||
|
entry->probability = 0;
|
||||||
|
typefind->possibilities = g_list_prepend (typefind->possibilities, entry);
|
||||||
|
all_factories = g_list_next (all_factories);
|
||||||
|
}
|
||||||
|
g_list_free (all_factories);
|
||||||
|
}
|
||||||
|
/* call every typefind function once */
|
||||||
|
walk = entries = typefind->possibilities;
|
||||||
|
GST_INFO_OBJECT (typefind, "iterating %u typefinding functions", g_list_length (entries));
|
||||||
|
typefind->possibilities = NULL;
|
||||||
|
while (walk) {
|
||||||
|
find.data = entry = (TypeFindEntry *) walk->data;
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
entry->probability = 0;
|
||||||
|
entry->requested_offset = 0;
|
||||||
|
entry->requested_size = 0;
|
||||||
|
gst_type_find_factory_call_function (entry->factory, &find);
|
||||||
|
free_entry_buffers (entry);
|
||||||
|
if (entry->probability == 0 && entry->requested_size == 0) {
|
||||||
|
GST_DEBUG_OBJECT (typefind, "'%s' was removed - no chance of being the right plugin",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory));
|
||||||
|
free_entry (entry);
|
||||||
|
} else if (entry->probability >= typefind->max_probability) {
|
||||||
|
/* wooha, got caps */
|
||||||
|
GstCaps *found_caps = entry->caps;
|
||||||
|
guint probability = entry->probability;
|
||||||
|
|
||||||
|
gst_caps_ref (found_caps);
|
||||||
|
GST_INFO_OBJECT (typefind, "'%s' returned %u/%u probability, using it NOW",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), probability, typefind->max_probability);
|
||||||
|
while (walk) {
|
||||||
|
free_entry ((TypeFindEntry *) walk->data);
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
}
|
||||||
|
walk = typefind->possibilities;
|
||||||
|
while (walk) {
|
||||||
|
free_entry (walk->data);
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
}
|
||||||
|
typefind->possibilities = NULL;
|
||||||
|
g_list_free (typefind->possibilities);
|
||||||
|
g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0, probability, found_caps);
|
||||||
|
gst_caps_unref (found_caps);
|
||||||
|
} else {
|
||||||
|
typefind->possibilities = g_list_prepend (typefind->possibilities, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_list_free (entries);
|
||||||
|
/* we may now already have caps or we might be left without functions to try */
|
||||||
|
if (typefind->caps) {
|
||||||
|
stop_typefinding (typefind);
|
||||||
|
} else if (typefind->possibilities == NULL) {
|
||||||
|
gst_element_error (GST_ELEMENT (typefind), "media type could not be detected");
|
||||||
|
} else {
|
||||||
|
/* set up typefind element for next iteration */
|
||||||
|
typefind->possibilities = g_list_sort (typefind->possibilities, compare_type_find_entry);
|
||||||
|
|
||||||
|
walk = typefind->possibilities;
|
||||||
|
while (walk) {
|
||||||
|
entry = (TypeFindEntry *) walk->data;
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
if (entry->requested_size > 0) {
|
||||||
|
/* FIXME: need heuristic to find out if we should seek */
|
||||||
|
gint64 seek_offset;
|
||||||
|
GstEvent *event;
|
||||||
|
|
||||||
|
seek_offset = entry->requested_offset > 0 ? entry->requested_offset :
|
||||||
|
find_element_get_length (entry) + entry->requested_offset;
|
||||||
|
seek_offset += gst_buffer_store_get_size (typefind->store, seek_offset);
|
||||||
|
event = gst_event_new_seek (GST_FORMAT_BYTES | GST_SEEK_METHOD_SET, seek_offset);
|
||||||
|
if (gst_pad_send_event (GST_PAD_PEER (typefind->sink), event)) {
|
||||||
|
/* done seeking */
|
||||||
|
GST_DEBUG_OBJECT (typefind, "'%s' was reset - seeked to %"G_GINT64_FORMAT,
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), seek_offset);
|
||||||
|
break;
|
||||||
|
} else if (entry->requested_offset < 0) {
|
||||||
|
/* impossible to seek */
|
||||||
|
GST_DEBUG_OBJECT (typefind, "'%s' was reset - couldn't seek to %"G_GINT64_FORMAT,
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), seek_offset);
|
||||||
|
entry->requested_size = 0;
|
||||||
|
entry->requested_offset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* throw out all entries that can't get more data */
|
||||||
|
walk = g_list_next (typefind->possibilities);
|
||||||
|
while (walk) {
|
||||||
|
GList *cur = walk;
|
||||||
|
entry = (TypeFindEntry *) walk->data;
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
if (entry->requested_size == 0) {
|
||||||
|
GST_DEBUG_OBJECT (typefind, "'%s' was removed - higher possibilities available",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory));
|
||||||
|
free_entry (entry);
|
||||||
|
typefind->possibilities = g_list_delete_link (typefind->possibilities, cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (g_list_next (typefind->possibilities) == NULL) {
|
||||||
|
entry = (TypeFindEntry *) typefind->possibilities->data;
|
||||||
|
if (entry->probability > typefind->min_probability) {
|
||||||
|
GST_INFO_OBJECT (typefind, "'%s' is the only typefind left, using it now (probability %u)",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), entry->probability);
|
||||||
|
g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0, entry->probability, entry->caps);
|
||||||
|
free_entry (entry);
|
||||||
|
g_list_free (typefind->possibilities);
|
||||||
|
typefind->possibilities = NULL;
|
||||||
|
stop_typefinding (typefind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static GstElementStateReturn
|
||||||
|
gst_type_find_element_change_state (GstElement *element)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind;
|
||||||
|
|
||||||
|
typefind = GST_TYPE_FIND_ELEMENT (element);
|
||||||
|
|
||||||
|
switch (GST_STATE_TRANSITION (element)) {
|
||||||
|
case GST_STATE_READY_TO_PAUSED:
|
||||||
|
start_typefinding (typefind);
|
||||||
|
break;
|
||||||
|
case GST_STATE_PAUSED_TO_READY:
|
||||||
|
stop_typefinding (typefind);
|
||||||
|
gst_caps_replace (&typefind->caps, NULL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||||
|
}
|
78
gst/elements/gsttypefind.h
Normal file
78
gst/elements/gsttypefind.h
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
|
*
|
||||||
|
* gsttypefind.h: element that detects type of stream
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __GST_TYPE_FIND_ELEMENT_H__
|
||||||
|
#define __GST_TYPE_FIND_ELEMENT_H__
|
||||||
|
|
||||||
|
#include <gst/gstinfo.h>
|
||||||
|
#include <gst/gstelement.h>
|
||||||
|
/* #include <gst/gstbufferstore.h> */
|
||||||
|
#include "gstbufferstore.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_EXTERN(gst_type_find_element_debug);
|
||||||
|
|
||||||
|
extern GstElementDetails gst_type_find_element_details;
|
||||||
|
|
||||||
|
#define GST_TYPE_TYPE_FIND_ELEMENT (gst_type_find_element_get_type ())
|
||||||
|
#define GST_TYPE_FIND_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TYPE_FIND_ELEMENT, GstTypeFindElement))
|
||||||
|
#define GST_IS_TYPE_FIND_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TYPE_FIND_ELEMENT))
|
||||||
|
#define GST_TYPE_FIND_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_TYPE_FIND_ELEMENT, GstTypeFindElementClass))
|
||||||
|
#define GST_IS_TYPE_FIND_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_TYPE_FIND_ELEMENT))
|
||||||
|
#define GST_TYPE_FIND_ELEMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_TYPE_FIND_ELEMENT, GstTypeFindElementClass))
|
||||||
|
|
||||||
|
typedef struct _GstTypeFindElement GstTypeFindElement;
|
||||||
|
typedef struct _GstTypeFindElementClass GstTypeFindElementClass;
|
||||||
|
|
||||||
|
struct _GstTypeFindElement {
|
||||||
|
GstElement element;
|
||||||
|
|
||||||
|
GstPad * sink;
|
||||||
|
GstPad * src;
|
||||||
|
|
||||||
|
guint min_probability;
|
||||||
|
guint max_probability;
|
||||||
|
GstCaps * caps;
|
||||||
|
|
||||||
|
guint mode;
|
||||||
|
GstBufferStore * store;
|
||||||
|
guint64 stream_length;
|
||||||
|
gboolean stream_length_available;
|
||||||
|
|
||||||
|
GList * possibilities;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GstTypeFindElementClass {
|
||||||
|
GstElementClass parent_class;
|
||||||
|
|
||||||
|
/* signals */
|
||||||
|
void (*have_type) (GstTypeFindElement *element,
|
||||||
|
guint probability,
|
||||||
|
GstCaps * caps);
|
||||||
|
};
|
||||||
|
|
||||||
|
GType gst_type_find_element_get_type (void);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __GST_TYPE_FIND_ELEMENT_H__ */
|
669
gst/elements/gsttypefindelement.c
Normal file
669
gst/elements/gsttypefindelement.c
Normal file
|
@ -0,0 +1,669 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
|
*
|
||||||
|
* gsttypefind.c: element that detects type of stream
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* FIXME: need a better solution for non-seekable streams */
|
||||||
|
|
||||||
|
/* way of operation:
|
||||||
|
* 1) get a list of all typefind functions sorted best to worst
|
||||||
|
* 2) if all elements have been called with all requested data goto 8
|
||||||
|
* 3) call all functions once with all available data
|
||||||
|
* 4) if a function returns a value >= ARG_MAXIMUM goto 8
|
||||||
|
* 5) all functions with a result > ARG_MINIMUM or functions that did not get
|
||||||
|
* all requested data (where peek returned NULL) stay in list
|
||||||
|
* 6) seek to requested offset of best function that still has open data
|
||||||
|
* requests
|
||||||
|
* 7) goto 2
|
||||||
|
* 8) take best available result and use its caps
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "gsttypefindelement.h"
|
||||||
|
#include "gst/gst_private.h"
|
||||||
|
|
||||||
|
#include <gst/gsttypefind.h>
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY (gst_type_find_element_debug);
|
||||||
|
#define GST_CAT_DEFAULT gst_type_find_element_debug
|
||||||
|
|
||||||
|
GstElementDetails gst_type_find_element_details = {
|
||||||
|
"TypeFind",
|
||||||
|
"Generic",
|
||||||
|
"LGPL",
|
||||||
|
"Finds the media type of a stream",
|
||||||
|
VERSION,
|
||||||
|
"Benjamin Otte <in7y118@public.uni-hamburg.de>",
|
||||||
|
"(C) 2003",
|
||||||
|
};
|
||||||
|
|
||||||
|
/* generic templates */
|
||||||
|
GST_PAD_TEMPLATE_FACTORY (type_find_element_sink_factory,
|
||||||
|
"sink",
|
||||||
|
GST_PAD_SINK,
|
||||||
|
GST_PAD_ALWAYS,
|
||||||
|
GST_CAPS_ANY
|
||||||
|
);
|
||||||
|
GST_PAD_TEMPLATE_FACTORY (type_find_element_src_factory,
|
||||||
|
"src",
|
||||||
|
GST_PAD_SRC,
|
||||||
|
GST_PAD_ALWAYS,
|
||||||
|
GST_CAPS_ANY
|
||||||
|
);
|
||||||
|
|
||||||
|
/* TypeFind signals and args */
|
||||||
|
enum {
|
||||||
|
HAVE_TYPE,
|
||||||
|
LAST_SIGNAL
|
||||||
|
};
|
||||||
|
enum {
|
||||||
|
ARG_0,
|
||||||
|
ARG_CAPS,
|
||||||
|
ARG_MINIMUM,
|
||||||
|
ARG_MAXIMUM
|
||||||
|
};
|
||||||
|
enum {
|
||||||
|
MODE_NORMAL, /* act as identity */
|
||||||
|
MODE_TYPEFIND, /* do typefinding */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void gst_type_find_element_class_init (gpointer g_class,
|
||||||
|
gpointer class_data);
|
||||||
|
static void gst_type_find_element_init (GTypeInstance *instance,
|
||||||
|
gpointer g_class);
|
||||||
|
static void gst_type_find_element_dispose (GObject * object);
|
||||||
|
static void gst_type_find_element_set_property (GObject * object,
|
||||||
|
guint prop_id,
|
||||||
|
const GValue * value,
|
||||||
|
GParamSpec * pspec);
|
||||||
|
static void gst_type_find_element_get_property (GObject * object,
|
||||||
|
guint prop_id,
|
||||||
|
GValue * value,
|
||||||
|
GParamSpec * pspec);
|
||||||
|
|
||||||
|
static const GstEventMask *
|
||||||
|
gst_type_find_element_src_event_mask (GstPad * pad);
|
||||||
|
static gboolean gst_type_find_element_src_event (GstPad * pad,
|
||||||
|
GstEvent * event);
|
||||||
|
|
||||||
|
static void gst_type_find_element_chain (GstPad * sinkpad,
|
||||||
|
GstData * data);
|
||||||
|
static GstElementStateReturn
|
||||||
|
gst_type_find_element_change_state (GstElement * element);
|
||||||
|
|
||||||
|
static GstElementClass *parent_class = NULL;
|
||||||
|
static guint gst_type_find_element_signals[LAST_SIGNAL] = { 0 };
|
||||||
|
|
||||||
|
GType
|
||||||
|
gst_type_find_element_get_type (void)
|
||||||
|
{
|
||||||
|
static GType typefind_type = 0;
|
||||||
|
|
||||||
|
if (!typefind_type) {
|
||||||
|
static const GTypeInfo typefind_info = {
|
||||||
|
sizeof (GstTypeFindElementClass),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
gst_type_find_element_class_init,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
sizeof (GstTypeFindElement),
|
||||||
|
0,
|
||||||
|
gst_type_find_element_init,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
typefind_type = g_type_register_static (GST_TYPE_ELEMENT,
|
||||||
|
"GstTypeFindElement",
|
||||||
|
&typefind_info, 0);
|
||||||
|
}
|
||||||
|
return typefind_type;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_have_type (GstTypeFindElement *typefind, guint probability, GstCaps *caps)
|
||||||
|
{
|
||||||
|
gchar *caps_str;
|
||||||
|
|
||||||
|
g_assert (typefind->caps == NULL);
|
||||||
|
g_assert (caps != NULL);
|
||||||
|
|
||||||
|
caps_str = gst_caps_to_string (caps);
|
||||||
|
GST_INFO_OBJECT (typefind, "found caps %s", caps_str);
|
||||||
|
g_free (caps_str);
|
||||||
|
gst_caps_replace (&typefind->caps, caps);
|
||||||
|
if (gst_pad_try_set_caps (typefind->src, caps) < GST_PAD_LINK_OK) {
|
||||||
|
gst_element_error (GST_ELEMENT (typefind), "could not set caps on source pad");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_class_init (gpointer g_class, gpointer class_data)
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class;
|
||||||
|
GstElementClass *gstelement_class;
|
||||||
|
GstTypeFindElementClass *typefind_class;
|
||||||
|
|
||||||
|
gobject_class = G_OBJECT_CLASS (g_class);
|
||||||
|
gstelement_class = GST_ELEMENT_CLASS (g_class);
|
||||||
|
typefind_class = GST_TYPE_FIND_ELEMENT_CLASS (g_class);
|
||||||
|
|
||||||
|
parent_class = g_type_class_peek_parent (g_class);
|
||||||
|
|
||||||
|
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_type_find_element_set_property);
|
||||||
|
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_type_find_element_get_property);
|
||||||
|
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_type_find_element_dispose);
|
||||||
|
|
||||||
|
typefind_class->have_type = gst_type_find_element_have_type;
|
||||||
|
|
||||||
|
g_object_class_install_property (gobject_class, ARG_CAPS,
|
||||||
|
g_param_spec_boxed ("caps", _("caps"), _("detected capabilities in stream"),
|
||||||
|
GST_TYPE_CAPS, G_PARAM_READABLE));
|
||||||
|
g_object_class_install_property (gobject_class, ARG_MINIMUM,
|
||||||
|
g_param_spec_uint ("minimum", _("minimum"), "minimum probability required to accept caps",
|
||||||
|
GST_TYPE_FIND_MINIMUM, GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MINIMUM, G_PARAM_READWRITE));
|
||||||
|
g_object_class_install_property (gobject_class, ARG_MINIMUM,
|
||||||
|
g_param_spec_uint ("maximum", _("maximum"), "probability to stop typefinding",
|
||||||
|
GST_TYPE_FIND_MINIMUM, GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MAXIMUM, G_PARAM_READWRITE));
|
||||||
|
|
||||||
|
gst_type_find_element_signals[HAVE_TYPE] = g_signal_new ("have_type",
|
||||||
|
G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_LAST,
|
||||||
|
G_STRUCT_OFFSET (GstTypeFindElementClass, have_type), NULL, NULL,
|
||||||
|
gst_marshal_VOID__UINT_BOXED, G_TYPE_NONE, 2,
|
||||||
|
G_TYPE_UINT, GST_TYPE_CAPS);
|
||||||
|
|
||||||
|
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_type_find_element_change_state);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_init (GTypeInstance *instance, gpointer g_class)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (instance);
|
||||||
|
|
||||||
|
/* sinkpad */
|
||||||
|
typefind->sink = gst_pad_new_from_template (
|
||||||
|
GST_PAD_TEMPLATE_GET (type_find_element_sink_factory), "sink");
|
||||||
|
gst_pad_set_chain_function (typefind->sink,
|
||||||
|
gst_type_find_element_chain);
|
||||||
|
gst_element_add_pad (GST_ELEMENT (typefind), typefind->sink);
|
||||||
|
/* srcpad */
|
||||||
|
typefind->src = gst_pad_new_from_template (
|
||||||
|
GST_PAD_TEMPLATE_GET (type_find_element_src_factory), "src");
|
||||||
|
gst_pad_set_event_function (typefind->src, gst_type_find_element_src_event);
|
||||||
|
gst_pad_set_event_mask_function (typefind->src, gst_type_find_element_src_event_mask);
|
||||||
|
gst_element_add_pad (GST_ELEMENT (typefind), typefind->src);
|
||||||
|
|
||||||
|
typefind->caps = NULL;
|
||||||
|
typefind->min_probability = 1;
|
||||||
|
typefind->max_probability = GST_TYPE_FIND_MAXIMUM;
|
||||||
|
|
||||||
|
typefind->store = gst_buffer_store_new ();
|
||||||
|
|
||||||
|
GST_FLAG_SET (typefind, GST_ELEMENT_EVENT_AWARE);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_dispose (GObject *object)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (object);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||||
|
|
||||||
|
if (typefind->store) {
|
||||||
|
g_object_unref (typefind->store);
|
||||||
|
typefind->store = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_set_property (GObject *object, guint prop_id,
|
||||||
|
const GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind;
|
||||||
|
|
||||||
|
g_return_if_fail (GST_IS_TYPE_FIND_ELEMENT (object));
|
||||||
|
|
||||||
|
typefind = GST_TYPE_FIND_ELEMENT (object);
|
||||||
|
|
||||||
|
switch (prop_id) {
|
||||||
|
case ARG_MINIMUM:
|
||||||
|
typefind->min_probability = g_value_get_uint (value);
|
||||||
|
g_object_notify (object, "minimum");
|
||||||
|
break;
|
||||||
|
case ARG_MAXIMUM:
|
||||||
|
typefind->max_probability = g_value_get_uint (value);
|
||||||
|
g_object_notify (object, "maximum");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_get_property (GObject *object, guint prop_id,
|
||||||
|
GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind;
|
||||||
|
|
||||||
|
g_return_if_fail (GST_IS_TYPE_FIND_ELEMENT (object));
|
||||||
|
|
||||||
|
typefind = GST_TYPE_FIND_ELEMENT (object);
|
||||||
|
|
||||||
|
switch (prop_id) {
|
||||||
|
case ARG_CAPS:
|
||||||
|
g_value_set_boxed (value, typefind->caps);
|
||||||
|
break;
|
||||||
|
case ARG_MINIMUM:
|
||||||
|
g_value_set_uint (value, typefind->min_probability);
|
||||||
|
break;
|
||||||
|
case ARG_MAXIMUM:
|
||||||
|
g_value_set_uint (value, typefind->max_probability);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static const GstEventMask *
|
||||||
|
gst_type_find_element_src_event_mask (GstPad *pad)
|
||||||
|
{
|
||||||
|
static const GstEventMask mask[] = {
|
||||||
|
{ GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_END | GST_SEEK_FLAG_FLUSH},
|
||||||
|
/* add more if you want, event masks suck and need to die anyway */
|
||||||
|
{ 0, }
|
||||||
|
};
|
||||||
|
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
static gboolean
|
||||||
|
gst_type_find_element_src_event (GstPad *pad, GstEvent *event)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
|
||||||
|
|
||||||
|
if (typefind->mode == MODE_TYPEFIND) {
|
||||||
|
/* need to do more? */
|
||||||
|
gst_data_unref (GST_DATA (event));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return gst_pad_event_default (pad, event);
|
||||||
|
}
|
||||||
|
typedef struct {
|
||||||
|
GstTypeFindFactory * factory;
|
||||||
|
gint probability;
|
||||||
|
GstCaps * caps;
|
||||||
|
gint64 requested_offset;
|
||||||
|
guint requested_size;
|
||||||
|
|
||||||
|
GList * buffers;
|
||||||
|
GstTypeFindElement * self;
|
||||||
|
} TypeFindEntry;
|
||||||
|
static void
|
||||||
|
free_entry_buffers (TypeFindEntry *entry)
|
||||||
|
{
|
||||||
|
g_list_foreach (entry->buffers, (GFunc) gst_data_unref, NULL);
|
||||||
|
g_list_free (entry->buffers);
|
||||||
|
entry->buffers = NULL;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
free_entry (TypeFindEntry *entry)
|
||||||
|
{
|
||||||
|
free_entry_buffers (entry);
|
||||||
|
|
||||||
|
if (entry->caps)
|
||||||
|
gst_caps_unref (entry->caps);
|
||||||
|
g_free (entry);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
start_typefinding (GstTypeFindElement *typefind)
|
||||||
|
{
|
||||||
|
g_assert (typefind->caps == NULL);
|
||||||
|
g_assert (typefind->possibilities == NULL);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (typefind, "starting typefinding");
|
||||||
|
typefind->mode = MODE_TYPEFIND;
|
||||||
|
typefind->stream_length_available = TRUE;
|
||||||
|
typefind->stream_length = 0;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
stop_typefinding (GstTypeFindElement *typefind)
|
||||||
|
{
|
||||||
|
/* stop all typefinding and set mode back to normal */
|
||||||
|
gboolean push_cached_buffers = gst_element_get_state (GST_ELEMENT (typefind)) == GST_STATE_PLAYING;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (typefind, "stopping typefinding%s", push_cached_buffers ? " and pushing cached buffers" : "");
|
||||||
|
if (typefind->possibilities != NULL) {
|
||||||
|
/* this should only happen on PAUSED => READY or EOS */
|
||||||
|
GST_LOG_OBJECT (typefind, "freeing remaining %u typefind functions", g_list_length (typefind->possibilities));
|
||||||
|
g_list_foreach (typefind->possibilities, (GFunc) free_entry, NULL);
|
||||||
|
g_list_free (typefind->possibilities);
|
||||||
|
typefind->possibilities = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
typefind->mode = MODE_NORMAL;
|
||||||
|
|
||||||
|
if (push_cached_buffers) {
|
||||||
|
GstBuffer *buffer;
|
||||||
|
guint size = gst_buffer_store_get_size (typefind->store, 0);
|
||||||
|
if (size && (buffer = gst_buffer_store_get_buffer (typefind->store, 0, size))) {
|
||||||
|
gst_pad_push (typefind->src, GST_DATA (buffer));
|
||||||
|
} else {
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
GST_LOG_OBJECT (typefind, "seeking back to current position %u", size);
|
||||||
|
if (!gst_pad_send_event (GST_PAD_PEER (typefind->sink),
|
||||||
|
gst_event_new_seek (GST_SEEK_METHOD_SET | GST_FORMAT_BYTES, size))) {
|
||||||
|
GST_WARNING_OBJECT (typefind, "could not seek to required position %u, hope for the best", size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gst_buffer_store_clear (typefind->store);
|
||||||
|
}
|
||||||
|
static guint64
|
||||||
|
find_element_get_length (gpointer data)
|
||||||
|
{
|
||||||
|
TypeFindEntry *entry = (TypeFindEntry *) data;
|
||||||
|
GstTypeFindElement *typefind = entry->self;
|
||||||
|
GstFormat format = GST_FORMAT_BYTES;
|
||||||
|
|
||||||
|
if (!typefind->stream_length_available) {
|
||||||
|
GST_LOG_OBJECT (entry->self, "'%s' called get_length () but we know it's not available",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (entry->self->stream_length == 0) {
|
||||||
|
typefind->stream_length_available = gst_pad_query (GST_PAD_PEER (entry->self->sink), GST_QUERY_TOTAL,
|
||||||
|
&format, &entry->self->stream_length);
|
||||||
|
if (format != GST_FORMAT_BYTES)
|
||||||
|
typefind->stream_length_available = FALSE;
|
||||||
|
if (!typefind->stream_length_available) {
|
||||||
|
GST_DEBUG_OBJECT (entry->self, "'%s' called get_length () but it's not available",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory));
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
GST_DEBUG_OBJECT (entry->self, "'%s' called get_length () and it's %"G_GUINT64_FORMAT" bytes",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), entry->self->stream_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry->self->stream_length;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_handle_event (GstPad *pad, GstEvent *event)
|
||||||
|
{
|
||||||
|
TypeFindEntry *entry;
|
||||||
|
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
|
||||||
|
|
||||||
|
if (typefind->mode == MODE_TYPEFIND) {
|
||||||
|
/* need to do more? */
|
||||||
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_EOS:
|
||||||
|
/* this should only happen when we got all available data */
|
||||||
|
entry = (TypeFindEntry *) typefind->possibilities ? typefind->possibilities->data : NULL;
|
||||||
|
if (entry && entry->probability >= typefind->min_probability) {
|
||||||
|
GST_INFO_OBJECT (typefind, "'%s' is the best typefind left after we got all data, using it now (probability %u)",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), entry->probability);
|
||||||
|
g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0, entry->probability, entry->caps);
|
||||||
|
}
|
||||||
|
stop_typefinding (typefind);
|
||||||
|
gst_pad_event_default (pad, event);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
gst_data_unref (GST_DATA (event));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
gst_pad_event_default (pad, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static guint8 *
|
||||||
|
find_peek (gpointer data, gint64 offset, guint size)
|
||||||
|
{
|
||||||
|
GstBuffer *buf;
|
||||||
|
TypeFindEntry *entry = (TypeFindEntry *) data;
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (entry->self, "'%s' called peek (%"G_GINT64_FORMAT", %u)",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), offset, size);
|
||||||
|
if (offset >= 0) {
|
||||||
|
buf = gst_buffer_store_get_buffer (entry->self->store, offset, size);
|
||||||
|
} else {
|
||||||
|
/* FIXME: can we do this easily without querying length? */
|
||||||
|
guint64 length = find_element_get_length (data);
|
||||||
|
|
||||||
|
if (length == 0) {
|
||||||
|
buf = NULL;
|
||||||
|
} else {
|
||||||
|
buf = gst_buffer_store_get_buffer (entry->self->store, length + offset, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf) {
|
||||||
|
entry->buffers = g_list_prepend (entry->buffers, buf);
|
||||||
|
return GST_BUFFER_DATA (buf);
|
||||||
|
} else {
|
||||||
|
if (entry->requested_size == 0) {
|
||||||
|
GST_LOG_OBJECT (entry->self, "setting requested peek (%"G_GINT64_FORMAT", %u) on '%s'",
|
||||||
|
offset, size, GST_PLUGIN_FEATURE_NAME (entry->factory));
|
||||||
|
entry->requested_offset = offset;
|
||||||
|
entry->requested_size = size;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
find_suggest (gpointer data, guint probability, GstCaps *caps)
|
||||||
|
{
|
||||||
|
gchar *str;
|
||||||
|
TypeFindEntry *entry = (TypeFindEntry *) data;
|
||||||
|
|
||||||
|
str = gst_caps_to_string (caps);
|
||||||
|
GST_LOG_OBJECT (entry->self, "'%s' called suggest (%u, %s)",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), probability, str);
|
||||||
|
g_free (str);
|
||||||
|
if (((gint) probability) > entry->probability) {
|
||||||
|
entry->probability = probability;
|
||||||
|
gst_caps_replace (&entry->caps, caps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static gint
|
||||||
|
compare_type_find_entry (gconstpointer a, gconstpointer b)
|
||||||
|
{
|
||||||
|
TypeFindEntry *one = (TypeFindEntry *) a;
|
||||||
|
TypeFindEntry *two = (TypeFindEntry *) b;
|
||||||
|
|
||||||
|
if (one->probability == two->probability) {
|
||||||
|
/* FIXME: can be improved by analyzing requests */
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return two->probability - one->probability;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static gint
|
||||||
|
compare_type_find_factory (gconstpointer fac1, gconstpointer fac2)
|
||||||
|
{
|
||||||
|
return GST_PLUGIN_FEATURE (fac1)->rank - GST_PLUGIN_FEATURE (fac2)->rank;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_chain (GstPad *pad, GstData *data)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind;
|
||||||
|
GList *entries;
|
||||||
|
TypeFindEntry *entry;
|
||||||
|
GList *walk;
|
||||||
|
GstTypeFind find = {find_peek, find_suggest, NULL, find_element_get_length };
|
||||||
|
|
||||||
|
typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
|
||||||
|
if (GST_IS_EVENT (data)) {
|
||||||
|
gst_type_find_element_handle_event (pad, GST_EVENT (data));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (typefind->mode) {
|
||||||
|
case MODE_NORMAL:
|
||||||
|
gst_pad_push (typefind->src, data);
|
||||||
|
return;
|
||||||
|
case MODE_TYPEFIND: {
|
||||||
|
gst_buffer_store_add_buffer (typefind->store, GST_BUFFER (data));
|
||||||
|
gst_data_unref (data);
|
||||||
|
if (typefind->possibilities == NULL) {
|
||||||
|
/* not yet started, get all typefinding functions into our "queue" */
|
||||||
|
GList *all_factories = gst_type_find_factory_get_list ();
|
||||||
|
GST_INFO_OBJECT (typefind, "starting with %u typefinding functions",
|
||||||
|
g_list_length ((GList *) all_factories));
|
||||||
|
|
||||||
|
all_factories = g_list_sort (all_factories, compare_type_find_factory);
|
||||||
|
walk = all_factories;
|
||||||
|
while (all_factories) {
|
||||||
|
entry = g_new0 (TypeFindEntry, 1);
|
||||||
|
|
||||||
|
entry->factory = GST_TYPE_FIND_FACTORY (all_factories->data);
|
||||||
|
entry->self = typefind;
|
||||||
|
entry->probability = 0;
|
||||||
|
typefind->possibilities = g_list_prepend (typefind->possibilities, entry);
|
||||||
|
all_factories = g_list_next (all_factories);
|
||||||
|
}
|
||||||
|
g_list_free (all_factories);
|
||||||
|
}
|
||||||
|
/* call every typefind function once */
|
||||||
|
walk = entries = typefind->possibilities;
|
||||||
|
GST_INFO_OBJECT (typefind, "iterating %u typefinding functions", g_list_length (entries));
|
||||||
|
typefind->possibilities = NULL;
|
||||||
|
while (walk) {
|
||||||
|
find.data = entry = (TypeFindEntry *) walk->data;
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
entry->probability = 0;
|
||||||
|
entry->requested_offset = 0;
|
||||||
|
entry->requested_size = 0;
|
||||||
|
gst_type_find_factory_call_function (entry->factory, &find);
|
||||||
|
free_entry_buffers (entry);
|
||||||
|
if (entry->probability == 0 && entry->requested_size == 0) {
|
||||||
|
GST_DEBUG_OBJECT (typefind, "'%s' was removed - no chance of being the right plugin",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory));
|
||||||
|
free_entry (entry);
|
||||||
|
} else if (entry->probability >= typefind->max_probability) {
|
||||||
|
/* wooha, got caps */
|
||||||
|
GstCaps *found_caps = entry->caps;
|
||||||
|
guint probability = entry->probability;
|
||||||
|
|
||||||
|
gst_caps_ref (found_caps);
|
||||||
|
GST_INFO_OBJECT (typefind, "'%s' returned %u/%u probability, using it NOW",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), probability, typefind->max_probability);
|
||||||
|
while (walk) {
|
||||||
|
free_entry ((TypeFindEntry *) walk->data);
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
}
|
||||||
|
walk = typefind->possibilities;
|
||||||
|
while (walk) {
|
||||||
|
free_entry (walk->data);
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
}
|
||||||
|
typefind->possibilities = NULL;
|
||||||
|
g_list_free (typefind->possibilities);
|
||||||
|
g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0, probability, found_caps);
|
||||||
|
gst_caps_unref (found_caps);
|
||||||
|
} else {
|
||||||
|
typefind->possibilities = g_list_prepend (typefind->possibilities, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_list_free (entries);
|
||||||
|
/* we may now already have caps or we might be left without functions to try */
|
||||||
|
if (typefind->caps) {
|
||||||
|
stop_typefinding (typefind);
|
||||||
|
} else if (typefind->possibilities == NULL) {
|
||||||
|
gst_element_error (GST_ELEMENT (typefind), "media type could not be detected");
|
||||||
|
} else {
|
||||||
|
/* set up typefind element for next iteration */
|
||||||
|
typefind->possibilities = g_list_sort (typefind->possibilities, compare_type_find_entry);
|
||||||
|
|
||||||
|
walk = typefind->possibilities;
|
||||||
|
while (walk) {
|
||||||
|
entry = (TypeFindEntry *) walk->data;
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
if (entry->requested_size > 0) {
|
||||||
|
/* FIXME: need heuristic to find out if we should seek */
|
||||||
|
gint64 seek_offset;
|
||||||
|
GstEvent *event;
|
||||||
|
|
||||||
|
seek_offset = entry->requested_offset > 0 ? entry->requested_offset :
|
||||||
|
find_element_get_length (entry) + entry->requested_offset;
|
||||||
|
seek_offset += gst_buffer_store_get_size (typefind->store, seek_offset);
|
||||||
|
event = gst_event_new_seek (GST_FORMAT_BYTES | GST_SEEK_METHOD_SET, seek_offset);
|
||||||
|
if (gst_pad_send_event (GST_PAD_PEER (typefind->sink), event)) {
|
||||||
|
/* done seeking */
|
||||||
|
GST_DEBUG_OBJECT (typefind, "'%s' was reset - seeked to %"G_GINT64_FORMAT,
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), seek_offset);
|
||||||
|
break;
|
||||||
|
} else if (entry->requested_offset < 0) {
|
||||||
|
/* impossible to seek */
|
||||||
|
GST_DEBUG_OBJECT (typefind, "'%s' was reset - couldn't seek to %"G_GINT64_FORMAT,
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), seek_offset);
|
||||||
|
entry->requested_size = 0;
|
||||||
|
entry->requested_offset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* throw out all entries that can't get more data */
|
||||||
|
walk = g_list_next (typefind->possibilities);
|
||||||
|
while (walk) {
|
||||||
|
GList *cur = walk;
|
||||||
|
entry = (TypeFindEntry *) walk->data;
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
if (entry->requested_size == 0) {
|
||||||
|
GST_DEBUG_OBJECT (typefind, "'%s' was removed - higher possibilities available",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory));
|
||||||
|
free_entry (entry);
|
||||||
|
typefind->possibilities = g_list_delete_link (typefind->possibilities, cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (g_list_next (typefind->possibilities) == NULL) {
|
||||||
|
entry = (TypeFindEntry *) typefind->possibilities->data;
|
||||||
|
if (entry->probability > typefind->min_probability) {
|
||||||
|
GST_INFO_OBJECT (typefind, "'%s' is the only typefind left, using it now (probability %u)",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), entry->probability);
|
||||||
|
g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0, entry->probability, entry->caps);
|
||||||
|
free_entry (entry);
|
||||||
|
g_list_free (typefind->possibilities);
|
||||||
|
typefind->possibilities = NULL;
|
||||||
|
stop_typefinding (typefind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static GstElementStateReturn
|
||||||
|
gst_type_find_element_change_state (GstElement *element)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind;
|
||||||
|
|
||||||
|
typefind = GST_TYPE_FIND_ELEMENT (element);
|
||||||
|
|
||||||
|
switch (GST_STATE_TRANSITION (element)) {
|
||||||
|
case GST_STATE_READY_TO_PAUSED:
|
||||||
|
start_typefinding (typefind);
|
||||||
|
break;
|
||||||
|
case GST_STATE_PAUSED_TO_READY:
|
||||||
|
stop_typefinding (typefind);
|
||||||
|
gst_caps_replace (&typefind->caps, NULL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||||
|
}
|
78
gst/elements/gsttypefindelement.h
Normal file
78
gst/elements/gsttypefindelement.h
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
|
*
|
||||||
|
* gsttypefind.h: element that detects type of stream
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __GST_TYPE_FIND_ELEMENT_H__
|
||||||
|
#define __GST_TYPE_FIND_ELEMENT_H__
|
||||||
|
|
||||||
|
#include <gst/gstinfo.h>
|
||||||
|
#include <gst/gstelement.h>
|
||||||
|
/* #include <gst/gstbufferstore.h> */
|
||||||
|
#include "gstbufferstore.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_EXTERN(gst_type_find_element_debug);
|
||||||
|
|
||||||
|
extern GstElementDetails gst_type_find_element_details;
|
||||||
|
|
||||||
|
#define GST_TYPE_TYPE_FIND_ELEMENT (gst_type_find_element_get_type ())
|
||||||
|
#define GST_TYPE_FIND_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TYPE_FIND_ELEMENT, GstTypeFindElement))
|
||||||
|
#define GST_IS_TYPE_FIND_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TYPE_FIND_ELEMENT))
|
||||||
|
#define GST_TYPE_FIND_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_TYPE_FIND_ELEMENT, GstTypeFindElementClass))
|
||||||
|
#define GST_IS_TYPE_FIND_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_TYPE_FIND_ELEMENT))
|
||||||
|
#define GST_TYPE_FIND_ELEMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_TYPE_FIND_ELEMENT, GstTypeFindElementClass))
|
||||||
|
|
||||||
|
typedef struct _GstTypeFindElement GstTypeFindElement;
|
||||||
|
typedef struct _GstTypeFindElementClass GstTypeFindElementClass;
|
||||||
|
|
||||||
|
struct _GstTypeFindElement {
|
||||||
|
GstElement element;
|
||||||
|
|
||||||
|
GstPad * sink;
|
||||||
|
GstPad * src;
|
||||||
|
|
||||||
|
guint min_probability;
|
||||||
|
guint max_probability;
|
||||||
|
GstCaps * caps;
|
||||||
|
|
||||||
|
guint mode;
|
||||||
|
GstBufferStore * store;
|
||||||
|
guint64 stream_length;
|
||||||
|
gboolean stream_length_available;
|
||||||
|
|
||||||
|
GList * possibilities;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GstTypeFindElementClass {
|
||||||
|
GstElementClass parent_class;
|
||||||
|
|
||||||
|
/* signals */
|
||||||
|
void (*have_type) (GstTypeFindElement *element,
|
||||||
|
guint probability,
|
||||||
|
GstCaps * caps);
|
||||||
|
};
|
||||||
|
|
||||||
|
GType gst_type_find_element_get_type (void);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __GST_TYPE_FIND_ELEMENT_H__ */
|
|
@ -27,9 +27,6 @@
|
||||||
|
|
||||||
#include "gst.h"
|
#include "gst.h"
|
||||||
#include "gstqueue.h"
|
#include "gstqueue.h"
|
||||||
#ifndef GST_DISABLE_TYPEFIND
|
|
||||||
#include "gsttypefind.h"
|
|
||||||
#endif /* GST_DISABLE_TYPEFIND */
|
|
||||||
#ifndef GST_DISABLE_REGISTRY
|
#ifndef GST_DISABLE_REGISTRY
|
||||||
#include "registries/gstxmlregistry.h"
|
#include "registries/gstxmlregistry.h"
|
||||||
#endif /* GST_DISABLE_REGISTRY */
|
#endif /* GST_DISABLE_REGISTRY */
|
||||||
|
@ -461,10 +458,6 @@ gst_register_core_elements (GModule *module, GstPlugin *plugin)
|
||||||
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
|
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
|
||||||
factory = gst_element_factory_new ("queue", gst_queue_get_type (), &gst_queue_details);
|
factory = gst_element_factory_new ("queue", gst_queue_get_type (), &gst_queue_details);
|
||||||
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
|
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
|
||||||
#ifndef GST_DISABLE_TYPEFIND
|
|
||||||
factory = gst_element_factory_new ("typefind", gst_type_find_get_type (), &gst_type_find_details);
|
|
||||||
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
|
|
||||||
#endif /* GST_DISABLE_TYPEFIND */
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -510,8 +503,8 @@ init_post (void)
|
||||||
gst_ghost_pad_get_type ();
|
gst_ghost_pad_get_type ();
|
||||||
gst_element_factory_get_type ();
|
gst_element_factory_get_type ();
|
||||||
gst_element_get_type ();
|
gst_element_get_type ();
|
||||||
gst_type_factory_get_type ();
|
|
||||||
gst_scheduler_factory_get_type ();
|
gst_scheduler_factory_get_type ();
|
||||||
|
gst_type_find_factory_get_type ();
|
||||||
gst_bin_get_type ();
|
gst_bin_get_type ();
|
||||||
#ifndef GST_DISABLE_AUTOPLUG
|
#ifndef GST_DISABLE_AUTOPLUG
|
||||||
gst_autoplug_factory_get_type ();
|
gst_autoplug_factory_get_type ();
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
#include <gst/gstindex.h>
|
#include <gst/gstindex.h>
|
||||||
#include <gst/gstpipeline.h>
|
#include <gst/gstpipeline.h>
|
||||||
#include <gst/gstthread.h>
|
#include <gst/gstthread.h>
|
||||||
#include <gst/gsttype.h>
|
#include <gst/gsttypefind.h>
|
||||||
#include <gst/gstautoplug.h>
|
#include <gst/gstautoplug.h>
|
||||||
#include <gst/gstcaps.h>
|
#include <gst/gstcaps.h>
|
||||||
#include <gst/gstprops.h>
|
#include <gst/gstprops.h>
|
||||||
|
|
|
@ -78,7 +78,6 @@ extern GstDebugCategory *GST_CAT_PLUGIN_LOADING;
|
||||||
extern GstDebugCategory *GST_CAT_PLUGIN_INFO;
|
extern GstDebugCategory *GST_CAT_PLUGIN_INFO;
|
||||||
extern GstDebugCategory *GST_CAT_PROPERTIES;
|
extern GstDebugCategory *GST_CAT_PROPERTIES;
|
||||||
extern GstDebugCategory *GST_CAT_THREAD;
|
extern GstDebugCategory *GST_CAT_THREAD;
|
||||||
extern GstDebugCategory *GST_CAT_TYPES;
|
|
||||||
extern GstDebugCategory *GST_CAT_XML;
|
extern GstDebugCategory *GST_CAT_XML;
|
||||||
extern GstDebugCategory *GST_CAT_NEGOTIATION;
|
extern GstDebugCategory *GST_CAT_NEGOTIATION;
|
||||||
extern GstDebugCategory *GST_CAT_REFCOUNTING;
|
extern GstDebugCategory *GST_CAT_REFCOUNTING;
|
||||||
|
|
|
@ -301,8 +301,6 @@ gst_buffer_create_sub (GstBuffer *parent, guint offset, guint size)
|
||||||
}
|
}
|
||||||
/* ref the real parent */
|
/* ref the real parent */
|
||||||
gst_data_ref (GST_DATA (parent));
|
gst_data_ref (GST_DATA (parent));
|
||||||
/* make sure nobody overwrites data in the parent */
|
|
||||||
GST_DATA_FLAG_SET (parent, GST_DATA_READONLY);
|
|
||||||
|
|
||||||
/* create the new buffer */
|
/* create the new buffer */
|
||||||
buffer = gst_mem_chunk_alloc (chunk);
|
buffer = gst_mem_chunk_alloc (chunk);
|
||||||
|
@ -337,9 +335,12 @@ gst_buffer_create_sub (GstBuffer *parent, guint offset, guint size)
|
||||||
GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE;
|
GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE;
|
||||||
GST_BUFFER_OFFSET (buffer) = GST_BUFFER_OFFSET_NONE;
|
GST_BUFFER_OFFSET (buffer) = GST_BUFFER_OFFSET_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
|
GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
|
/* make sure nobody overwrites data as it would overwrite in the parent.
|
||||||
|
* data in parent cannot be overwritten because we hold a ref */
|
||||||
|
GST_DATA_FLAG_SET (parent, GST_DATA_READONLY);
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
#include "gst_private.h"
|
#include "gst_private.h"
|
||||||
|
|
||||||
#include "gstcaps.h"
|
#include "gstcaps.h"
|
||||||
#include "gsttype.h"
|
|
||||||
#include "gstmemchunk.h"
|
#include "gstmemchunk.h"
|
||||||
#include "gstinfo.h"
|
#include "gstinfo.h"
|
||||||
|
|
||||||
|
@ -192,30 +191,6 @@ gst_caps_get_type (void)
|
||||||
{
|
{
|
||||||
return _gst_caps_type;
|
return _gst_caps_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
static guint16
|
|
||||||
get_type_for_mime (const gchar *mime)
|
|
||||||
{
|
|
||||||
guint16 typeid;
|
|
||||||
|
|
||||||
typeid = gst_type_find_by_mime (mime);
|
|
||||||
if (typeid == 0) {
|
|
||||||
GstTypeDefinition definition;
|
|
||||||
GstTypeFactory *factory;
|
|
||||||
|
|
||||||
definition.name = "capstype";
|
|
||||||
definition.mime = g_strdup (mime);
|
|
||||||
definition.exts = NULL;
|
|
||||||
definition.typefindfunc = NULL;
|
|
||||||
|
|
||||||
factory = gst_type_factory_new (&definition);
|
|
||||||
typeid = gst_type_register (factory);
|
|
||||||
|
|
||||||
g_free (definition.mime);
|
|
||||||
}
|
|
||||||
return typeid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_caps_new:
|
* gst_caps_new:
|
||||||
* @name: the name of this capability
|
* @name: the name of this capability
|
||||||
|
@ -231,9 +206,8 @@ gst_caps_new (const gchar *name, const gchar *mime, GstProps *props)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (mime != NULL, NULL);
|
g_return_val_if_fail (mime != NULL, NULL);
|
||||||
|
|
||||||
return gst_caps_new_id (name, get_type_for_mime (mime), props);
|
return gst_caps_new_id (name, g_quark_from_string (mime), props);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_caps_new_id:
|
* gst_caps_new_id:
|
||||||
* @name: the name of this capability
|
* @name: the name of this capability
|
||||||
|
@ -245,7 +219,7 @@ gst_caps_new (const gchar *name, const gchar *mime, GstProps *props)
|
||||||
* Returns: a new capability
|
* Returns: a new capability
|
||||||
*/
|
*/
|
||||||
GstCaps*
|
GstCaps*
|
||||||
gst_caps_new_id (const gchar *name, const guint16 id, GstProps *props)
|
gst_caps_new_id (const gchar *name, const GQuark id, GstProps *props)
|
||||||
{
|
{
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
|
|
||||||
|
@ -584,7 +558,6 @@ gst_caps_set_name (GstCaps *caps, const gchar *name)
|
||||||
g_free (caps->name);
|
g_free (caps->name);
|
||||||
caps->name = g_strdup (name);
|
caps->name = g_strdup (name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_caps_get_mime:
|
* gst_caps_get_mime:
|
||||||
* @caps: the caps to get the mime type from
|
* @caps: the caps to get the mime type from
|
||||||
|
@ -596,18 +569,10 @@ gst_caps_set_name (GstCaps *caps, const gchar *name)
|
||||||
const gchar*
|
const gchar*
|
||||||
gst_caps_get_mime (GstCaps *caps)
|
gst_caps_get_mime (GstCaps *caps)
|
||||||
{
|
{
|
||||||
GstType *type;
|
|
||||||
|
|
||||||
g_return_val_if_fail (caps != NULL, NULL);
|
g_return_val_if_fail (caps != NULL, NULL);
|
||||||
|
|
||||||
type = gst_type_find_by_id (caps->id);
|
return g_quark_to_string (caps->id);
|
||||||
|
|
||||||
if (type)
|
|
||||||
return type->mime;
|
|
||||||
else
|
|
||||||
return "unknown/unknown";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_caps_set_mime:
|
* gst_caps_set_mime:
|
||||||
* @caps: the caps to set the mime type to
|
* @caps: the caps to set the mime type to
|
||||||
|
@ -621,40 +586,8 @@ gst_caps_set_mime (GstCaps *caps, const gchar *mime)
|
||||||
g_return_if_fail (caps != NULL);
|
g_return_if_fail (caps != NULL);
|
||||||
g_return_if_fail (mime != NULL);
|
g_return_if_fail (mime != NULL);
|
||||||
|
|
||||||
caps->id = get_type_for_mime (mime);
|
caps->id = g_quark_from_string (mime);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_caps_get_type_id:
|
|
||||||
* @caps: the caps to get the type id from
|
|
||||||
*
|
|
||||||
* Get the type id of the caps.
|
|
||||||
*
|
|
||||||
* Returns: the type id of the caps
|
|
||||||
*/
|
|
||||||
guint16
|
|
||||||
gst_caps_get_type_id (GstCaps *caps)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (caps != NULL, 0);
|
|
||||||
|
|
||||||
return caps->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_caps_set_type_id:
|
|
||||||
* @caps: the caps to set the type id to
|
|
||||||
* @type_id: the type id to set
|
|
||||||
*
|
|
||||||
* Set the type id of the caps.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
gst_caps_set_type_id (GstCaps *caps, guint16 type_id)
|
|
||||||
{
|
|
||||||
g_return_if_fail (caps != NULL);
|
|
||||||
|
|
||||||
caps->id = type_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_caps_set_props:
|
* gst_caps_set_props:
|
||||||
* @caps: the caps to attach the properties to
|
* @caps: the caps to attach the properties to
|
||||||
|
@ -880,8 +813,8 @@ gst_caps_check_compatibility_func (GstCaps *fromcaps, GstCaps *tocaps)
|
||||||
{
|
{
|
||||||
if (fromcaps->id != tocaps->id) {
|
if (fromcaps->id != tocaps->id) {
|
||||||
GST_CAT_DEBUG (GST_CAT_CAPS,"mime types differ (%s to %s)",
|
GST_CAT_DEBUG (GST_CAT_CAPS,"mime types differ (%s to %s)",
|
||||||
gst_type_find_by_id (fromcaps->id)->mime,
|
gst_caps_get_mime (fromcaps),
|
||||||
gst_type_find_by_id (tocaps->id)->mime);
|
gst_caps_get_mime (tocaps));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -963,8 +896,8 @@ gst_caps_intersect_func (GstCaps *caps1, GstCaps *caps2)
|
||||||
|
|
||||||
if (caps1->id != caps2->id) {
|
if (caps1->id != caps2->id) {
|
||||||
GST_CAT_DEBUG (GST_CAT_CAPS, "mime types differ (%s to %s)",
|
GST_CAT_DEBUG (GST_CAT_CAPS, "mime types differ (%s to %s)",
|
||||||
gst_type_find_by_id (caps1->id)->mime,
|
gst_caps_get_mime (caps1),
|
||||||
gst_type_find_by_id (caps2->id)->mime);
|
gst_caps_get_mime (caps2));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1127,7 +1060,7 @@ gst_caps_save_thyself (GstCaps *caps, xmlNodePtr parent)
|
||||||
subtree = xmlNewChild (parent, NULL, "capscomp", NULL);
|
subtree = xmlNewChild (parent, NULL, "capscomp", NULL);
|
||||||
|
|
||||||
xmlNewChild (subtree, NULL, "name", caps->name);
|
xmlNewChild (subtree, NULL, "name", caps->name);
|
||||||
xmlNewChild (subtree, NULL, "type", gst_type_find_by_id (caps->id)->mime);
|
xmlNewChild (subtree, NULL, "type", gst_caps_get_mime (caps));
|
||||||
if (caps->properties) {
|
if (caps->properties) {
|
||||||
subsubtree = xmlNewChild (subtree, NULL, "properties", NULL);
|
subsubtree = xmlNewChild (subtree, NULL, "properties", NULL);
|
||||||
|
|
||||||
|
@ -1175,7 +1108,7 @@ gst_caps_load_thyself (xmlNodePtr parent)
|
||||||
}
|
}
|
||||||
if (!strcmp (subfield->name, "type")) {
|
if (!strcmp (subfield->name, "type")) {
|
||||||
content = xmlNodeGetContent (subfield);
|
content = xmlNodeGetContent (subfield);
|
||||||
caps->id = get_type_for_mime (content);
|
caps->id = g_quark_from_string (content);
|
||||||
g_free (content);
|
g_free (content);
|
||||||
}
|
}
|
||||||
else if (!strcmp (subfield->name, "properties")) {
|
else if (!strcmp (subfield->name, "properties")) {
|
||||||
|
|
|
@ -63,7 +63,7 @@ typedef enum {
|
||||||
struct _GstCaps {
|
struct _GstCaps {
|
||||||
/* --- public --- */
|
/* --- public --- */
|
||||||
gchar *name; /* the name of this caps */
|
gchar *name; /* the name of this caps */
|
||||||
guint16 id; /* type id (major type) representing
|
GQuark id; /* type id (major type) representing
|
||||||
the mime type, it's stored as a GQuark
|
the mime type, it's stored as a GQuark
|
||||||
for speed/space reasons */
|
for speed/space reasons */
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ void _gst_caps_initialize (void);
|
||||||
/* creating new caps */
|
/* creating new caps */
|
||||||
GType gst_caps_get_type (void);
|
GType gst_caps_get_type (void);
|
||||||
GstCaps* gst_caps_new (const gchar *name, const gchar *mime, GstProps *props);
|
GstCaps* gst_caps_new (const gchar *name, const gchar *mime, GstProps *props);
|
||||||
GstCaps* gst_caps_new_id (const gchar *name, const guint16 id, GstProps *props);
|
GstCaps* gst_caps_new_id (const gchar *name, const GQuark id, GstProps *props);
|
||||||
GstCaps* gst_caps_get_any (void);
|
GstCaps* gst_caps_get_any (void);
|
||||||
/* replace pointer to caps, doing proper refcounting */
|
/* replace pointer to caps, doing proper refcounting */
|
||||||
void gst_caps_replace (GstCaps **oldcaps, GstCaps *newcaps);
|
void gst_caps_replace (GstCaps **oldcaps, GstCaps *newcaps);
|
||||||
|
@ -151,9 +151,6 @@ void gst_caps_set_name (GstCaps *caps, const gchar *name);
|
||||||
const gchar* gst_caps_get_mime (GstCaps *caps);
|
const gchar* gst_caps_get_mime (GstCaps *caps);
|
||||||
void gst_caps_set_mime (GstCaps *caps, const gchar *mime);
|
void gst_caps_set_mime (GstCaps *caps, const gchar *mime);
|
||||||
|
|
||||||
guint16 gst_caps_get_type_id (GstCaps *caps);
|
|
||||||
void gst_caps_set_type_id (GstCaps *caps, guint16 type_id);
|
|
||||||
|
|
||||||
GstCaps* gst_caps_set_props (GstCaps *caps, GstProps *props);
|
GstCaps* gst_caps_set_props (GstCaps *caps, GstProps *props);
|
||||||
GstProps* gst_caps_get_props (GstCaps *caps);
|
GstProps* gst_caps_get_props (GstCaps *caps);
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#define GST_DISABLE_LOADSAVE_REGISTRY 1
|
#define GST_DISABLE_LOADSAVE_REGISTRY 1
|
||||||
#define GST_DISABLE_GST_DEBUG 1
|
#define GST_DISABLE_GST_DEBUG 1
|
||||||
#define GST_DISABLE_LOADSAVE 1
|
#define GST_DISABLE_LOADSAVE 1
|
||||||
#define GST_DISABLE_TYPEFIND 1
|
|
||||||
#define GST_DISABLE_AUTOPLUG 1
|
#define GST_DISABLE_AUTOPLUG 1
|
||||||
#define GST_DISABLE_PARSE 1
|
#define GST_DISABLE_PARSE 1
|
||||||
#define GST_DISABLE_TRACE 1
|
#define GST_DISABLE_TRACE 1
|
||||||
|
@ -31,9 +30,6 @@
|
||||||
/* DOES NOT WORK */
|
/* DOES NOT WORK */
|
||||||
@GST_DISABLE_LOADSAVE_DEFINE@
|
@GST_DISABLE_LOADSAVE_DEFINE@
|
||||||
|
|
||||||
/* DOES NOT WORK */
|
|
||||||
@GST_DISABLE_TYPEFIND_DEFINE@
|
|
||||||
|
|
||||||
/* DOES NOT WORK */
|
/* DOES NOT WORK */
|
||||||
@GST_DISABLE_AUTOPLUG_DEFINE@
|
@GST_DISABLE_AUTOPLUG_DEFINE@
|
||||||
|
|
||||||
|
|
|
@ -2545,7 +2545,7 @@ gst_element_dispose (GObject *object)
|
||||||
GList *pads;
|
GList *pads;
|
||||||
GstPad *pad;
|
GstPad *pad;
|
||||||
|
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, element, "dispose");
|
GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "dispose");
|
||||||
|
|
||||||
gst_element_set_state (element, GST_STATE_NULL);
|
gst_element_set_state (element, GST_STATE_NULL);
|
||||||
|
|
||||||
|
|
|
@ -9,4 +9,6 @@ VOID:OBJECT,POINTER
|
||||||
VOID:OBJECT,STRING
|
VOID:OBJECT,STRING
|
||||||
VOID:INT,INT
|
VOID:INT,INT
|
||||||
VOID:INT64
|
VOID:INT64
|
||||||
|
VOID:UINT,BOXED
|
||||||
BOOLEAN:VOID
|
BOOLEAN:VOID
|
||||||
|
BOOLEAN:POINTER
|
||||||
|
|
12
gst/gstpad.c
12
gst/gstpad.c
|
@ -25,7 +25,6 @@
|
||||||
#include "gstpad.h"
|
#include "gstpad.h"
|
||||||
#include "gstutils.h"
|
#include "gstutils.h"
|
||||||
#include "gstelement.h"
|
#include "gstelement.h"
|
||||||
#include "gsttype.h"
|
|
||||||
#include "gstbin.h"
|
#include "gstbin.h"
|
||||||
#include "gstscheduler.h"
|
#include "gstscheduler.h"
|
||||||
#include "gstevent.h"
|
#include "gstevent.h"
|
||||||
|
@ -2311,14 +2310,19 @@ gst_pad_push (GstPad *pad, GstData *data)
|
||||||
{
|
{
|
||||||
GstRealPad *peer;
|
GstRealPad *peer;
|
||||||
|
|
||||||
g_assert (GST_IS_PAD (pad));
|
g_return_if_fail (GST_IS_PAD (pad));
|
||||||
GST_CAT_LOG_OBJECT (GST_CAT_DATAFLOW, pad, "pushing");
|
|
||||||
|
|
||||||
g_return_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SRC);
|
g_return_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SRC);
|
||||||
|
|
||||||
if (!gst_probe_dispatcher_dispatch (&(GST_REAL_PAD (pad)->probedisp), &data))
|
if (!gst_probe_dispatcher_dispatch (&(GST_REAL_PAD (pad)->probedisp), &data))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!GST_PAD_IS_LINKED (pad)) {
|
||||||
|
GST_CAT_LOG_OBJECT (GST_CAT_DATAFLOW, pad, "not pushing data %p as pad is unconnected", data);
|
||||||
|
gst_data_unref (data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_CAT_LOG_OBJECT (GST_CAT_DATAFLOW, pad, "pushing");
|
||||||
peer = GST_RPAD_PEER (pad);
|
peer = GST_RPAD_PEER (pad);
|
||||||
|
|
||||||
if (!peer) {
|
if (!peer) {
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
#include "gstregistry.h"
|
#include "gstregistry.h"
|
||||||
#include "gstinfo.h"
|
#include "gstinfo.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
static void gst_plugin_feature_class_init (GstPluginFeatureClass *klass);
|
static void gst_plugin_feature_class_init (GstPluginFeatureClass *klass);
|
||||||
static void gst_plugin_feature_init (GstPluginFeature *feature);
|
static void gst_plugin_feature_init (GstPluginFeature *feature);
|
||||||
|
|
||||||
|
@ -136,7 +138,6 @@ gst_plugin_feature_type_name_filter (GstPluginFeature *feature,
|
||||||
return ((data->type == 0 || data->type == G_OBJECT_TYPE (feature)) &&
|
return ((data->type == 0 || data->type == G_OBJECT_TYPE (feature)) &&
|
||||||
(data->name == NULL || !strcmp (data->name, GST_PLUGIN_FEATURE_NAME (feature))));
|
(data->name == NULL || !strcmp (data->name, GST_PLUGIN_FEATURE_NAME (feature))));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_plugin_feature_set_rank:
|
* gst_plugin_feature_set_rank:
|
||||||
* @feature: feature to rank
|
* @feature: feature to rank
|
||||||
|
@ -153,4 +154,25 @@ gst_plugin_feature_set_rank (GstPluginFeature *feature, guint16 rank)
|
||||||
|
|
||||||
feature->rank = rank;
|
feature->rank = rank;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* gst_plugin_feature_set_rank:
|
||||||
|
* @feature: a feature
|
||||||
|
* @name: the name to set
|
||||||
|
*
|
||||||
|
* Sets the name of a plugin feature. The name uniquely identifies a feature
|
||||||
|
* within all features of the same type. Renaming a plugin feature is not
|
||||||
|
* allowed.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_plugin_feature_set_name (GstPluginFeature *feature, const gchar *name)
|
||||||
|
{
|
||||||
|
g_return_if_fail (GST_IS_PLUGIN_FEATURE (feature));
|
||||||
|
g_return_if_fail (name != NULL);
|
||||||
|
|
||||||
|
if (feature->name) {
|
||||||
|
g_return_if_fail (strcmp (feature->name, name) == 0);
|
||||||
|
} else {
|
||||||
|
feature->name = g_strdup (name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,7 @@ gboolean gst_plugin_feature_type_name_filter (GstPluginFeature *feature,
|
||||||
GstTypeNameData *data);
|
GstTypeNameData *data);
|
||||||
|
|
||||||
void gst_plugin_feature_set_rank (GstPluginFeature *feature, guint16 rank);
|
void gst_plugin_feature_set_rank (GstPluginFeature *feature, guint16 rank);
|
||||||
|
void gst_plugin_feature_set_name (GstPluginFeature *feature, const gchar *name);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
/* GStreamer
|
/* GStreamer
|
||||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
* 2000 Wim Taymans <wtay@chello.be>
|
|
||||||
*
|
*
|
||||||
* gsttypefind.c:
|
* gsttypefind.h: typefinding subsystem
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Library General Public
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
@ -20,234 +19,291 @@
|
||||||
* Boston, MA 02111-1307, USA.
|
* Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "gst_private.h"
|
|
||||||
#include "gsttype.h"
|
|
||||||
#include "gstinfo.h"
|
#include "gstinfo.h"
|
||||||
#include "gsttypefind.h"
|
#include "gsttypefind.h"
|
||||||
|
#include "gstregistrypool.h"
|
||||||
|
|
||||||
GstElementDetails gst_type_find_details = {
|
GST_DEBUG_CATEGORY_STATIC (gst_type_find_debug);
|
||||||
"TypeFind",
|
#define GST_CAT_DEFAULT gst_type_find_debug
|
||||||
"Generic",
|
|
||||||
"LGPL",
|
|
||||||
"Finds the media type of a stream",
|
|
||||||
VERSION,
|
|
||||||
"Erik Walthinsen <omega@cse.ogi.edu>,"
|
|
||||||
"Wim Taymans <wim.taymans@chello.be>",
|
|
||||||
"(C) 1999",
|
|
||||||
};
|
|
||||||
|
|
||||||
/* generic templates */
|
static void gst_type_find_factory_class_init (gpointer g_class,
|
||||||
GST_PAD_TEMPLATE_FACTORY (type_find_sink_factory,
|
gpointer class_data);
|
||||||
"sink",
|
static void gst_type_find_factory_init (GTypeInstance * instance,
|
||||||
GST_PAD_SINK,
|
gpointer g_class);
|
||||||
GST_PAD_ALWAYS,
|
static void gst_type_find_factory_dispose (GObject * object);
|
||||||
NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
/* TypeFind signals and args */
|
static void gst_type_find_factory_unload_thyself (GstPluginFeature * feature);
|
||||||
enum {
|
|
||||||
HAVE_TYPE,
|
|
||||||
LAST_SIGNAL
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
static void gst_type_find_load_plugin (GstTypeFind * find,
|
||||||
ARG_0,
|
gpointer data);
|
||||||
ARG_CAPS,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
static GstPluginFeatureClass *parent_class = NULL;
|
||||||
static void gst_type_find_class_init (GstTypeFindClass *klass);
|
|
||||||
static void gst_type_find_init (GstTypeFind *typefind);
|
|
||||||
|
|
||||||
static void gst_type_find_set_property (GObject *object, guint prop_id,
|
|
||||||
const GValue *value,
|
|
||||||
GParamSpec *pspec);
|
|
||||||
static void gst_type_find_get_property (GObject *object, guint prop_id,
|
|
||||||
GValue *value,
|
|
||||||
GParamSpec *pspec);
|
|
||||||
|
|
||||||
static void gst_type_find_loopfunc (GstElement *element);
|
|
||||||
static GstElementStateReturn
|
|
||||||
gst_type_find_change_state (GstElement *element);
|
|
||||||
|
|
||||||
static GstElementClass *parent_class = NULL;
|
|
||||||
static guint gst_type_find_signals[LAST_SIGNAL] = { 0 };
|
|
||||||
|
|
||||||
GType
|
GType
|
||||||
gst_type_find_get_type (void)
|
gst_type_find_factory_get_type (void)
|
||||||
{
|
{
|
||||||
static GType typefind_type = 0;
|
static GType typefind_type = 0;
|
||||||
|
|
||||||
if (!typefind_type) {
|
if (!typefind_type) {
|
||||||
static const GTypeInfo typefind_info = {
|
static const GTypeInfo typefind_info = {
|
||||||
sizeof(GstTypeFindClass),
|
sizeof (GstTypeFindFactoryClass),
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
(GClassInitFunc)gst_type_find_class_init,
|
gst_type_find_factory_class_init,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
sizeof(GstTypeFind),
|
sizeof (GstTypeFindFactory),
|
||||||
0,
|
0,
|
||||||
(GInstanceInitFunc)gst_type_find_init,
|
gst_type_find_factory_init,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
typefind_type = g_type_register_static (GST_TYPE_ELEMENT,
|
typefind_type = g_type_register_static (GST_TYPE_PLUGIN_FEATURE,
|
||||||
"GstTypeFind",
|
"GstTypeFindFactory",
|
||||||
&typefind_info, 0);
|
&typefind_info, 0);
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_type_find_debug, "GST_TYPEFIND",
|
||||||
|
GST_DEBUG_FG_GREEN, "typefinding subsystem");
|
||||||
}
|
}
|
||||||
|
|
||||||
return typefind_type;
|
return typefind_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_type_find_class_init (GstTypeFindClass *klass)
|
gst_type_find_factory_class_init (gpointer g_class, gpointer class_data)
|
||||||
{
|
{
|
||||||
GObjectClass *gobject_class;
|
GstPluginFeatureClass *gstpluginfeature_class = GST_PLUGIN_FEATURE_CLASS (g_class);
|
||||||
GstElementClass *gstelement_class;
|
GObjectClass *object_class = G_OBJECT_CLASS (g_class);
|
||||||
|
|
||||||
gobject_class = (GObjectClass*)klass;
|
parent_class = g_type_class_peek_parent (g_class);
|
||||||
gstelement_class = (GstElementClass*)klass;
|
|
||||||
|
object_class->dispose = gst_type_find_factory_dispose;
|
||||||
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
|
||||||
|
gstpluginfeature_class->unload_thyself = GST_DEBUG_FUNCPTR (gst_type_find_factory_unload_thyself);
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_CAPS,
|
|
||||||
g_param_spec_pointer ("caps", "Caps", "Found capabilities", G_PARAM_READABLE));
|
|
||||||
|
|
||||||
gst_type_find_signals[HAVE_TYPE] =
|
|
||||||
g_signal_new ("have_type", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
|
|
||||||
G_STRUCT_OFFSET (GstTypeFindClass, have_type), NULL, NULL,
|
|
||||||
g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
|
|
||||||
G_TYPE_POINTER);
|
|
||||||
|
|
||||||
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_type_find_set_property);
|
|
||||||
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_type_find_get_property);
|
|
||||||
|
|
||||||
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_type_find_change_state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_type_find_init (GstTypeFind *typefind)
|
gst_type_find_factory_init (GTypeInstance *instance, gpointer g_class)
|
||||||
{
|
{
|
||||||
typefind->sinkpad = gst_pad_new_from_template (
|
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (instance);
|
||||||
GST_PAD_TEMPLATE_GET (type_find_sink_factory), "sink");
|
|
||||||
gst_element_add_pad (GST_ELEMENT (typefind), typefind->sinkpad);
|
|
||||||
|
|
||||||
gst_element_set_loop_function (GST_ELEMENT (typefind),
|
factory->user_data = factory;
|
||||||
gst_type_find_loopfunc);
|
factory->function = gst_type_find_load_plugin;
|
||||||
|
|
||||||
typefind->caps = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_type_find_set_property (GObject *object, guint prop_id,
|
gst_type_find_factory_dispose (GObject *object)
|
||||||
const GValue *value, GParamSpec *pspec)
|
|
||||||
{
|
{
|
||||||
GstTypeFind *typefind;
|
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (object);
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_TYPE_FIND (object));
|
if (factory->caps) {
|
||||||
|
gst_caps_unref (factory->caps);
|
||||||
typefind = GST_TYPE_FIND (object);
|
factory->caps = NULL;
|
||||||
|
}
|
||||||
switch (prop_id) {
|
if (factory->extensions) {
|
||||||
default:
|
g_strfreev (factory->extensions);
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
factory->extensions = NULL;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_type_find_get_property (GObject *object, guint prop_id,
|
gst_type_find_factory_unload_thyself (GstPluginFeature *feature)
|
||||||
GValue *value, GParamSpec *pspec)
|
|
||||||
{
|
{
|
||||||
GstTypeFind *typefind;
|
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (feature);
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_TYPE_FIND (object));
|
factory->function = gst_type_find_load_plugin;
|
||||||
|
factory->user_data = factory;
|
||||||
typefind = GST_TYPE_FIND (object);
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
case ARG_CAPS:
|
|
||||||
g_value_set_pointer (value, typefind->caps);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_type_find_loopfunc (GstElement *element)
|
gst_type_find_load_plugin (GstTypeFind *find, gpointer data)
|
||||||
{
|
{
|
||||||
GstTypeFind *typefind;
|
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (data);
|
||||||
const GList *type_list;
|
|
||||||
GstType *type;
|
|
||||||
|
|
||||||
typefind = GST_TYPE_FIND (element);
|
GST_DEBUG_OBJECT (factory, "need to load typefind function %s", GST_PLUGIN_FEATURE_NAME (factory));
|
||||||
|
|
||||||
GST_DEBUG ("Started typefinding loop in '%s'",
|
if (gst_plugin_feature_ensure_loaded (GST_PLUGIN_FEATURE (factory))) {
|
||||||
GST_OBJECT_NAME (typefind));
|
if (factory->function == gst_type_find_load_plugin) {
|
||||||
|
/* looks like we didn't get a real typefind function */
|
||||||
type_list = gst_type_get_list ();
|
g_warning ("could not load valid typefind function for feature '%s'\n", GST_PLUGIN_FEATURE_NAME (factory));
|
||||||
|
} else {
|
||||||
while (type_list) {
|
g_assert (factory->function);
|
||||||
GSList *factories;
|
gst_type_find_factory_call_function (factory, find);
|
||||||
type = (GstType *) type_list->data;
|
|
||||||
|
|
||||||
factories = type->factories;
|
|
||||||
|
|
||||||
while (factories) {
|
|
||||||
GstTypeFactory *factory = GST_TYPE_FACTORY (factories->data);
|
|
||||||
GstTypeFindFunc typefindfunc = (GstTypeFindFunc) factory->typefindfunc;
|
|
||||||
GstCaps *caps;
|
|
||||||
|
|
||||||
GST_CAT_DEBUG (GST_CAT_TYPES, "try type (%p) :%d \"%s\" %p",
|
|
||||||
factory, type->id, type->mime, typefindfunc);
|
|
||||||
if (typefindfunc && (caps = typefindfunc (typefind->bs, factory))) {
|
|
||||||
GST_CAT_DEBUG (GST_CAT_TYPES, "found type: %d \"%s\" \"%s\"",
|
|
||||||
caps->id, type->mime, gst_caps_get_name (caps));
|
|
||||||
gst_caps_replace (&typefind->caps, caps);
|
|
||||||
|
|
||||||
if (gst_pad_try_set_caps (typefind->sinkpad, caps) <= 0) {
|
|
||||||
g_warning ("typefind: found type but peer didn't accept it");
|
|
||||||
}
|
|
||||||
|
|
||||||
gst_object_ref (GST_OBJECT (typefind));
|
|
||||||
g_signal_emit (G_OBJECT (typefind), gst_type_find_signals[HAVE_TYPE],
|
|
||||||
0, typefind->caps);
|
|
||||||
gst_object_unref (GST_OBJECT (typefind));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
factories = g_slist_next (factories);
|
|
||||||
}
|
}
|
||||||
type_list = g_list_next (type_list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if we get here, nothing worked... :'(. */
|
|
||||||
gst_element_error (GST_ELEMENT (typefind),
|
|
||||||
"media type could not be detected");
|
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
static GstElementStateReturn
|
* gst_type_find_factory_get_list:
|
||||||
gst_type_find_change_state (GstElement *element)
|
*
|
||||||
|
* Gets the list of all registered typefind factories. You must free the
|
||||||
|
* list using g_list_free.
|
||||||
|
*
|
||||||
|
* Returns: the list of all registered typefind factories
|
||||||
|
*/
|
||||||
|
GList *
|
||||||
|
gst_type_find_factory_get_list (void)
|
||||||
{
|
{
|
||||||
GstTypeFind *typefind;
|
return gst_registry_pool_feature_list (GST_TYPE_TYPE_FIND_FACTORY);
|
||||||
GstElementStateReturn ret;
|
|
||||||
|
|
||||||
typefind = GST_TYPE_FIND (element);
|
|
||||||
|
|
||||||
switch (GST_STATE_TRANSITION (element)) {
|
|
||||||
case GST_STATE_READY_TO_PAUSED:
|
|
||||||
typefind->bs = gst_bytestream_new (typefind->sinkpad);
|
|
||||||
break;
|
|
||||||
case GST_STATE_PAUSED_TO_READY:
|
|
||||||
gst_bytestream_destroy (typefind->bs);
|
|
||||||
gst_caps_replace (&typefind->caps, NULL);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* gst_type_find_factory_get_caps:
|
||||||
|
* @factory: a factory
|
||||||
|
*
|
||||||
|
* Gets the caps associated with a typefind factory.
|
||||||
|
*
|
||||||
|
* Returns: the #GstCaps associated with this factory
|
||||||
|
*/
|
||||||
|
GstCaps *
|
||||||
|
gst_type_find_factory_get_caps (const GstTypeFindFactory *factory)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (GST_IS_TYPE_FIND_FACTORY (factory), NULL);
|
||||||
|
|
||||||
|
return factory->caps;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* gst_type_find_factory_get_extensions:
|
||||||
|
* @factory: a factory
|
||||||
|
*
|
||||||
|
* Gets the extensions associated with a typefind factory. The returned
|
||||||
|
* array should not be changed. If you need to change stuff in it, you should
|
||||||
|
* copy it using g_stdupv().
|
||||||
|
*
|
||||||
|
* Returns: a NULL-terminated array of extensions associated with this factory
|
||||||
|
*/
|
||||||
|
gchar **
|
||||||
|
gst_type_find_factory_get_extensions (const GstTypeFindFactory *factory)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (GST_IS_TYPE_FIND_FACTORY (factory), NULL);
|
||||||
|
|
||||||
|
return factory->extensions;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* gst_type_find_factory_call_function:
|
||||||
|
* @factory: a factory
|
||||||
|
* @find: a properly setup #GstTypeFind entry. The get_data and suggest_type
|
||||||
|
* members must be set.
|
||||||
|
*
|
||||||
|
* Calls the typefinding function associated with this factory.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_type_find_factory_call_function (const GstTypeFindFactory *factory, GstTypeFind *find)
|
||||||
|
{
|
||||||
|
g_return_if_fail (GST_IS_TYPE_FIND_FACTORY (factory));
|
||||||
|
g_return_if_fail (find != NULL);
|
||||||
|
g_return_if_fail (find->peek != NULL);
|
||||||
|
g_return_if_fail (find->suggest != NULL);
|
||||||
|
|
||||||
|
/* should never happen */
|
||||||
|
g_assert (factory->function != NULL);
|
||||||
|
|
||||||
|
factory->function (find, factory->user_data);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* gst_type_find_factory_register:
|
||||||
|
* @plugin: the GstPlugin to register with
|
||||||
|
* @name: the name for registering
|
||||||
|
* @rank: rank (or importance) of this typefind function
|
||||||
|
* @func: the function to use for typefinding
|
||||||
|
* @extensions: optional extensions that could belong to this type
|
||||||
|
* @possible_caps: optionally the caps that could be returned when typefinding succeeds
|
||||||
|
* @data: optional user data. This user data must be available until the plugin
|
||||||
|
* is unloaded.
|
||||||
|
*
|
||||||
|
* Registers a new typefind function to be used for typefinding. After
|
||||||
|
* registering this function will be available for typefinding.
|
||||||
|
* This function is typically called during an element's plugin initialization.
|
||||||
|
*
|
||||||
|
* Returns: TRUE on success, FALSE otherwise
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_type_find_factory_register (GstPlugin *plugin, const gchar *name, guint rank,
|
||||||
|
GstTypeFindFunction func, gchar **extensions, GstCaps *possible_caps,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
GstTypeFindFactory *factory;
|
||||||
|
|
||||||
|
g_return_if_fail (plugin != NULL);
|
||||||
|
g_return_if_fail (name != NULL);
|
||||||
|
g_return_if_fail (func != NULL);
|
||||||
|
|
||||||
|
GST_INFO ("registering typefind function for %s", name);
|
||||||
|
factory = GST_TYPE_FIND_FACTORY (gst_registry_pool_find_feature (name, GST_TYPE_TYPE_FIND_FACTORY));
|
||||||
|
if (!factory) {
|
||||||
|
factory = g_object_new (GST_TYPE_TYPE_FIND_FACTORY, NULL);
|
||||||
|
GST_DEBUG_OBJECT (factory, "using new typefind factory for %s", name);
|
||||||
|
g_assert (GST_IS_TYPE_FIND_FACTORY (factory));
|
||||||
|
gst_plugin_feature_set_name (GST_PLUGIN_FEATURE (factory), name);
|
||||||
|
} else {
|
||||||
|
GST_DEBUG_OBJECT (factory, "using old typefind factory for %s", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_plugin_feature_set_rank (GST_PLUGIN_FEATURE (factory), rank);
|
||||||
|
if (factory->extensions)
|
||||||
|
g_strfreev (factory->extensions);
|
||||||
|
|
||||||
|
factory->extensions = g_strdupv (extensions);
|
||||||
|
gst_caps_replace (&factory->caps, possible_caps);
|
||||||
|
factory->function = func;
|
||||||
|
factory->user_data = data;
|
||||||
|
|
||||||
|
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** typefind function interface **********************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_type_find_peek:
|
||||||
|
* @find: the find object the function was called with
|
||||||
|
* @offset: the offset
|
||||||
|
* @size: the number of bytes to return
|
||||||
|
*
|
||||||
|
* Returns size bytes of the stream to identify beginning at offset. If offset
|
||||||
|
* is a positive number, the offset is relative to the beginning of the stream,
|
||||||
|
* if offset is a negative number the offset is relative to the end of the
|
||||||
|
* stream. The returned memory is valid until the typefinding function returns
|
||||||
|
* and must not be freed.
|
||||||
|
* If NULL is returned, that data is not available.
|
||||||
|
*
|
||||||
|
* Returns: the requested data or NULL if that data is not available.
|
||||||
|
*/
|
||||||
|
guint8 *
|
||||||
|
gst_type_find_peek (GstTypeFind *find, gint64 offset, guint size)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (find->peek != NULL, NULL);
|
||||||
|
|
||||||
|
return find->peek (find->data, offset, size);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* gst_type_find_suggest:
|
||||||
|
* @find: the find object the function was called with
|
||||||
|
* @probability: the probability in percent that the suggestion is right
|
||||||
|
* @caps: the fixed caps to suggest
|
||||||
|
*
|
||||||
|
* If a typefind function calls this function it suggests the caps with the
|
||||||
|
* given probability. A typefind function may supply different suggestions
|
||||||
|
* in one call.
|
||||||
|
* It is up to the caller of the typefind function to interpret these values.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_type_find_suggest (GstTypeFind *find, guint probability, GstCaps *caps)
|
||||||
|
{
|
||||||
|
g_return_if_fail (find->suggest != NULL);
|
||||||
|
g_return_if_fail (probability <= 100);
|
||||||
|
g_return_if_fail (caps != NULL);
|
||||||
|
g_return_if_fail (GST_CAPS_IS_FIXED (caps));
|
||||||
|
|
||||||
|
gst_caps_ref (caps);
|
||||||
|
gst_caps_sink (caps);
|
||||||
|
find->suggest (find->data, probability, caps);
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* gst_type_find_get_length:
|
||||||
|
* @find: the find object the function was called with
|
||||||
|
*
|
||||||
|
* Get the length of the data stream.
|
||||||
|
*
|
||||||
|
* Returns: the length of the data stream or 0 if it is not available.
|
||||||
|
*/
|
||||||
|
guint64
|
||||||
|
gst_type_find_get_length (GstTypeFind *find)
|
||||||
|
{
|
||||||
|
if (find->get_length == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return find->get_length(find->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
/* GStreamer
|
/* GStreamer
|
||||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
* 2000 Wim Taymans <wtay@chello.be>
|
|
||||||
*
|
*
|
||||||
* gsttypefind.h:
|
* gsttypefind.h: typefinding subsystem
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Library General Public
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
@ -24,51 +23,103 @@
|
||||||
#ifndef __GST_TYPE_FIND_H__
|
#ifndef __GST_TYPE_FIND_H__
|
||||||
#define __GST_TYPE_FIND_H__
|
#define __GST_TYPE_FIND_H__
|
||||||
|
|
||||||
#ifndef GST_DISABLE_TYPE_FIND
|
#include <gst/gstbuffer.h>
|
||||||
|
#include <gst/gstcaps.h>
|
||||||
#include <gst/gstelement.h>
|
#include <gst/gstplugin.h>
|
||||||
#include <gst/gstbytestream.h>
|
#include <gst/gstpluginfeature.h>
|
||||||
|
#include <gst/gsttypes.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
extern GstElementDetails gst_type_find_details;
|
#define GST_TYPE_TYPE_FIND_FACTORY (gst_type_find_factory_get_type())
|
||||||
|
#define GST_TYPE_FIND_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TYPE_FIND_FACTORY, GstTypeFindFactory))
|
||||||
|
#define GST_IS_TYPE_FIND_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TYPE_FIND_FACTORY))
|
||||||
|
#define GST_TYPE_FIND_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_TYPE_FIND_FACTORY, GstTypeFindFactoryClass))
|
||||||
|
#define GST_IS_TYPE_FIND_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_TYPE_FIND_FACTORY))
|
||||||
|
#define GST_TYPE_FIND_FACTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_TYPE_FIND_FACTORY, GstTypeFindFactoryClass))
|
||||||
|
|
||||||
#define GST_TYPE_TYPE_FIND (gst_type_find_get_type ())
|
typedef struct _GstTypeFind GstTypeFind;
|
||||||
#define GST_TYPE_FIND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TYPE_FIND, GstTypeFind))
|
typedef struct _GstTypeFindFactory GstTypeFindFactory;
|
||||||
#define GST_IS_TYPE_FIND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TYPE_FIND))
|
typedef struct _GstTypeFindFactoryClass GstTypeFindFactoryClass;
|
||||||
#define GST_TYPE_FIND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_TYPE_FIND, GstTypeFindClass))
|
|
||||||
#define GST_IS_TYPE_FIND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_TYPE_FIND))
|
|
||||||
#define GST_TYPE_FIND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_TYPE_FIND, GstTypeFindClass))
|
|
||||||
|
|
||||||
typedef struct _GstTypeFind GstTypeFind;
|
typedef void (* GstTypeFindFunction) (GstTypeFind *find, gpointer data);
|
||||||
typedef struct _GstTypeFindClass GstTypeFindClass;
|
|
||||||
|
enum {
|
||||||
|
GST_TYPE_FIND_MINIMUM = 1,
|
||||||
|
GST_TYPE_FIND_POSSIBLE = 50,
|
||||||
|
GST_TYPE_FIND_LIKELY = 80,
|
||||||
|
GST_TYPE_FIND_NEARLY_CERTAIN = 99,
|
||||||
|
GST_TYPE_FIND_MAXIMUM = 100,
|
||||||
|
} GstTypeFindProbability;
|
||||||
|
|
||||||
struct _GstTypeFind {
|
struct _GstTypeFind {
|
||||||
GstElement element;
|
/* private to the caller of the typefind function */
|
||||||
|
guint8 * (* peek) (gpointer data,
|
||||||
|
gint64 offset,
|
||||||
|
guint size);
|
||||||
|
void (* suggest) (gpointer data,
|
||||||
|
guint probability,
|
||||||
|
GstCaps * caps);
|
||||||
|
|
||||||
|
gpointer data;
|
||||||
|
|
||||||
|
/* optional */
|
||||||
|
guint64 (* get_length) (gpointer data);
|
||||||
|
|
||||||
GstPad *sinkpad;
|
/* <private> */
|
||||||
GstByteStream *bs;
|
GST_STRUCT_PADDING
|
||||||
|
|
||||||
GstCaps *caps;
|
|
||||||
|
|
||||||
GST_OBJECT_PADDING
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstTypeFindClass {
|
struct _GstTypeFindFactory {
|
||||||
GstElementClass parent_class;
|
GstPluginFeature feature;
|
||||||
|
/* <private> */
|
||||||
/* signals */
|
|
||||||
void (*have_type) (GstElement *element,
|
|
||||||
GstCaps *caps);
|
|
||||||
|
|
||||||
|
GstTypeFindFunction function;
|
||||||
|
gchar ** extensions;
|
||||||
|
GstCaps * caps; /* FIXME: not yet saved in registry */
|
||||||
|
|
||||||
|
gpointer user_data;
|
||||||
|
|
||||||
|
GST_OBJECT_PADDING
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GstTypeFindFactoryClass {
|
||||||
|
GstPluginFeatureClass parent;
|
||||||
|
/* <private> */
|
||||||
|
|
||||||
GST_CLASS_PADDING
|
GST_CLASS_PADDING
|
||||||
};
|
};
|
||||||
|
|
||||||
GType gst_type_find_get_type (void);
|
/* typefind function interface */
|
||||||
|
guint8 * gst_type_find_peek (GstTypeFind * find,
|
||||||
|
gint64 offset,
|
||||||
|
guint size);
|
||||||
|
void gst_type_find_suggest (GstTypeFind * find,
|
||||||
|
guint probability,
|
||||||
|
GstCaps * caps);
|
||||||
|
guint64 gst_type_find_get_length (GstTypeFind * find);
|
||||||
|
|
||||||
|
/* registration interface */
|
||||||
|
void gst_type_find_factory_register (GstPlugin * plugin,
|
||||||
|
const gchar * name,
|
||||||
|
guint rank,
|
||||||
|
GstTypeFindFunction func,
|
||||||
|
gchar ** extensions,
|
||||||
|
GstCaps * possible_caps,
|
||||||
|
gpointer data);
|
||||||
|
|
||||||
|
/* typefinding interface */
|
||||||
|
|
||||||
|
GType gst_type_find_factory_get_type (void);
|
||||||
|
|
||||||
|
GList * gst_type_find_factory_get_list (void);
|
||||||
|
|
||||||
|
gchar ** gst_type_find_factory_get_extensions (const GstTypeFindFactory *factory);
|
||||||
|
GstCaps * gst_type_find_factory_get_caps (const GstTypeFindFactory *factory);
|
||||||
|
void gst_type_find_factory_call_function (const GstTypeFindFactory *factory,
|
||||||
|
GstTypeFind *find);
|
||||||
|
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* GST_DISABLE_TYPE_FIND */
|
|
||||||
|
|
||||||
#endif /* __GST_TYPE_FIND_H__ */
|
#endif /* __GST_TYPE_FIND_H__ */
|
||||||
|
|
|
@ -265,7 +265,6 @@ gst_util_set_object_arg (GObject * object, const gchar * name, const gchar * val
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "gstpad.h"
|
#include "gstpad.h"
|
||||||
#include "gsttype.h"
|
|
||||||
#include "gstprops.h"
|
#include "gstprops.h"
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -399,14 +398,11 @@ gst_print_pad_caps (GString * buf, gint indent, GstPad * pad)
|
||||||
gint capx = 0;
|
gint capx = 0;
|
||||||
|
|
||||||
while (caps) {
|
while (caps) {
|
||||||
GstType *type;
|
|
||||||
|
|
||||||
string_append_indent (buf, indent);
|
string_append_indent (buf, indent);
|
||||||
g_string_append_printf (buf, "Cap[%d]: %s\n", capx++, caps->name);
|
g_string_append_printf (buf, "Cap[%d]: %s\n", capx++, caps->name);
|
||||||
|
|
||||||
type = gst_type_find_by_id (caps->id);
|
|
||||||
string_append_indent (buf, indent + 2);
|
string_append_indent (buf, indent + 2);
|
||||||
g_string_append_printf (buf, "MIME type: %s\n", type->mime ? type->mime : "unknown/unknown");
|
g_string_append_printf (buf, "MIME type: %s\n", gst_caps_get_mime (caps));
|
||||||
|
|
||||||
if (caps->properties)
|
if (caps->properties)
|
||||||
gst_print_props (buf, indent + 4, caps->properties->properties, TRUE);
|
gst_print_props (buf, indent + 4, caps->properties->properties, TRUE);
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
#include <gst/gst_private.h>
|
#include <gst/gst_private.h>
|
||||||
#include <gst/gstelement.h>
|
#include <gst/gstelement.h>
|
||||||
#include <gst/gsttype.h>
|
#include <gst/gsttypefind.h>
|
||||||
#include <gst/gstscheduler.h>
|
#include <gst/gstscheduler.h>
|
||||||
#include <gst/gstautoplug.h>
|
#include <gst/gstautoplug.h>
|
||||||
#include <gst/gsturi.h>
|
#include <gst/gsturi.h>
|
||||||
|
@ -712,19 +712,42 @@ gst_xml_registry_parse_element_factory (GMarkupParseContext *context, const gcha
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_xml_registry_parse_type_factory (GMarkupParseContext *context, const gchar *tag, const gchar *text,
|
gst_xml_registry_parse_type_find_factory (GMarkupParseContext *context, const gchar *tag, const gchar *text,
|
||||||
gsize text_len, GstXMLRegistry *registry, GError **error)
|
gsize text_len, GstXMLRegistry *registry, GError **error)
|
||||||
{
|
{
|
||||||
GstTypeFactory *factory = GST_TYPE_FACTORY (registry->current_feature);
|
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (registry->current_feature);
|
||||||
|
|
||||||
if (!strcmp (tag, "name")) {
|
if (!strcmp (tag, "name")) {
|
||||||
registry->current_feature->name = g_strndup (text, text_len);
|
registry->current_feature->name = g_strndup (text, text_len);
|
||||||
}
|
}
|
||||||
else if (!strcmp (tag, "mime")) {
|
else if (!strcmp(tag, "rank")) {
|
||||||
factory->mime = g_strndup (text, text_len);
|
glong rank;
|
||||||
|
gchar *ret;
|
||||||
|
rank = strtol (text, &ret, 0);
|
||||||
|
if (ret == text + text_len) {
|
||||||
|
gst_element_factory_set_rank (factory, rank);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (!strcmp(tag, "extensions")) {
|
/* FIXME!!
|
||||||
factory->exts = g_strndup (text, text_len);
|
else if (!strcmp (tag, "caps")) {
|
||||||
|
factory->caps = g_strndup (text, text_len);
|
||||||
|
}*/
|
||||||
|
else if (!strcmp(tag, "extension")) {
|
||||||
|
gchar **new;
|
||||||
|
gchar **old = factory->extensions;
|
||||||
|
gint i = 0;
|
||||||
|
|
||||||
|
/* expensive, but cycles are cheap... */
|
||||||
|
if (old)
|
||||||
|
while (old[i]) i++;
|
||||||
|
new = g_new0 (gchar *, i + 2);
|
||||||
|
new[i] = g_strndup (text, text_len);
|
||||||
|
while (i > 0) {
|
||||||
|
i--;
|
||||||
|
new[i] = old[i];
|
||||||
|
}
|
||||||
|
g_free (old);
|
||||||
|
factory->extensions = new;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -905,8 +928,8 @@ gst_xml_registry_start_element (GMarkupParseContext *context,
|
||||||
xmlregistry->parser = gst_xml_registry_parse_element_factory;
|
xmlregistry->parser = gst_xml_registry_parse_element_factory;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (GST_IS_TYPE_FACTORY (feature)) {
|
else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
|
||||||
xmlregistry->parser = gst_xml_registry_parse_type_factory;
|
xmlregistry->parser = gst_xml_registry_parse_type_find_factory;
|
||||||
}
|
}
|
||||||
else if (GST_IS_SCHEDULER_FACTORY (feature)) {
|
else if (GST_IS_SCHEDULER_FACTORY (feature)) {
|
||||||
xmlregistry->parser = gst_xml_registry_parse_scheduler_factory;
|
xmlregistry->parser = gst_xml_registry_parse_scheduler_factory;
|
||||||
|
@ -1087,20 +1110,11 @@ gst_xml_registry_end_element (GMarkupParseContext *context,
|
||||||
break;
|
break;
|
||||||
case GST_XML_REGISTRY_FEATURE:
|
case GST_XML_REGISTRY_FEATURE:
|
||||||
if (!strcmp (element_name, "feature")) {
|
if (!strcmp (element_name, "feature")) {
|
||||||
if (GST_IS_TYPE_FACTORY (xmlregistry->current_feature)) {
|
|
||||||
GstTypeFactory *factory = GST_TYPE_FACTORY (xmlregistry->current_feature);
|
|
||||||
gst_type_register (factory);
|
|
||||||
}
|
|
||||||
xmlregistry->state = GST_XML_REGISTRY_PLUGIN;
|
xmlregistry->state = GST_XML_REGISTRY_PLUGIN;
|
||||||
xmlregistry->parser = gst_xml_registry_parse_plugin;
|
xmlregistry->parser = gst_xml_registry_parse_plugin;
|
||||||
gst_plugin_add_feature (xmlregistry->current_plugin, xmlregistry->current_feature);
|
gst_plugin_add_feature (xmlregistry->current_plugin, xmlregistry->current_feature);
|
||||||
xmlregistry->current_feature = NULL;
|
xmlregistry->current_feature = NULL;
|
||||||
}
|
}
|
||||||
else if (!strcmp (element_name, "typefind")) {
|
|
||||||
GstTypeFactory *factory = GST_TYPE_FACTORY (xmlregistry->current_feature);
|
|
||||||
|
|
||||||
factory->typefindfunc = gst_type_type_find_dummy;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case GST_XML_REGISTRY_PADTEMPLATE:
|
case GST_XML_REGISTRY_PADTEMPLATE:
|
||||||
if (!strcmp (element_name, "padtemplate")) {
|
if (!strcmp (element_name, "padtemplate")) {
|
||||||
|
@ -1270,12 +1284,19 @@ gst_xml_registry_paths_text (GMarkupParseContext *context, const gchar *text,
|
||||||
#define PUT_ESCAPED(tag,value) \
|
#define PUT_ESCAPED(tag,value) \
|
||||||
G_STMT_START{ \
|
G_STMT_START{ \
|
||||||
const gchar *toconv = value; \
|
const gchar *toconv = value; \
|
||||||
if (value) { \
|
if (toconv) { \
|
||||||
gchar *v = g_markup_escape_text (toconv, strlen (toconv)); \
|
gchar *v = g_markup_escape_text (toconv, strlen (toconv)); \
|
||||||
CLASS (xmlregistry)->save_func (xmlregistry, "<%s>%s</%s>\n", tag, v, tag); \
|
CLASS (xmlregistry)->save_func (xmlregistry, "<%s>%s</%s>\n", tag, v, tag); \
|
||||||
g_free (v); \
|
g_free (v); \
|
||||||
} \
|
} \
|
||||||
}G_STMT_END
|
}G_STMT_END
|
||||||
|
#define PUT_ESCAPED_INT(tag,value) \
|
||||||
|
G_STMT_START{ \
|
||||||
|
gchar *save = g_strdup_printf ("%ld", (glong) value); \
|
||||||
|
CLASS (xmlregistry)->save_func (xmlregistry, "<%s>%s</%s>\n", tag, save, tag); \
|
||||||
|
g_free (save); \
|
||||||
|
}G_STMT_END
|
||||||
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_xml_registry_save_props_func (GstPropsEntry *entry,
|
gst_xml_registry_save_props_func (GstPropsEntry *entry,
|
||||||
|
@ -1381,7 +1402,7 @@ gst_xml_registry_save_caps (GstXMLRegistry *xmlregistry, GstCaps *caps)
|
||||||
while (caps) {
|
while (caps) {
|
||||||
CLASS (xmlregistry)->save_func (xmlregistry, "<capscomp>\n");
|
CLASS (xmlregistry)->save_func (xmlregistry, "<capscomp>\n");
|
||||||
PUT_ESCAPED ("name", caps->name);
|
PUT_ESCAPED ("name", caps->name);
|
||||||
PUT_ESCAPED ("type", gst_type_find_by_id (caps->id)->mime);
|
PUT_ESCAPED ("type", gst_caps_get_mime (caps));
|
||||||
|
|
||||||
if (caps->properties) {
|
if (caps->properties) {
|
||||||
CLASS (xmlregistry)->save_func (xmlregistry, "<properties>\n");
|
CLASS (xmlregistry)->save_func (xmlregistry, "<properties>\n");
|
||||||
|
@ -1460,13 +1481,18 @@ gst_xml_registry_save_feature (GstXMLRegistry *xmlregistry, GstPluginFeature *fe
|
||||||
templates = g_list_next (templates);
|
templates = g_list_next (templates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (GST_IS_TYPE_FACTORY (feature)) {
|
else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
|
||||||
GstTypeFactory *factory = GST_TYPE_FACTORY (feature);
|
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (feature);
|
||||||
|
gint i = 0;
|
||||||
PUT_ESCAPED ("mime", factory->mime);
|
/* FIXME
|
||||||
PUT_ESCAPED ("extensions", factory->exts);
|
if (factory->caps) {
|
||||||
if (factory->typefindfunc) {
|
CLASS (xmlregistry)->save_func (xmlregistry, "<caps>\n");
|
||||||
CLASS (xmlregistry)->save_func (xmlregistry, "<typefind/>\n");
|
gst_xml_registry_save_caps (xmlregistry, factory->caps);
|
||||||
|
CLASS (xmlregistry)->save_func (xmlregistry, "</caps>\n");
|
||||||
|
} */
|
||||||
|
while (factory->extensions[i]) {
|
||||||
|
PUT_ESCAPED ("extension", factory->extensions[i]);
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (GST_IS_SCHEDULER_FACTORY (feature)) {
|
else if (GST_IS_SCHEDULER_FACTORY (feature)) {
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
SUBDIRS = control getbits
|
SUBDIRS = control getbits bytestream
|
||||||
|
|
||||||
DIST_SUBDIRS = control getbits
|
DIST_SUBDIRS = control getbits bytestream
|
||||||
|
|
10
libs/gst/bytestream/Makefile.am
Normal file
10
libs/gst/bytestream/Makefile.am
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
librarydir = $(libdir)/gstreamer-@GST_MAJORMINOR@
|
||||||
|
|
||||||
|
library_LTLIBRARIES = libgstbytestream.la
|
||||||
|
|
||||||
|
libgstbytestreamincludedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst
|
||||||
|
libgstbytestreaminclude_HEADERS = bytestream.h
|
||||||
|
|
||||||
|
libgstbytestream_la_SOURCES = bytestream.c
|
||||||
|
libgstbytestream_la_CFLAGS = $(GST_CFLAGS)
|
||||||
|
libgstbytestream_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
|
@ -28,7 +28,9 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include <gst/gstinfo.h>
|
#include <gst/gstinfo.h>
|
||||||
#include <gst/gstbytestream.h>
|
#include <gst/gstplugin.h>
|
||||||
|
#include <gst/gstversion.h>
|
||||||
|
#include "bytestream.h"
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_STATIC(debug_bs);
|
GST_DEBUG_CATEGORY_STATIC(debug_bs);
|
||||||
#define GST_CAT_DEFAULT debug_bs
|
#define GST_CAT_DEFAULT debug_bs
|
||||||
|
@ -76,8 +78,6 @@ gst_bytestream_new (GstPad * pad)
|
||||||
{
|
{
|
||||||
GstByteStream *bs = g_new (GstByteStream, 1);
|
GstByteStream *bs = g_new (GstByteStream, 1);
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_INIT (debug_bs, "bytestream", 0, "bytestream library");
|
|
||||||
|
|
||||||
bs->pad = pad;
|
bs->pad = pad;
|
||||||
gst_bytestream_init (bs);
|
gst_bytestream_init (bs);
|
||||||
|
|
||||||
|
@ -744,3 +744,19 @@ gst_bytestream_print_status (GstByteStream * bs)
|
||||||
GST_BUFFER_OFFSET (buf), GST_BUFFER_SIZE (buf));
|
GST_BUFFER_OFFSET (buf), GST_BUFFER_SIZE (buf));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
plugin_init (GModule *module, GstPlugin *plugin)
|
||||||
|
{
|
||||||
|
GST_DEBUG_CATEGORY_INIT (debug_bs, "bytestream", 0, "bytestream library");
|
||||||
|
|
||||||
|
gst_plugin_set_longname (plugin, "GstByteStream: a byte-oriented layer on top of buffer-passing");
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GstPluginDesc plugin_desc = {
|
||||||
|
GST_VERSION_MAJOR,
|
||||||
|
GST_VERSION_MINOR,
|
||||||
|
"gstbytestream",
|
||||||
|
plugin_init
|
||||||
|
};
|
|
@ -1,40 +1,51 @@
|
||||||
|
# FIXME:
|
||||||
|
# need to get gstbufferstore.[ch] into its own lib, preferrably
|
||||||
|
# libs/gst/buifferstore
|
||||||
|
# This requires building libs/gst before this dir, which we currently don't
|
||||||
|
# do.
|
||||||
|
|
||||||
plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@
|
plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@
|
||||||
|
|
||||||
plugin_LTLIBRARIES = libgstelements.la
|
plugin_LTLIBRARIES = libgstelements.la
|
||||||
|
|
||||||
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 \
|
gstelements.c \
|
||||||
gstfakesrc.c \
|
|
||||||
gstidentity.c \
|
|
||||||
gstfakesink.c \
|
gstfakesink.c \
|
||||||
gstfilesrc.c \
|
gstfakesrc.c \
|
||||||
gstfilesink.c \
|
gstfilesink.c \
|
||||||
gstfdsrc.c \
|
gstfilesrc.c \
|
||||||
gstfdsink.c \
|
gstfdsink.c \
|
||||||
|
gstfdsrc.c \
|
||||||
|
gstidentity.c \
|
||||||
|
gstmd5sink.c \
|
||||||
gstmultidisksrc.c \
|
gstmultidisksrc.c \
|
||||||
gstpipefilter.c \
|
gstpipefilter.c \
|
||||||
gsttee.c \
|
|
||||||
gstaggregator.c \
|
|
||||||
gstshaper.c \
|
gstshaper.c \
|
||||||
gststatistics.c \
|
gststatistics.c \
|
||||||
gstmd5sink.c
|
gsttee.c \
|
||||||
|
gsttypefindelement.c
|
||||||
|
|
||||||
libgstelements_la_CFLAGS = $(GST_CFLAGS)
|
libgstelements_la_CFLAGS = $(GST_CFLAGS)
|
||||||
libgstelements_la_LIBADD =
|
libgstelements_la_LIBADD =
|
||||||
libgstelements_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
libgstelements_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||||
|
|
||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
gstfakesrc.h \
|
|
||||||
gstidentity.h \
|
|
||||||
gstfakesink.h \
|
|
||||||
gstfilesink.h \
|
|
||||||
gstfdsrc.h \
|
|
||||||
gstmultidisksrc.h \
|
|
||||||
gstfdsink.h \
|
|
||||||
gstpipefilter.h \
|
|
||||||
gsttee.h \
|
|
||||||
gstaggregator.h \
|
gstaggregator.h \
|
||||||
gstshaper.h \
|
gstbufferstore.h \
|
||||||
gststatistics.h \
|
gstfakesink.h \
|
||||||
|
gstfakesrc.h \
|
||||||
|
gstfdsink.h \
|
||||||
|
gstfdsrc.h \
|
||||||
|
gstfilesink.h \
|
||||||
gstfilesrc.h \
|
gstfilesrc.h \
|
||||||
gstmd5sink.h
|
gstidentity.h \
|
||||||
|
gstmd5sink.h \
|
||||||
|
gstmultidisksrc.h \
|
||||||
|
gstpipefilter.h \
|
||||||
|
gstshaper.h \
|
||||||
|
gststatistics.h \
|
||||||
|
gsttee.h \
|
||||||
|
gsttypefindelement.h
|
||||||
|
|
465
plugins/elements/gstbufferstore.c
Normal file
465
plugins/elements/gstbufferstore.c
Normal file
|
@ -0,0 +1,465 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
|
*
|
||||||
|
* gstbufferstore.c: keep an easily accessible list of all buffers
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
#endif
|
||||||
|
#include "gstbufferstore.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY (gst_buffer_store_debug);
|
||||||
|
#define GST_CAT_DEFAULT gst_buffer_store_debug
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CLEARED,
|
||||||
|
BUFFER_ADDED,
|
||||||
|
LAST_SIGNAL
|
||||||
|
};
|
||||||
|
enum {
|
||||||
|
ARG_0
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void gst_buffer_store_class_init (gpointer g_class,
|
||||||
|
gpointer class_data);
|
||||||
|
static void gst_buffer_store_init (GTypeInstance * instance,
|
||||||
|
gpointer g_class);
|
||||||
|
static void gst_buffer_store_dispose (GObject * object);
|
||||||
|
|
||||||
|
static gboolean gst_buffer_store_add_buffer_func (GstBufferStore * store,
|
||||||
|
GstBuffer * buffer);
|
||||||
|
static void gst_buffer_store_cleared_func (GstBufferStore * store);
|
||||||
|
|
||||||
|
static GObjectClass *parent_class = NULL;
|
||||||
|
static guint gst_buffer_store_signals[LAST_SIGNAL] = { 0 };
|
||||||
|
|
||||||
|
G_GNUC_UNUSED static void
|
||||||
|
debug_buffers (GstBufferStore *store)
|
||||||
|
{
|
||||||
|
GList *walk = store->buffers;
|
||||||
|
|
||||||
|
g_printerr ("BUFFERS in store:\n");
|
||||||
|
while (walk) {
|
||||||
|
g_print ("%15"G_GUINT64_FORMAT" - %7u\n", GST_BUFFER_OFFSET (walk->data), GST_BUFFER_SIZE (walk->data));
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
}
|
||||||
|
g_printerr ("\n");
|
||||||
|
}
|
||||||
|
GType
|
||||||
|
gst_buffer_store_get_type (void)
|
||||||
|
{
|
||||||
|
static GType store_type = 0;
|
||||||
|
|
||||||
|
if (!store_type) {
|
||||||
|
static const GTypeInfo store_info = {
|
||||||
|
sizeof (GstBufferStoreClass),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
gst_buffer_store_class_init,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
sizeof (GstBufferStore),
|
||||||
|
0,
|
||||||
|
gst_buffer_store_init,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
store_type = g_type_register_static (G_TYPE_OBJECT,
|
||||||
|
"GstBufferStore",
|
||||||
|
&store_info, 0);
|
||||||
|
|
||||||
|
/* FIXME: better description anyone? */
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_buffer_store_debug, "bufferstore", 0, "store all data");
|
||||||
|
}
|
||||||
|
return store_type;
|
||||||
|
}
|
||||||
|
static gboolean
|
||||||
|
continue_accu (GSignalInvocationHint *ihint, GValue *return_accu,
|
||||||
|
const GValue *handler_return, gpointer data)
|
||||||
|
{
|
||||||
|
gboolean do_continue = g_value_get_boolean (handler_return);
|
||||||
|
g_value_set_boolean (return_accu, do_continue);
|
||||||
|
|
||||||
|
return do_continue;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_buffer_store_class_init (gpointer g_class, gpointer class_data)
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class;
|
||||||
|
GstBufferStoreClass *store_class;
|
||||||
|
|
||||||
|
gobject_class = G_OBJECT_CLASS (g_class);
|
||||||
|
store_class = GST_BUFFER_STORE_CLASS (g_class);
|
||||||
|
|
||||||
|
parent_class = g_type_class_peek_parent (g_class);
|
||||||
|
|
||||||
|
gobject_class->dispose = gst_buffer_store_dispose;
|
||||||
|
|
||||||
|
gst_buffer_store_signals[CLEARED] = g_signal_new ("cleared",
|
||||||
|
G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_LAST,
|
||||||
|
G_STRUCT_OFFSET (GstBufferStoreClass, cleared), NULL, NULL,
|
||||||
|
gst_marshal_VOID__VOID, G_TYPE_NONE, 0);
|
||||||
|
gst_buffer_store_signals[BUFFER_ADDED] = g_signal_new ("buffer-added",
|
||||||
|
G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_LAST,
|
||||||
|
G_STRUCT_OFFSET (GstBufferStoreClass, buffer_added), continue_accu, NULL,
|
||||||
|
gst_marshal_BOOLEAN__POINTER, G_TYPE_BOOLEAN, 1, G_TYPE_POINTER);
|
||||||
|
|
||||||
|
store_class->cleared = gst_buffer_store_cleared_func;
|
||||||
|
store_class->buffer_added = gst_buffer_store_add_buffer_func;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_buffer_store_init (GTypeInstance *instance, gpointer g_class)
|
||||||
|
{
|
||||||
|
GstBufferStore *store = GST_BUFFER_STORE (instance);
|
||||||
|
|
||||||
|
store->buffers = NULL;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_buffer_store_dispose (GObject *object)
|
||||||
|
{
|
||||||
|
GstBufferStore *store = GST_BUFFER_STORE (object);
|
||||||
|
|
||||||
|
gst_buffer_store_clear (store);
|
||||||
|
|
||||||
|
parent_class->dispose (object);
|
||||||
|
}
|
||||||
|
static gboolean
|
||||||
|
gst_buffer_store_add_buffer_func (GstBufferStore *store, GstBuffer *buffer)
|
||||||
|
{
|
||||||
|
g_assert (buffer != NULL);
|
||||||
|
|
||||||
|
if (!GST_BUFFER_OFFSET_IS_VALID (buffer) &&
|
||||||
|
store->buffers &&
|
||||||
|
GST_BUFFER_OFFSET_IS_VALID (store->buffers->data)) {
|
||||||
|
/* we assumed valid offsets, but suddenly they are not anymore */
|
||||||
|
GST_DEBUG_OBJECT (store, "attempting to add buffer %p with invalid offset to store with valid offset, abort",
|
||||||
|
buffer);
|
||||||
|
return FALSE;
|
||||||
|
} else if (!store->buffers || !GST_BUFFER_OFFSET_IS_VALID (store->buffers->data)) {
|
||||||
|
/* the starting buffer had an invalid offset, in that case we assume continuous buffers */
|
||||||
|
GST_LOG_OBJECT (store, "adding buffer %p with invalid offset and size %u",
|
||||||
|
buffer, GST_BUFFER_SIZE (buffer));
|
||||||
|
gst_data_ref (GST_DATA (buffer));
|
||||||
|
store->buffers = g_list_append (store->buffers, buffer);
|
||||||
|
return TRUE;
|
||||||
|
} else {
|
||||||
|
/* both list and buffer have valid offsets, we can really go wild */
|
||||||
|
GList *walk, *current_list = NULL;
|
||||||
|
GstBuffer *current;
|
||||||
|
|
||||||
|
g_assert (GST_BUFFER_OFFSET_IS_VALID (buffer));
|
||||||
|
GST_LOG_OBJECT (store, "attempting to add buffer %p with offset %"G_GUINT64_FORMAT" and size %u",
|
||||||
|
buffer, GST_BUFFER_OFFSET (buffer), GST_BUFFER_SIZE (buffer));
|
||||||
|
/* we keep a sorted list of non-overlapping buffers */
|
||||||
|
walk = store->buffers;
|
||||||
|
while (walk) {
|
||||||
|
current = GST_BUFFER (walk->data);
|
||||||
|
current_list = walk;
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
if (GST_BUFFER_OFFSET (current) < GST_BUFFER_OFFSET (buffer)) {
|
||||||
|
continue;
|
||||||
|
} else if (GST_BUFFER_OFFSET (current) == GST_BUFFER_OFFSET (buffer)) {
|
||||||
|
guint needed_size;
|
||||||
|
if (walk) {
|
||||||
|
needed_size = MIN (GST_BUFFER_SIZE (buffer),
|
||||||
|
GST_BUFFER_OFFSET (walk->data) - GST_BUFFER_OFFSET (current));
|
||||||
|
} else {
|
||||||
|
needed_size = GST_BUFFER_SIZE (buffer);
|
||||||
|
}
|
||||||
|
if (needed_size <= GST_BUFFER_SIZE (current)) {
|
||||||
|
buffer = NULL;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (needed_size < GST_BUFFER_SIZE (buffer)) {
|
||||||
|
/* need to create subbuffer to not have overlapping data */
|
||||||
|
GstBuffer *sub = gst_buffer_create_sub (buffer, 0, needed_size);
|
||||||
|
g_assert (sub);
|
||||||
|
buffer = sub;
|
||||||
|
} else {
|
||||||
|
gst_data_ref (GST_DATA (buffer));
|
||||||
|
}
|
||||||
|
/* replace current buffer with new one */
|
||||||
|
GST_INFO_OBJECT (store, "replacing buffer %p with buffer %p with offset %"G_GINT64_FORMAT" and size %u",
|
||||||
|
current_list->data, buffer, GST_BUFFER_OFFSET (buffer), GST_BUFFER_SIZE (buffer));
|
||||||
|
gst_data_unref (GST_DATA (current_list->data));
|
||||||
|
current_list->data = buffer;
|
||||||
|
buffer = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (GST_BUFFER_OFFSET (current) > GST_BUFFER_OFFSET (buffer)) {
|
||||||
|
GList *previous = g_list_previous (current_list);
|
||||||
|
guint64 start_offset = previous ?
|
||||||
|
GST_BUFFER_OFFSET (previous->data) + GST_BUFFER_SIZE (previous->data) : 0;
|
||||||
|
|
||||||
|
if (start_offset == GST_BUFFER_OFFSET (current)) {
|
||||||
|
buffer = NULL;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
/* we have data to insert */
|
||||||
|
if (start_offset > GST_BUFFER_OFFSET (buffer) ||
|
||||||
|
GST_BUFFER_OFFSET (buffer) + GST_BUFFER_SIZE (buffer) > GST_BUFFER_OFFSET (current)) {
|
||||||
|
/* need a subbuffer */
|
||||||
|
start_offset = GST_BUFFER_OFFSET (buffer) > start_offset ? 0 :
|
||||||
|
start_offset - GST_BUFFER_OFFSET (buffer);
|
||||||
|
GstBuffer* sub = gst_buffer_create_sub (buffer, start_offset,
|
||||||
|
MIN (GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (current) - start_offset - GST_BUFFER_OFFSET (buffer)));
|
||||||
|
g_assert (sub);
|
||||||
|
GST_BUFFER_OFFSET (sub) = start_offset + GST_BUFFER_OFFSET (buffer);
|
||||||
|
buffer = sub;
|
||||||
|
} else {
|
||||||
|
gst_data_ref (GST_DATA (buffer));
|
||||||
|
}
|
||||||
|
GST_INFO_OBJECT (store, "adding buffer %p with offset %"G_GINT64_FORMAT" and size %u",
|
||||||
|
buffer, GST_BUFFER_OFFSET (buffer), GST_BUFFER_SIZE (buffer));
|
||||||
|
store->buffers = g_list_insert_before (store->buffers, current_list, buffer);
|
||||||
|
buffer = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (buffer) {
|
||||||
|
gst_data_ref (GST_DATA (buffer));
|
||||||
|
GST_INFO_OBJECT (store, "adding buffer %p with offset %"G_GINT64_FORMAT" and size %u",
|
||||||
|
buffer, GST_BUFFER_OFFSET (buffer), GST_BUFFER_SIZE (buffer));
|
||||||
|
if (current_list) {
|
||||||
|
g_list_append (current_list, buffer);
|
||||||
|
} else {
|
||||||
|
g_assert (store->buffers == NULL);
|
||||||
|
store->buffers = g_list_prepend (NULL, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_buffer_store_cleared_func (GstBufferStore *store)
|
||||||
|
{
|
||||||
|
g_list_foreach (store->buffers, (GFunc) gst_data_unref, NULL);
|
||||||
|
g_list_free (store->buffers);
|
||||||
|
store->buffers = NULL;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* gst_buffer_store_new:
|
||||||
|
*
|
||||||
|
* Creates a new bufferstore.
|
||||||
|
*
|
||||||
|
* Returns: the new bufferstore.
|
||||||
|
*/
|
||||||
|
GstBufferStore *
|
||||||
|
gst_buffer_store_new (void)
|
||||||
|
{
|
||||||
|
return GST_BUFFER_STORE (g_object_new (GST_TYPE_BUFFER_STORE, NULL));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* gst_buffer_store_clear:
|
||||||
|
* @store: a bufferstore
|
||||||
|
*
|
||||||
|
* Clears the buffer store. All buffers are removed and the buffer store
|
||||||
|
* behaves like it was just created.
|
||||||
|
*/
|
||||||
|
/* FIXME: call this function _reset ? */
|
||||||
|
void
|
||||||
|
gst_buffer_store_clear (GstBufferStore *store)
|
||||||
|
{
|
||||||
|
g_return_if_fail (GST_IS_BUFFER_STORE (store));
|
||||||
|
|
||||||
|
g_signal_emit (store, gst_buffer_store_signals [CLEARED], 0, NULL);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* gst_buffer_store_add_buffer:
|
||||||
|
* @store: a bufferstore
|
||||||
|
* @buffer: the buffer to add
|
||||||
|
*
|
||||||
|
* Adds a buffer to the buffer store.
|
||||||
|
*
|
||||||
|
* Returns: TRUE, if the buffer was added, FALSE if an error occured.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
gst_buffer_store_add_buffer (GstBufferStore *store, GstBuffer *buffer)
|
||||||
|
{
|
||||||
|
gboolean ret;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_BUFFER_STORE (store), FALSE);
|
||||||
|
g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
|
||||||
|
|
||||||
|
if (store->buffers &&
|
||||||
|
GST_BUFFER_OFFSET_IS_VALID (store->buffers->data) &&
|
||||||
|
!GST_BUFFER_OFFSET_IS_VALID (buffer))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
g_signal_emit (store, gst_buffer_store_signals [BUFFER_ADDED], 0, buffer, &ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* gst_buffer_store_get_buffer:
|
||||||
|
* @store: a bufferstore
|
||||||
|
* @offset: starting offset of returned buffer
|
||||||
|
* @size: size of returned buffer
|
||||||
|
*
|
||||||
|
* Returns a buffer that corresponds to the given area of data. If part of the
|
||||||
|
* data is not available inside the store, NULL is returned. You have to unref
|
||||||
|
* the buffer after use.
|
||||||
|
*
|
||||||
|
* Returns: a buffer with the requested data or NULL if the data was not
|
||||||
|
* available.
|
||||||
|
*/
|
||||||
|
GstBuffer *
|
||||||
|
gst_buffer_store_get_buffer (GstBufferStore *store, guint64 offset, guint size)
|
||||||
|
{
|
||||||
|
GstBuffer *current;
|
||||||
|
GList *walk;
|
||||||
|
guint8 *data;
|
||||||
|
guint tmp;
|
||||||
|
guint64 cur_offset;
|
||||||
|
gboolean have_offset;
|
||||||
|
GstBuffer *ret = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_BUFFER_STORE (store), NULL);
|
||||||
|
|
||||||
|
walk = store->buffers;
|
||||||
|
if (!walk)
|
||||||
|
return NULL;
|
||||||
|
if (GST_BUFFER_OFFSET_IS_VALID (walk->data)) {
|
||||||
|
have_offset = TRUE;
|
||||||
|
} else {
|
||||||
|
have_offset = FALSE;
|
||||||
|
cur_offset = 0;
|
||||||
|
}
|
||||||
|
while (walk) {
|
||||||
|
current = GST_BUFFER (walk->data);
|
||||||
|
if (have_offset) {
|
||||||
|
cur_offset = GST_BUFFER_OFFSET (current);
|
||||||
|
}
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
if (cur_offset > offset) {
|
||||||
|
/* #include <windows.h>
|
||||||
|
do_nothing_loop (); */
|
||||||
|
} else if (cur_offset == offset &&
|
||||||
|
GST_BUFFER_SIZE (current) == size) {
|
||||||
|
GST_LOG_OBJECT (store, "found matching buffer %p for offset %"G_GUINT64_FORMAT" and size %u",
|
||||||
|
current, offset, size);
|
||||||
|
ret = current;
|
||||||
|
gst_data_ref (GST_DATA (ret));
|
||||||
|
GST_LOG_OBJECT (store, "refcount %d",
|
||||||
|
GST_DATA_REFCOUNT_VALUE(ret));
|
||||||
|
break;
|
||||||
|
} else if (cur_offset + GST_BUFFER_SIZE (current) > offset) {
|
||||||
|
if (cur_offset + GST_BUFFER_SIZE (current) >= offset + size) {
|
||||||
|
ret = gst_buffer_create_sub (current, offset - cur_offset, size);
|
||||||
|
GST_LOG_OBJECT (store, "created subbuffer %p from buffer %p for offset %llu and size %u",
|
||||||
|
ret, current, offset, size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* uh, the requested data spans some buffers */
|
||||||
|
ret = gst_buffer_new_and_alloc (size);
|
||||||
|
GST_LOG_OBJECT (store, "created buffer %p for offset %"G_GUINT64_FORMAT
|
||||||
|
" and size %u, will fill with data now",
|
||||||
|
ret, offset, size);
|
||||||
|
data = GST_BUFFER_DATA (ret);
|
||||||
|
tmp = GST_BUFFER_SIZE (current) - offset + cur_offset;
|
||||||
|
memcpy (data, GST_BUFFER_DATA (current) + offset - cur_offset, tmp);
|
||||||
|
data += tmp;
|
||||||
|
size -= tmp;
|
||||||
|
while (size) {
|
||||||
|
if (walk == NULL ||
|
||||||
|
(have_offset &&
|
||||||
|
GST_BUFFER_OFFSET (current) + GST_BUFFER_SIZE (current) != GST_BUFFER_OFFSET (walk->data))) {
|
||||||
|
GST_DEBUG_OBJECT (store, "not all data for offset %"G_GUINT64_FORMAT" and remaining size %u available, aborting",
|
||||||
|
offset, size);
|
||||||
|
gst_data_unref (GST_DATA (ret));
|
||||||
|
ret = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
current = GST_BUFFER (walk->data);
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
tmp = MIN (GST_BUFFER_SIZE (current), size);
|
||||||
|
memcpy (data, GST_BUFFER_DATA (current), tmp);
|
||||||
|
size -= tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!have_offset) {
|
||||||
|
cur_offset += GST_BUFFER_SIZE (current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* gst_buffer_store_get_size:
|
||||||
|
* @store: a bufferstore
|
||||||
|
* @offset: desired offset
|
||||||
|
*
|
||||||
|
* Calculates the number of bytes available starting from offset. This allows
|
||||||
|
* to query a buffer with the returned size.
|
||||||
|
*
|
||||||
|
* Returns: the number of continuous bytes in the bufferstore starting at
|
||||||
|
* offset.
|
||||||
|
*/
|
||||||
|
guint
|
||||||
|
gst_buffer_store_get_size (GstBufferStore *store, guint64 offset)
|
||||||
|
{
|
||||||
|
GList *walk;
|
||||||
|
guint64 cur_offset;
|
||||||
|
gboolean have_offset;
|
||||||
|
gboolean counting = FALSE;
|
||||||
|
GstBuffer *current;
|
||||||
|
guint ret = 0;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_BUFFER_STORE (store), 0);
|
||||||
|
|
||||||
|
walk = store->buffers;
|
||||||
|
if (!walk)
|
||||||
|
return 0;
|
||||||
|
if (GST_BUFFER_OFFSET_IS_VALID (walk->data)) {
|
||||||
|
have_offset = TRUE;
|
||||||
|
} else {
|
||||||
|
have_offset = FALSE;
|
||||||
|
cur_offset = 0;
|
||||||
|
}
|
||||||
|
while (walk) {
|
||||||
|
if (have_offset && counting &&
|
||||||
|
cur_offset + GST_BUFFER_SIZE (current) != GST_BUFFER_OFFSET (walk->data)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
current = GST_BUFFER (walk->data);
|
||||||
|
if (have_offset) {
|
||||||
|
cur_offset = GST_BUFFER_OFFSET (current);
|
||||||
|
}
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
if (counting) {
|
||||||
|
ret += GST_BUFFER_SIZE (current);
|
||||||
|
} else {
|
||||||
|
if (cur_offset > offset)
|
||||||
|
return 0;
|
||||||
|
if (cur_offset + GST_BUFFER_SIZE (current) > offset) {
|
||||||
|
/* we have at least some bytes */
|
||||||
|
ret = cur_offset + GST_BUFFER_SIZE (current) - offset;
|
||||||
|
counting = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!have_offset) {
|
||||||
|
cur_offset += GST_BUFFER_SIZE (current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
73
plugins/elements/gstbufferstore.h
Normal file
73
plugins/elements/gstbufferstore.h
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
|
*
|
||||||
|
* gsttypefind.h: keep an easily accessible list of all buffers
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __GST_BUFFER_STORE_H__
|
||||||
|
#define __GST_BUFFER_STORE_H__
|
||||||
|
|
||||||
|
#include <gst/gstbuffer.h>
|
||||||
|
#include <gst/gstinfo.h>
|
||||||
|
#include <gst/gstmarshal.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define GST_TYPE_BUFFER_STORE (gst_buffer_store_get_type ())
|
||||||
|
#define GST_BUFFER_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_BUFFER_STORE, GstBufferStore))
|
||||||
|
#define GST_IS_BUFFER_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_BUFFER_STORE))
|
||||||
|
#define GST_BUFFER_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_BUFFER_STORE, GstBufferStoreClass))
|
||||||
|
#define GST_IS_BUFFER_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_BUFFER_STORE))
|
||||||
|
#define GST_BUFFER_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_BUFFER_STORE, GstBufferStoreClass))
|
||||||
|
|
||||||
|
typedef struct _GstBufferStore GstBufferStore;
|
||||||
|
typedef struct _GstBufferStoreClass GstBufferStoreClass;
|
||||||
|
|
||||||
|
struct _GstBufferStore {
|
||||||
|
GObject object;
|
||||||
|
|
||||||
|
GList * buffers;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GstBufferStoreClass {
|
||||||
|
GObjectClass parent_class;
|
||||||
|
|
||||||
|
/* signals */
|
||||||
|
void (* cleared) (GstBufferStore * store);
|
||||||
|
gboolean (* buffer_added) (GstBufferStore * store,
|
||||||
|
GstBuffer * buffer);
|
||||||
|
};
|
||||||
|
|
||||||
|
GType gst_buffer_store_get_type (void);
|
||||||
|
|
||||||
|
GstBufferStore * gst_buffer_store_new (void);
|
||||||
|
void gst_buffer_store_clear (GstBufferStore * store);
|
||||||
|
|
||||||
|
gboolean gst_buffer_store_add_buffer (GstBufferStore * store,
|
||||||
|
GstBuffer * buffer);
|
||||||
|
|
||||||
|
GstBuffer * gst_buffer_store_get_buffer (GstBufferStore * store,
|
||||||
|
guint64 offset,
|
||||||
|
guint size);
|
||||||
|
guint gst_buffer_store_get_size (GstBufferStore * store,
|
||||||
|
guint64 offset);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __GST_BUFFER_STORE_H__ */
|
|
@ -27,20 +27,21 @@
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
|
||||||
#include "gstfilesrc.h"
|
#include "gstaggregator.h"
|
||||||
#include "gstfilesink.h"
|
|
||||||
#include "gstidentity.h"
|
|
||||||
#include "gstfakesink.h"
|
#include "gstfakesink.h"
|
||||||
#include "gstfakesrc.h"
|
#include "gstfakesrc.h"
|
||||||
#include "gstfdsink.h"
|
#include "gstfdsink.h"
|
||||||
#include "gstfdsrc.h"
|
#include "gstfdsrc.h"
|
||||||
|
#include "gstfilesink.h"
|
||||||
|
#include "gstfilesrc.h"
|
||||||
|
#include "gstidentity.h"
|
||||||
|
#include "gstmd5sink.h"
|
||||||
#include "gstmultidisksrc.h"
|
#include "gstmultidisksrc.h"
|
||||||
#include "gstpipefilter.h"
|
#include "gstpipefilter.h"
|
||||||
#include "gsttee.h"
|
|
||||||
#include "gstaggregator.h"
|
|
||||||
#include "gstshaper.h"
|
#include "gstshaper.h"
|
||||||
#include "gststatistics.h"
|
#include "gststatistics.h"
|
||||||
#include "gstmd5sink.h"
|
#include "gsttee.h"
|
||||||
|
#include "gsttypefindelement.h"
|
||||||
|
|
||||||
|
|
||||||
struct _elements_entry {
|
struct _elements_entry {
|
||||||
|
@ -55,20 +56,21 @@ 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_aggregator_get_type, &gst_aggregator_details, gst_aggregator_factory_init },
|
||||||
{ "fakesrc", gst_fakesrc_get_type, &gst_fakesrc_details, gst_fakesrc_factory_init },
|
{ "fakesrc", gst_fakesrc_get_type, &gst_fakesrc_details, gst_fakesrc_factory_init },
|
||||||
{ "fakesink", gst_fakesink_get_type, &gst_fakesink_details, gst_fakesink_factory_init },
|
{ "fakesink", gst_fakesink_get_type, &gst_fakesink_details, gst_fakesink_factory_init },
|
||||||
|
{ "fdsink", gst_fdsink_get_type, &gst_fdsink_details, NULL },
|
||||||
|
{ "fdsrc", gst_fdsrc_get_type, &gst_fdsrc_details, NULL },
|
||||||
{ "filesrc", gst_filesrc_get_type, &gst_filesrc_details, NULL },
|
{ "filesrc", gst_filesrc_get_type, &gst_filesrc_details, NULL },
|
||||||
{ "filesink", gst_filesink_get_type, &gst_filesink_details, NULL },
|
{ "filesink", gst_filesink_get_type, &gst_filesink_details, NULL },
|
||||||
{ "identity", gst_identity_get_type, &gst_identity_details, NULL },
|
{ "identity", gst_identity_get_type, &gst_identity_details, NULL },
|
||||||
{ "fdsink", gst_fdsink_get_type, &gst_fdsink_details, NULL },
|
{ "md5sink", gst_md5sink_get_type, &gst_md5sink_details, gst_md5sink_factory_init },
|
||||||
{ "fdsrc", gst_fdsrc_get_type, &gst_fdsrc_details, NULL },
|
|
||||||
{ "multidisksrc", gst_multidisksrc_get_type, &gst_multidisksrc_details, NULL },
|
{ "multidisksrc", gst_multidisksrc_get_type, &gst_multidisksrc_details, NULL },
|
||||||
{ "pipefilter", gst_pipefilter_get_type, &gst_pipefilter_details, NULL },
|
{ "pipefilter", gst_pipefilter_get_type, &gst_pipefilter_details, NULL },
|
||||||
{ "tee", gst_tee_get_type, &gst_tee_details, gst_tee_factory_init },
|
|
||||||
{ "aggregator", gst_aggregator_get_type, &gst_aggregator_details, gst_aggregator_factory_init },
|
|
||||||
{ "shaper", gst_shaper_get_type, &gst_shaper_details, gst_shaper_factory_init },
|
{ "shaper", gst_shaper_get_type, &gst_shaper_details, gst_shaper_factory_init },
|
||||||
{ "statistics", gst_statistics_get_type, &gst_statistics_details, NULL },
|
{ "statistics", gst_statistics_get_type, &gst_statistics_details, NULL },
|
||||||
{ "md5sink", gst_md5sink_get_type, &gst_md5sink_details, gst_md5sink_factory_init },
|
{ "tee", gst_tee_get_type, &gst_tee_details, gst_tee_factory_init },
|
||||||
|
{ "typefind", gst_type_find_element_get_type, &gst_type_find_element_details, NULL },
|
||||||
{ NULL, 0 },
|
{ NULL, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -80,20 +82,21 @@ plugin_init (GModule *module, GstPlugin *plugin)
|
||||||
|
|
||||||
gst_plugin_set_longname (plugin, "Standard GST Elements");
|
gst_plugin_set_longname (plugin, "Standard GST Elements");
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_fakesrc_debug, "fakesrc", 0, "fakesrc element");
|
GST_DEBUG_CATEGORY_INIT (gst_aggregator_debug, "aggregator", 0, "aggregator element");
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_fakesink_debug, "fakesink", 0, "fakesink element");
|
GST_DEBUG_CATEGORY_INIT (gst_fakesink_debug, "fakesink", 0, "fakesink element");
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_filesrc_debug, "filesrc", 0, "filesrc element");
|
GST_DEBUG_CATEGORY_INIT (gst_fakesrc_debug, "fakesrc", 0, "fakesrc element");
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_filesink_debug, "fakesink", 0, "filesink element");
|
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_identity_debug, "identity", 0, "identity element");
|
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_fdsrc_debug, "fdsrc", 0, "fdsrc element");
|
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_fdsink_debug, "fdsink", 0, "fdsink element");
|
GST_DEBUG_CATEGORY_INIT (gst_fdsink_debug, "fdsink", 0, "fdsink element");
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_fdsrc_debug, "fdsrc", 0, "fdsrc element");
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_filesink_debug, "filesink", 0, "filesink element");
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_filesrc_debug, "filesrc", 0, "filesrc element");
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_identity_debug, "identity", 0, "identity element");
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_md5sink_debug, "md5sink", 0, "md5sink element");
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_multidisksrc_debug, "multidisksrc", 0, "multidisksrc element");
|
GST_DEBUG_CATEGORY_INIT (gst_multidisksrc_debug, "multidisksrc", 0, "multidisksrc element");
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_pipefilter_debug, "pipefilter", 0, "pipefilter element");
|
GST_DEBUG_CATEGORY_INIT (gst_pipefilter_debug, "pipefilter", 0, "pipefilter element");
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_tee_debug, "tee", 0, "tee element");
|
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_aggregator_debug, "aggregator", 0, "aggregator element");
|
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_shaper_debug, "shaper", 0, "shaper element");
|
GST_DEBUG_CATEGORY_INIT (gst_shaper_debug, "shaper", 0, "shaper element");
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_statistics_debug, "statistics", 0, "statistics element");
|
GST_DEBUG_CATEGORY_INIT (gst_statistics_debug, "statistics", 0, "statistics element");
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_md5sink_debug, "md5sink", 0, "md5sink element");
|
GST_DEBUG_CATEGORY_INIT (gst_tee_debug, "tee", 0, "tee element");
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_type_find_element_debug, "typefind", GST_DEBUG_BG_YELLOW | GST_DEBUG_FG_GREEN, "typefind element");
|
||||||
|
|
||||||
while (_elements[i].name) {
|
while (_elements[i].name) {
|
||||||
factory = gst_element_factory_new (_elements[i].name,
|
factory = gst_element_factory_new (_elements[i].name,
|
||||||
|
@ -112,12 +115,10 @@ plugin_init (GModule *module, GstPlugin *plugin)
|
||||||
_elements[i].factoryinit (factory);
|
_elements[i].factoryinit (factory);
|
||||||
}
|
}
|
||||||
/* g_print("added factory '%s'\n",_elements[i].name); */
|
/* g_print("added factory '%s'\n",_elements[i].name); */
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* INFO (GST_INFO_PLUGIN_LOAD,"gstelements: loaded %d standard elements", i);*/
|
/* INFO (GST_INFO_PLUGIN_LOAD,"gstelements: loaded %d standard elements", i);*/
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -487,7 +487,7 @@ gst_fakesrc_set_property (GObject *object, guint prop_id, const GValue *value, G
|
||||||
src->pool = gst_buffer_pool_get_default (src->sizemax, 10);
|
src->pool = gst_buffer_pool_get_default (src->sizemax, 10);
|
||||||
} else {
|
} else {
|
||||||
if (src->pool) {
|
if (src->pool) {
|
||||||
gst_buffer_pool_free (src->pool);
|
gst_buffer_pool_unref (src->pool);
|
||||||
src->pool = NULL;
|
src->pool = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,18 +88,6 @@ GstElementDetails gst_filesrc_details = {
|
||||||
#define DEFAULT_BLOCKSIZE 4*1024
|
#define DEFAULT_BLOCKSIZE 4*1024
|
||||||
#define DEFAULT_MMAPSIZE 4*1024*1024
|
#define DEFAULT_MMAPSIZE 4*1024*1024
|
||||||
|
|
||||||
#ifdef G_HAVE_ISO_VARARGS
|
|
||||||
|
|
||||||
/* #define fs_print(...) g_print(__VA_ARGS__) */
|
|
||||||
#define fs_print(...)
|
|
||||||
|
|
||||||
#elif defined(G_HAVE_GNUC_VARARGS)
|
|
||||||
|
|
||||||
/* #define fs_print(format,args...) g_print(format, ## args) */
|
|
||||||
#define fs_print(format,args...)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* FileSrc signals and args */
|
/* FileSrc signals and args */
|
||||||
enum {
|
enum {
|
||||||
/* FILL ME */
|
/* FILL ME */
|
||||||
|
@ -305,7 +293,7 @@ gst_filesrc_set_property (GObject *object, guint prop_id, const GValue *value, G
|
||||||
src->mapsize = g_value_get_ulong (value);
|
src->mapsize = g_value_get_ulong (value);
|
||||||
g_object_notify (G_OBJECT (src), "mmapsize");
|
g_object_notify (G_OBJECT (src), "mmapsize");
|
||||||
} else {
|
} else {
|
||||||
GST_INFO ( "invalid mapsize, must a multiple of pagesize, which is %d",
|
GST_INFO_OBJECT (src, "invalid mapsize, must a multiple of pagesize, which is %d",
|
||||||
src->pagesize);
|
src->pagesize);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -355,8 +343,8 @@ gst_filesrc_free_parent_mmap (GstBuffer *buf)
|
||||||
{
|
{
|
||||||
GstFileSrc *src = GST_FILESRC (GST_BUFFER_POOL_PRIVATE (buf));
|
GstFileSrc *src = GST_FILESRC (GST_BUFFER_POOL_PRIVATE (buf));
|
||||||
|
|
||||||
fs_print ("freeing mmap()d buffer at %d+%d\n",
|
GST_LOG_OBJECT (src, "freeing mmap()d buffer at %"G_GUINT64_FORMAT"+%u",
|
||||||
GST_BUFFER_OFFSET (buf), GST_BUFFER_SIZE (buf));
|
GST_BUFFER_OFFSET (buf), GST_BUFFER_SIZE (buf));
|
||||||
|
|
||||||
/* remove the buffer from the list of available mmap'd regions */
|
/* remove the buffer from the list of available mmap'd regions */
|
||||||
g_mutex_lock (src->map_regions_lock);
|
g_mutex_lock (src->map_regions_lock);
|
||||||
|
@ -375,13 +363,14 @@ gst_filesrc_free_parent_mmap (GstBuffer *buf)
|
||||||
munmap (GST_BUFFER_DATA (buf), GST_BUFFER_MAXSIZE (buf));
|
munmap (GST_BUFFER_DATA (buf), GST_BUFFER_MAXSIZE (buf));
|
||||||
/* cast to unsigned long, since there's no gportable way to print
|
/* cast to unsigned long, since there's no gportable way to print
|
||||||
* guint64 as hex */
|
* guint64 as hex */
|
||||||
GST_DEBUG ( "unmapped region %08lx+%08lx at %p",
|
GST_LOG_OBJECT (src, "unmapped region %08lx+%08lx at %p",
|
||||||
(unsigned long) GST_BUFFER_OFFSET (buf),
|
(unsigned long) GST_BUFFER_OFFSET (buf),
|
||||||
(unsigned long) GST_BUFFER_MAXSIZE (buf),
|
(unsigned long) GST_BUFFER_MAXSIZE (buf),
|
||||||
GST_BUFFER_DATA (buf));
|
GST_BUFFER_DATA (buf));
|
||||||
|
|
||||||
GST_BUFFER_DATA (buf) = NULL;
|
GST_BUFFER_DATA (buf) = NULL;
|
||||||
|
|
||||||
|
g_object_unref (src);
|
||||||
gst_buffer_default_free (buf);
|
gst_buffer_default_free (buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,7 +383,7 @@ gst_filesrc_map_region (GstFileSrc *src, off_t offset, size_t size)
|
||||||
|
|
||||||
g_return_val_if_fail (offset >= 0, NULL);
|
g_return_val_if_fail (offset >= 0, NULL);
|
||||||
|
|
||||||
fs_print ("mapping region %08llx+%08lx from file into memory\n",offset,(unsigned long)size);
|
GST_LOG_OBJECT (src, "mapping region %08llx+%08lx from file into memory",offset,(unsigned long)size);
|
||||||
mmapregion = mmap (NULL, size, PROT_READ, MAP_SHARED, src->fd, offset);
|
mmapregion = mmap (NULL, size, PROT_READ, MAP_SHARED, src->fd, offset);
|
||||||
|
|
||||||
if (mmapregion == NULL) {
|
if (mmapregion == NULL) {
|
||||||
|
@ -402,11 +391,11 @@ gst_filesrc_map_region (GstFileSrc *src, off_t offset, size_t size)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else if (mmapregion == MAP_FAILED) {
|
else if (mmapregion == MAP_FAILED) {
|
||||||
GST_DEBUG ("mmap (0x%08lx, %d, 0x%llx) : %s",
|
GST_WARNING_OBJECT (src, "mmap (0x%08lx, %d, 0x%llx) failed: %s",
|
||||||
(unsigned long)size, src->fd, offset, strerror (errno));
|
(unsigned long)size, src->fd, offset, strerror (errno));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
GST_DEBUG ( "mapped region %08lx+%08lx from file into memory at %p",
|
GST_LOG_OBJECT (src, "mapped region %08lx+%08lx from file into memory at %p",
|
||||||
(unsigned long)offset, (unsigned long)size, mmapregion);
|
(unsigned long)offset, (unsigned long)size, mmapregion);
|
||||||
|
|
||||||
/* time to allocate a new mapbuf */
|
/* time to allocate a new mapbuf */
|
||||||
|
@ -426,6 +415,7 @@ gst_filesrc_map_region (GstFileSrc *src, off_t offset, size_t size)
|
||||||
GST_BUFFER_OFFSET (buf) = offset;
|
GST_BUFFER_OFFSET (buf) = offset;
|
||||||
GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE;
|
GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE;
|
||||||
GST_BUFFER_POOL_PRIVATE (buf) = src;
|
GST_BUFFER_POOL_PRIVATE (buf) = src;
|
||||||
|
g_object_ref (src);
|
||||||
GST_BUFFER_FREE_FUNC (buf) = (GstDataFreeFunction) gst_filesrc_free_parent_mmap;
|
GST_BUFFER_FREE_FUNC (buf) = (GstDataFreeFunction) gst_filesrc_free_parent_mmap;
|
||||||
|
|
||||||
g_mutex_lock (src->map_regions_lock);
|
g_mutex_lock (src->map_regions_lock);
|
||||||
|
@ -522,7 +512,7 @@ gst_filesrc_get_mmap (GstFileSrc *src)
|
||||||
/* if the end is before the mapend, the buffer is in current mmap region... */
|
/* if the end is before the mapend, the buffer is in current mmap region... */
|
||||||
/* ('cause by definition if readend is in the buffer, so's readstart) */
|
/* ('cause by definition if readend is in the buffer, so's readstart) */
|
||||||
if (readend <= mapend) {
|
if (readend <= mapend) {
|
||||||
fs_print ("read buf %llu+%d lives in current mapbuf %lld+%d, creating subbuffer of mapbuf\n",
|
GST_LOG_OBJECT (src, "read buf %llu+%d lives in current mapbuf %lld+%d, creating subbuffer of mapbuf",
|
||||||
src->curoffset, readsize, mapstart, mapsize);
|
src->curoffset, readsize, mapstart, mapsize);
|
||||||
buf = gst_buffer_create_sub (src->mapbuf, src->curoffset - mapstart,
|
buf = gst_buffer_create_sub (src->mapbuf, src->curoffset - mapstart,
|
||||||
readsize);
|
readsize);
|
||||||
|
@ -530,8 +520,8 @@ gst_filesrc_get_mmap (GstFileSrc *src)
|
||||||
|
|
||||||
/* if the start actually is within the current mmap region, map an overlap buffer */
|
/* if the start actually is within the current mmap region, map an overlap buffer */
|
||||||
} else if (src->curoffset < mapend) {
|
} else if (src->curoffset < mapend) {
|
||||||
fs_print ("read buf %llu+%d starts in mapbuf %d+%d but ends outside, creating new mmap\n",
|
GST_LOG_OBJECT (src, "read buf %llu+%d starts in mapbuf %d+%d but ends outside, creating new mmap",
|
||||||
src->curoffset, readsize, mapstart, mapsize);
|
(unsigned long long) src->curoffset, (gint) readsize, (gint) mapstart, (gint) mapsize);
|
||||||
buf = gst_filesrc_map_small_region (src, src->curoffset, readsize);
|
buf = gst_filesrc_map_small_region (src, src->curoffset, readsize);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -545,8 +535,8 @@ gst_filesrc_get_mmap (GstFileSrc *src)
|
||||||
/* either the read buffer overlaps the start of the mmap region */
|
/* either the read buffer overlaps the start of the mmap region */
|
||||||
/* or the read buffer fully contains the current mmap region */
|
/* or the read buffer fully contains the current mmap region */
|
||||||
/* either way, it's really not relevant, we just create a new region anyway*/
|
/* either way, it's really not relevant, we just create a new region anyway*/
|
||||||
fs_print ("read buf %llu+%d starts before mapbuf %d+%d, but overlaps it\n",
|
GST_LOG_OBJECT (src, "read buf %llu+%d starts before mapbuf %d+%d, but overlaps it",
|
||||||
src->curoffset,readsize, mapstart, mapsize);
|
(unsigned long long) src->curoffset, (gint) readsize, (gint) mapstart, (gint) mapsize);
|
||||||
buf = gst_filesrc_map_small_region (src, src->curoffset, readsize);
|
buf = gst_filesrc_map_small_region (src, src->curoffset, readsize);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -555,7 +545,7 @@ gst_filesrc_get_mmap (GstFileSrc *src)
|
||||||
/* then deal with the case where the read buffer is totally outside */
|
/* then deal with the case where the read buffer is totally outside */
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
/* first check to see if there's a map that covers the right region already */
|
/* first check to see if there's a map that covers the right region already */
|
||||||
fs_print ("searching for mapbuf to cover %llu+%d\n",src->curoffset,readsize);
|
GST_LOG_OBJECT (src, "searching for mapbuf to cover %llu+%d",src->curoffset,readsize);
|
||||||
region.offset = src->curoffset;
|
region.offset = src->curoffset;
|
||||||
region.size = readsize;
|
region.size = readsize;
|
||||||
map = g_tree_search (src->map_regions,
|
map = g_tree_search (src->map_regions,
|
||||||
|
@ -564,7 +554,8 @@ gst_filesrc_get_mmap (GstFileSrc *src)
|
||||||
|
|
||||||
/* if we found an exact match, subbuffer it */
|
/* if we found an exact match, subbuffer it */
|
||||||
if (map != NULL) {
|
if (map != NULL) {
|
||||||
fs_print ("found mapbuf at %d+%d, creating subbuffer\n",GST_BUFFER_OFFSET(map),GST_BUFFER_SIZE(map));
|
GST_LOG_OBJECT (src, "found mapbuf at %"G_GUINT64_FORMAT"+%u, creating subbuffer",
|
||||||
|
GST_BUFFER_OFFSET (map), GST_BUFFER_SIZE (map));
|
||||||
buf = gst_buffer_create_sub (map, src->curoffset - GST_BUFFER_OFFSET(map), readsize);
|
buf = gst_buffer_create_sub (map, src->curoffset - GST_BUFFER_OFFSET(map), readsize);
|
||||||
GST_BUFFER_OFFSET (buf) = src->curoffset;
|
GST_BUFFER_OFFSET (buf) = src->curoffset;
|
||||||
|
|
||||||
|
@ -572,7 +563,7 @@ gst_filesrc_get_mmap (GstFileSrc *src)
|
||||||
} else {
|
} else {
|
||||||
/* if the read buffer crosses a mmap region boundary, create a one-off region */
|
/* if the read buffer crosses a mmap region boundary, create a one-off region */
|
||||||
if ((src->curoffset / src->mapsize) != (readend / src->mapsize)) {
|
if ((src->curoffset / src->mapsize) != (readend / src->mapsize)) {
|
||||||
fs_print ("read buf %llu+%d crosses a %d-byte boundary, creating a one-off\n",
|
GST_LOG_OBJECT (src, "read buf %llu+%d crosses a %d-byte boundary, creating a one-off",
|
||||||
src->curoffset,readsize,src->mapsize);
|
src->curoffset,readsize,src->mapsize);
|
||||||
buf = gst_filesrc_map_small_region (src, src->curoffset, readsize);
|
buf = gst_filesrc_map_small_region (src, src->curoffset, readsize);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
|
@ -583,7 +574,7 @@ gst_filesrc_get_mmap (GstFileSrc *src)
|
||||||
size_t mapsize;
|
size_t mapsize;
|
||||||
|
|
||||||
off_t nextmap = src->curoffset - (src->curoffset % src->mapsize);
|
off_t nextmap = src->curoffset - (src->curoffset % src->mapsize);
|
||||||
fs_print ("read buf %llu+%d in new mapbuf at %llu+%d, mapping and subbuffering\n",
|
GST_LOG_OBJECT (src, "read buf %llu+%d in new mapbuf at %llu+%d, mapping and subbuffering",
|
||||||
src->curoffset, readsize, nextmap, src->mapsize);
|
src->curoffset, readsize, nextmap, src->mapsize);
|
||||||
/* first, we're done with the old mapbuf */
|
/* first, we're done with the old mapbuf */
|
||||||
gst_buffer_unref(src->mapbuf);
|
gst_buffer_unref(src->mapbuf);
|
||||||
|
@ -591,7 +582,7 @@ gst_filesrc_get_mmap (GstFileSrc *src)
|
||||||
|
|
||||||
/* double the mapsize as long as the readsize is smaller */
|
/* double the mapsize as long as the readsize is smaller */
|
||||||
while (readsize - (src->curoffset - nextmap) > mapsize) {
|
while (readsize - (src->curoffset - nextmap) > mapsize) {
|
||||||
fs_print ("readsize smaller then mapsize %08x %d\n", readsize, mapsize);
|
GST_LOG_OBJECT (src, "readsize smaller then mapsize %08x %d", readsize, mapsize);
|
||||||
mapsize <<=1;
|
mapsize <<=1;
|
||||||
}
|
}
|
||||||
/* create a new one */
|
/* create a new one */
|
||||||
|
@ -664,7 +655,7 @@ gst_filesrc_get (GstPad *pad)
|
||||||
GstEvent *event;
|
GstEvent *event;
|
||||||
|
|
||||||
src->seek_happened = FALSE;
|
src->seek_happened = FALSE;
|
||||||
GST_DEBUG ("filesrc sending discont");
|
GST_DEBUG_OBJECT (src, "sending discont");
|
||||||
event = gst_event_new_discontinuous (FALSE, GST_FORMAT_BYTES, src->curoffset, NULL);
|
event = gst_event_new_discontinuous (FALSE, GST_FORMAT_BYTES, src->curoffset, NULL);
|
||||||
src->need_flush = FALSE;
|
src->need_flush = FALSE;
|
||||||
return GST_DATA (event);
|
return GST_DATA (event);
|
||||||
|
@ -672,13 +663,13 @@ gst_filesrc_get (GstPad *pad)
|
||||||
/* check for flush */
|
/* check for flush */
|
||||||
if (src->need_flush) {
|
if (src->need_flush) {
|
||||||
src->need_flush = FALSE;
|
src->need_flush = FALSE;
|
||||||
GST_DEBUG ("filesrc sending flush");
|
GST_DEBUG_OBJECT (src, "sending flush");
|
||||||
return GST_DATA (gst_event_new_flush ());
|
return GST_DATA (gst_event_new_flush ());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check for EOF */
|
/* check for EOF */
|
||||||
if (src->curoffset == src->filelen) {
|
if (src->curoffset == src->filelen) {
|
||||||
GST_DEBUG ("filesrc 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));
|
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
||||||
|
@ -697,7 +688,7 @@ gst_filesrc_open_file (GstFileSrc *src)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (!GST_FLAG_IS_SET (src ,GST_FILESRC_OPEN), FALSE);
|
g_return_val_if_fail (!GST_FLAG_IS_SET (src ,GST_FILESRC_OPEN), FALSE);
|
||||||
|
|
||||||
GST_DEBUG ( "opening file %s",src->filename);
|
GST_INFO_OBJECT (src, "opening file %s",src->filename);
|
||||||
|
|
||||||
/* open the file */
|
/* open the file */
|
||||||
src->fd = open (src->filename, O_RDONLY);
|
src->fd = open (src->filename, O_RDONLY);
|
||||||
|
@ -829,7 +820,7 @@ gst_filesrc_srcpad_event (GstPad *pad, GstEvent *event)
|
||||||
{
|
{
|
||||||
GstFileSrc *src = GST_FILESRC (GST_PAD_PARENT (pad));
|
GstFileSrc *src = GST_FILESRC (GST_PAD_PARENT (pad));
|
||||||
|
|
||||||
GST_DEBUG ( "event %d", GST_EVENT_TYPE (event));
|
GST_DEBUG_OBJECT (src, "event %d", GST_EVENT_TYPE (event));
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
case GST_EVENT_SEEK:
|
case GST_EVENT_SEEK:
|
||||||
|
@ -847,19 +838,19 @@ gst_filesrc_srcpad_event (GstPad *pad, GstEvent *event)
|
||||||
if (offset > src->filelen)
|
if (offset > src->filelen)
|
||||||
goto error;
|
goto error;
|
||||||
src->curoffset = offset;
|
src->curoffset = offset;
|
||||||
GST_DEBUG ( "seek set pending to %" G_GINT64_FORMAT, src->curoffset);
|
GST_DEBUG_OBJECT (src, "seek set pending to %" G_GINT64_FORMAT, src->curoffset);
|
||||||
break;
|
break;
|
||||||
case GST_SEEK_METHOD_CUR:
|
case GST_SEEK_METHOD_CUR:
|
||||||
if (offset + src->curoffset > src->filelen)
|
if (offset + src->curoffset > src->filelen)
|
||||||
goto error;
|
goto error;
|
||||||
src->curoffset += offset;
|
src->curoffset += offset;
|
||||||
GST_DEBUG ( "seek cur pending to %" G_GINT64_FORMAT, src->curoffset);
|
GST_DEBUG_OBJECT (src, "seek cur pending to %" G_GINT64_FORMAT, src->curoffset);
|
||||||
break;
|
break;
|
||||||
case GST_SEEK_METHOD_END:
|
case GST_SEEK_METHOD_END:
|
||||||
if (ABS (offset) > src->filelen)
|
if (ABS (offset) > src->filelen)
|
||||||
goto error;
|
goto error;
|
||||||
src->curoffset = src->filelen - ABS (offset);
|
src->curoffset = src->filelen - ABS (offset);
|
||||||
GST_DEBUG ( "seek end pending to %" G_GINT64_FORMAT, src->curoffset);
|
GST_DEBUG_OBJECT (src, "seek end pending to %" G_GINT64_FORMAT, src->curoffset);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto error;
|
goto error;
|
||||||
|
|
669
plugins/elements/gsttypefind.c
Normal file
669
plugins/elements/gsttypefind.c
Normal file
|
@ -0,0 +1,669 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
|
*
|
||||||
|
* gsttypefind.c: element that detects type of stream
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* FIXME: need a better solution for non-seekable streams */
|
||||||
|
|
||||||
|
/* way of operation:
|
||||||
|
* 1) get a list of all typefind functions sorted best to worst
|
||||||
|
* 2) if all elements have been called with all requested data goto 8
|
||||||
|
* 3) call all functions once with all available data
|
||||||
|
* 4) if a function returns a value >= ARG_MAXIMUM goto 8
|
||||||
|
* 5) all functions with a result > ARG_MINIMUM or functions that did not get
|
||||||
|
* all requested data (where peek returned NULL) stay in list
|
||||||
|
* 6) seek to requested offset of best function that still has open data
|
||||||
|
* requests
|
||||||
|
* 7) goto 2
|
||||||
|
* 8) take best available result and use its caps
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "gsttypefindelement.h"
|
||||||
|
#include "gst/gst_private.h"
|
||||||
|
|
||||||
|
#include <gst/gsttypefind.h>
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY (gst_type_find_element_debug);
|
||||||
|
#define GST_CAT_DEFAULT gst_type_find_element_debug
|
||||||
|
|
||||||
|
GstElementDetails gst_type_find_element_details = {
|
||||||
|
"TypeFind",
|
||||||
|
"Generic",
|
||||||
|
"LGPL",
|
||||||
|
"Finds the media type of a stream",
|
||||||
|
VERSION,
|
||||||
|
"Benjamin Otte <in7y118@public.uni-hamburg.de>",
|
||||||
|
"(C) 2003",
|
||||||
|
};
|
||||||
|
|
||||||
|
/* generic templates */
|
||||||
|
GST_PAD_TEMPLATE_FACTORY (type_find_element_sink_factory,
|
||||||
|
"sink",
|
||||||
|
GST_PAD_SINK,
|
||||||
|
GST_PAD_ALWAYS,
|
||||||
|
GST_CAPS_ANY
|
||||||
|
);
|
||||||
|
GST_PAD_TEMPLATE_FACTORY (type_find_element_src_factory,
|
||||||
|
"src",
|
||||||
|
GST_PAD_SRC,
|
||||||
|
GST_PAD_ALWAYS,
|
||||||
|
GST_CAPS_ANY
|
||||||
|
);
|
||||||
|
|
||||||
|
/* TypeFind signals and args */
|
||||||
|
enum {
|
||||||
|
HAVE_TYPE,
|
||||||
|
LAST_SIGNAL
|
||||||
|
};
|
||||||
|
enum {
|
||||||
|
ARG_0,
|
||||||
|
ARG_CAPS,
|
||||||
|
ARG_MINIMUM,
|
||||||
|
ARG_MAXIMUM
|
||||||
|
};
|
||||||
|
enum {
|
||||||
|
MODE_NORMAL, /* act as identity */
|
||||||
|
MODE_TYPEFIND, /* do typefinding */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void gst_type_find_element_class_init (gpointer g_class,
|
||||||
|
gpointer class_data);
|
||||||
|
static void gst_type_find_element_init (GTypeInstance *instance,
|
||||||
|
gpointer g_class);
|
||||||
|
static void gst_type_find_element_dispose (GObject * object);
|
||||||
|
static void gst_type_find_element_set_property (GObject * object,
|
||||||
|
guint prop_id,
|
||||||
|
const GValue * value,
|
||||||
|
GParamSpec * pspec);
|
||||||
|
static void gst_type_find_element_get_property (GObject * object,
|
||||||
|
guint prop_id,
|
||||||
|
GValue * value,
|
||||||
|
GParamSpec * pspec);
|
||||||
|
|
||||||
|
static const GstEventMask *
|
||||||
|
gst_type_find_element_src_event_mask (GstPad * pad);
|
||||||
|
static gboolean gst_type_find_element_src_event (GstPad * pad,
|
||||||
|
GstEvent * event);
|
||||||
|
|
||||||
|
static void gst_type_find_element_chain (GstPad * sinkpad,
|
||||||
|
GstData * data);
|
||||||
|
static GstElementStateReturn
|
||||||
|
gst_type_find_element_change_state (GstElement * element);
|
||||||
|
|
||||||
|
static GstElementClass *parent_class = NULL;
|
||||||
|
static guint gst_type_find_element_signals[LAST_SIGNAL] = { 0 };
|
||||||
|
|
||||||
|
GType
|
||||||
|
gst_type_find_element_get_type (void)
|
||||||
|
{
|
||||||
|
static GType typefind_type = 0;
|
||||||
|
|
||||||
|
if (!typefind_type) {
|
||||||
|
static const GTypeInfo typefind_info = {
|
||||||
|
sizeof (GstTypeFindElementClass),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
gst_type_find_element_class_init,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
sizeof (GstTypeFindElement),
|
||||||
|
0,
|
||||||
|
gst_type_find_element_init,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
typefind_type = g_type_register_static (GST_TYPE_ELEMENT,
|
||||||
|
"GstTypeFindElement",
|
||||||
|
&typefind_info, 0);
|
||||||
|
}
|
||||||
|
return typefind_type;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_have_type (GstTypeFindElement *typefind, guint probability, GstCaps *caps)
|
||||||
|
{
|
||||||
|
gchar *caps_str;
|
||||||
|
|
||||||
|
g_assert (typefind->caps == NULL);
|
||||||
|
g_assert (caps != NULL);
|
||||||
|
|
||||||
|
caps_str = gst_caps_to_string (caps);
|
||||||
|
GST_INFO_OBJECT (typefind, "found caps %s", caps_str);
|
||||||
|
g_free (caps_str);
|
||||||
|
gst_caps_replace (&typefind->caps, caps);
|
||||||
|
if (gst_pad_try_set_caps (typefind->src, caps) < GST_PAD_LINK_OK) {
|
||||||
|
gst_element_error (GST_ELEMENT (typefind), "could not set caps on source pad");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_class_init (gpointer g_class, gpointer class_data)
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class;
|
||||||
|
GstElementClass *gstelement_class;
|
||||||
|
GstTypeFindElementClass *typefind_class;
|
||||||
|
|
||||||
|
gobject_class = G_OBJECT_CLASS (g_class);
|
||||||
|
gstelement_class = GST_ELEMENT_CLASS (g_class);
|
||||||
|
typefind_class = GST_TYPE_FIND_ELEMENT_CLASS (g_class);
|
||||||
|
|
||||||
|
parent_class = g_type_class_peek_parent (g_class);
|
||||||
|
|
||||||
|
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_type_find_element_set_property);
|
||||||
|
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_type_find_element_get_property);
|
||||||
|
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_type_find_element_dispose);
|
||||||
|
|
||||||
|
typefind_class->have_type = gst_type_find_element_have_type;
|
||||||
|
|
||||||
|
g_object_class_install_property (gobject_class, ARG_CAPS,
|
||||||
|
g_param_spec_boxed ("caps", _("caps"), _("detected capabilities in stream"),
|
||||||
|
GST_TYPE_CAPS, G_PARAM_READABLE));
|
||||||
|
g_object_class_install_property (gobject_class, ARG_MINIMUM,
|
||||||
|
g_param_spec_uint ("minimum", _("minimum"), "minimum probability required to accept caps",
|
||||||
|
GST_TYPE_FIND_MINIMUM, GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MINIMUM, G_PARAM_READWRITE));
|
||||||
|
g_object_class_install_property (gobject_class, ARG_MINIMUM,
|
||||||
|
g_param_spec_uint ("maximum", _("maximum"), "probability to stop typefinding",
|
||||||
|
GST_TYPE_FIND_MINIMUM, GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MAXIMUM, G_PARAM_READWRITE));
|
||||||
|
|
||||||
|
gst_type_find_element_signals[HAVE_TYPE] = g_signal_new ("have_type",
|
||||||
|
G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_LAST,
|
||||||
|
G_STRUCT_OFFSET (GstTypeFindElementClass, have_type), NULL, NULL,
|
||||||
|
gst_marshal_VOID__UINT_BOXED, G_TYPE_NONE, 2,
|
||||||
|
G_TYPE_UINT, GST_TYPE_CAPS);
|
||||||
|
|
||||||
|
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_type_find_element_change_state);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_init (GTypeInstance *instance, gpointer g_class)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (instance);
|
||||||
|
|
||||||
|
/* sinkpad */
|
||||||
|
typefind->sink = gst_pad_new_from_template (
|
||||||
|
GST_PAD_TEMPLATE_GET (type_find_element_sink_factory), "sink");
|
||||||
|
gst_pad_set_chain_function (typefind->sink,
|
||||||
|
gst_type_find_element_chain);
|
||||||
|
gst_element_add_pad (GST_ELEMENT (typefind), typefind->sink);
|
||||||
|
/* srcpad */
|
||||||
|
typefind->src = gst_pad_new_from_template (
|
||||||
|
GST_PAD_TEMPLATE_GET (type_find_element_src_factory), "src");
|
||||||
|
gst_pad_set_event_function (typefind->src, gst_type_find_element_src_event);
|
||||||
|
gst_pad_set_event_mask_function (typefind->src, gst_type_find_element_src_event_mask);
|
||||||
|
gst_element_add_pad (GST_ELEMENT (typefind), typefind->src);
|
||||||
|
|
||||||
|
typefind->caps = NULL;
|
||||||
|
typefind->min_probability = 1;
|
||||||
|
typefind->max_probability = GST_TYPE_FIND_MAXIMUM;
|
||||||
|
|
||||||
|
typefind->store = gst_buffer_store_new ();
|
||||||
|
|
||||||
|
GST_FLAG_SET (typefind, GST_ELEMENT_EVENT_AWARE);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_dispose (GObject *object)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (object);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||||
|
|
||||||
|
if (typefind->store) {
|
||||||
|
g_object_unref (typefind->store);
|
||||||
|
typefind->store = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_set_property (GObject *object, guint prop_id,
|
||||||
|
const GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind;
|
||||||
|
|
||||||
|
g_return_if_fail (GST_IS_TYPE_FIND_ELEMENT (object));
|
||||||
|
|
||||||
|
typefind = GST_TYPE_FIND_ELEMENT (object);
|
||||||
|
|
||||||
|
switch (prop_id) {
|
||||||
|
case ARG_MINIMUM:
|
||||||
|
typefind->min_probability = g_value_get_uint (value);
|
||||||
|
g_object_notify (object, "minimum");
|
||||||
|
break;
|
||||||
|
case ARG_MAXIMUM:
|
||||||
|
typefind->max_probability = g_value_get_uint (value);
|
||||||
|
g_object_notify (object, "maximum");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_get_property (GObject *object, guint prop_id,
|
||||||
|
GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind;
|
||||||
|
|
||||||
|
g_return_if_fail (GST_IS_TYPE_FIND_ELEMENT (object));
|
||||||
|
|
||||||
|
typefind = GST_TYPE_FIND_ELEMENT (object);
|
||||||
|
|
||||||
|
switch (prop_id) {
|
||||||
|
case ARG_CAPS:
|
||||||
|
g_value_set_boxed (value, typefind->caps);
|
||||||
|
break;
|
||||||
|
case ARG_MINIMUM:
|
||||||
|
g_value_set_uint (value, typefind->min_probability);
|
||||||
|
break;
|
||||||
|
case ARG_MAXIMUM:
|
||||||
|
g_value_set_uint (value, typefind->max_probability);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static const GstEventMask *
|
||||||
|
gst_type_find_element_src_event_mask (GstPad *pad)
|
||||||
|
{
|
||||||
|
static const GstEventMask mask[] = {
|
||||||
|
{ GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_END | GST_SEEK_FLAG_FLUSH},
|
||||||
|
/* add more if you want, event masks suck and need to die anyway */
|
||||||
|
{ 0, }
|
||||||
|
};
|
||||||
|
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
static gboolean
|
||||||
|
gst_type_find_element_src_event (GstPad *pad, GstEvent *event)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
|
||||||
|
|
||||||
|
if (typefind->mode == MODE_TYPEFIND) {
|
||||||
|
/* need to do more? */
|
||||||
|
gst_data_unref (GST_DATA (event));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return gst_pad_event_default (pad, event);
|
||||||
|
}
|
||||||
|
typedef struct {
|
||||||
|
GstTypeFindFactory * factory;
|
||||||
|
gint probability;
|
||||||
|
GstCaps * caps;
|
||||||
|
gint64 requested_offset;
|
||||||
|
guint requested_size;
|
||||||
|
|
||||||
|
GList * buffers;
|
||||||
|
GstTypeFindElement * self;
|
||||||
|
} TypeFindEntry;
|
||||||
|
static void
|
||||||
|
free_entry_buffers (TypeFindEntry *entry)
|
||||||
|
{
|
||||||
|
g_list_foreach (entry->buffers, (GFunc) gst_data_unref, NULL);
|
||||||
|
g_list_free (entry->buffers);
|
||||||
|
entry->buffers = NULL;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
free_entry (TypeFindEntry *entry)
|
||||||
|
{
|
||||||
|
free_entry_buffers (entry);
|
||||||
|
|
||||||
|
if (entry->caps)
|
||||||
|
gst_caps_unref (entry->caps);
|
||||||
|
g_free (entry);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
start_typefinding (GstTypeFindElement *typefind)
|
||||||
|
{
|
||||||
|
g_assert (typefind->caps == NULL);
|
||||||
|
g_assert (typefind->possibilities == NULL);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (typefind, "starting typefinding");
|
||||||
|
typefind->mode = MODE_TYPEFIND;
|
||||||
|
typefind->stream_length_available = TRUE;
|
||||||
|
typefind->stream_length = 0;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
stop_typefinding (GstTypeFindElement *typefind)
|
||||||
|
{
|
||||||
|
/* stop all typefinding and set mode back to normal */
|
||||||
|
gboolean push_cached_buffers = gst_element_get_state (GST_ELEMENT (typefind)) == GST_STATE_PLAYING;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (typefind, "stopping typefinding%s", push_cached_buffers ? " and pushing cached buffers" : "");
|
||||||
|
if (typefind->possibilities != NULL) {
|
||||||
|
/* this should only happen on PAUSED => READY or EOS */
|
||||||
|
GST_LOG_OBJECT (typefind, "freeing remaining %u typefind functions", g_list_length (typefind->possibilities));
|
||||||
|
g_list_foreach (typefind->possibilities, (GFunc) free_entry, NULL);
|
||||||
|
g_list_free (typefind->possibilities);
|
||||||
|
typefind->possibilities = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
typefind->mode = MODE_NORMAL;
|
||||||
|
|
||||||
|
if (push_cached_buffers) {
|
||||||
|
GstBuffer *buffer;
|
||||||
|
guint size = gst_buffer_store_get_size (typefind->store, 0);
|
||||||
|
if (size && (buffer = gst_buffer_store_get_buffer (typefind->store, 0, size))) {
|
||||||
|
gst_pad_push (typefind->src, GST_DATA (buffer));
|
||||||
|
} else {
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
GST_LOG_OBJECT (typefind, "seeking back to current position %u", size);
|
||||||
|
if (!gst_pad_send_event (GST_PAD_PEER (typefind->sink),
|
||||||
|
gst_event_new_seek (GST_SEEK_METHOD_SET | GST_FORMAT_BYTES, size))) {
|
||||||
|
GST_WARNING_OBJECT (typefind, "could not seek to required position %u, hope for the best", size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gst_buffer_store_clear (typefind->store);
|
||||||
|
}
|
||||||
|
static guint64
|
||||||
|
find_element_get_length (gpointer data)
|
||||||
|
{
|
||||||
|
TypeFindEntry *entry = (TypeFindEntry *) data;
|
||||||
|
GstTypeFindElement *typefind = entry->self;
|
||||||
|
GstFormat format = GST_FORMAT_BYTES;
|
||||||
|
|
||||||
|
if (!typefind->stream_length_available) {
|
||||||
|
GST_LOG_OBJECT (entry->self, "'%s' called get_length () but we know it's not available",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (entry->self->stream_length == 0) {
|
||||||
|
typefind->stream_length_available = gst_pad_query (GST_PAD_PEER (entry->self->sink), GST_QUERY_TOTAL,
|
||||||
|
&format, &entry->self->stream_length);
|
||||||
|
if (format != GST_FORMAT_BYTES)
|
||||||
|
typefind->stream_length_available = FALSE;
|
||||||
|
if (!typefind->stream_length_available) {
|
||||||
|
GST_DEBUG_OBJECT (entry->self, "'%s' called get_length () but it's not available",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory));
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
GST_DEBUG_OBJECT (entry->self, "'%s' called get_length () and it's %"G_GUINT64_FORMAT" bytes",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), entry->self->stream_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry->self->stream_length;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_handle_event (GstPad *pad, GstEvent *event)
|
||||||
|
{
|
||||||
|
TypeFindEntry *entry;
|
||||||
|
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
|
||||||
|
|
||||||
|
if (typefind->mode == MODE_TYPEFIND) {
|
||||||
|
/* need to do more? */
|
||||||
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_EOS:
|
||||||
|
/* this should only happen when we got all available data */
|
||||||
|
entry = (TypeFindEntry *) typefind->possibilities ? typefind->possibilities->data : NULL;
|
||||||
|
if (entry && entry->probability >= typefind->min_probability) {
|
||||||
|
GST_INFO_OBJECT (typefind, "'%s' is the best typefind left after we got all data, using it now (probability %u)",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), entry->probability);
|
||||||
|
g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0, entry->probability, entry->caps);
|
||||||
|
}
|
||||||
|
stop_typefinding (typefind);
|
||||||
|
gst_pad_event_default (pad, event);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
gst_data_unref (GST_DATA (event));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
gst_pad_event_default (pad, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static guint8 *
|
||||||
|
find_peek (gpointer data, gint64 offset, guint size)
|
||||||
|
{
|
||||||
|
GstBuffer *buf;
|
||||||
|
TypeFindEntry *entry = (TypeFindEntry *) data;
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (entry->self, "'%s' called peek (%"G_GINT64_FORMAT", %u)",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), offset, size);
|
||||||
|
if (offset >= 0) {
|
||||||
|
buf = gst_buffer_store_get_buffer (entry->self->store, offset, size);
|
||||||
|
} else {
|
||||||
|
/* FIXME: can we do this easily without querying length? */
|
||||||
|
guint64 length = find_element_get_length (data);
|
||||||
|
|
||||||
|
if (length == 0) {
|
||||||
|
buf = NULL;
|
||||||
|
} else {
|
||||||
|
buf = gst_buffer_store_get_buffer (entry->self->store, length + offset, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf) {
|
||||||
|
entry->buffers = g_list_prepend (entry->buffers, buf);
|
||||||
|
return GST_BUFFER_DATA (buf);
|
||||||
|
} else {
|
||||||
|
if (entry->requested_size == 0) {
|
||||||
|
GST_LOG_OBJECT (entry->self, "setting requested peek (%"G_GINT64_FORMAT", %u) on '%s'",
|
||||||
|
offset, size, GST_PLUGIN_FEATURE_NAME (entry->factory));
|
||||||
|
entry->requested_offset = offset;
|
||||||
|
entry->requested_size = size;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
find_suggest (gpointer data, guint probability, GstCaps *caps)
|
||||||
|
{
|
||||||
|
gchar *str;
|
||||||
|
TypeFindEntry *entry = (TypeFindEntry *) data;
|
||||||
|
|
||||||
|
str = gst_caps_to_string (caps);
|
||||||
|
GST_LOG_OBJECT (entry->self, "'%s' called suggest (%u, %s)",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), probability, str);
|
||||||
|
g_free (str);
|
||||||
|
if (((gint) probability) > entry->probability) {
|
||||||
|
entry->probability = probability;
|
||||||
|
gst_caps_replace (&entry->caps, caps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static gint
|
||||||
|
compare_type_find_entry (gconstpointer a, gconstpointer b)
|
||||||
|
{
|
||||||
|
TypeFindEntry *one = (TypeFindEntry *) a;
|
||||||
|
TypeFindEntry *two = (TypeFindEntry *) b;
|
||||||
|
|
||||||
|
if (one->probability == two->probability) {
|
||||||
|
/* FIXME: can be improved by analyzing requests */
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return two->probability - one->probability;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static gint
|
||||||
|
compare_type_find_factory (gconstpointer fac1, gconstpointer fac2)
|
||||||
|
{
|
||||||
|
return GST_PLUGIN_FEATURE (fac1)->rank - GST_PLUGIN_FEATURE (fac2)->rank;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_chain (GstPad *pad, GstData *data)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind;
|
||||||
|
GList *entries;
|
||||||
|
TypeFindEntry *entry;
|
||||||
|
GList *walk;
|
||||||
|
GstTypeFind find = {find_peek, find_suggest, NULL, find_element_get_length };
|
||||||
|
|
||||||
|
typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
|
||||||
|
if (GST_IS_EVENT (data)) {
|
||||||
|
gst_type_find_element_handle_event (pad, GST_EVENT (data));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (typefind->mode) {
|
||||||
|
case MODE_NORMAL:
|
||||||
|
gst_pad_push (typefind->src, data);
|
||||||
|
return;
|
||||||
|
case MODE_TYPEFIND: {
|
||||||
|
gst_buffer_store_add_buffer (typefind->store, GST_BUFFER (data));
|
||||||
|
gst_data_unref (data);
|
||||||
|
if (typefind->possibilities == NULL) {
|
||||||
|
/* not yet started, get all typefinding functions into our "queue" */
|
||||||
|
GList *all_factories = gst_type_find_factory_get_list ();
|
||||||
|
GST_INFO_OBJECT (typefind, "starting with %u typefinding functions",
|
||||||
|
g_list_length ((GList *) all_factories));
|
||||||
|
|
||||||
|
all_factories = g_list_sort (all_factories, compare_type_find_factory);
|
||||||
|
walk = all_factories;
|
||||||
|
while (all_factories) {
|
||||||
|
entry = g_new0 (TypeFindEntry, 1);
|
||||||
|
|
||||||
|
entry->factory = GST_TYPE_FIND_FACTORY (all_factories->data);
|
||||||
|
entry->self = typefind;
|
||||||
|
entry->probability = 0;
|
||||||
|
typefind->possibilities = g_list_prepend (typefind->possibilities, entry);
|
||||||
|
all_factories = g_list_next (all_factories);
|
||||||
|
}
|
||||||
|
g_list_free (all_factories);
|
||||||
|
}
|
||||||
|
/* call every typefind function once */
|
||||||
|
walk = entries = typefind->possibilities;
|
||||||
|
GST_INFO_OBJECT (typefind, "iterating %u typefinding functions", g_list_length (entries));
|
||||||
|
typefind->possibilities = NULL;
|
||||||
|
while (walk) {
|
||||||
|
find.data = entry = (TypeFindEntry *) walk->data;
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
entry->probability = 0;
|
||||||
|
entry->requested_offset = 0;
|
||||||
|
entry->requested_size = 0;
|
||||||
|
gst_type_find_factory_call_function (entry->factory, &find);
|
||||||
|
free_entry_buffers (entry);
|
||||||
|
if (entry->probability == 0 && entry->requested_size == 0) {
|
||||||
|
GST_DEBUG_OBJECT (typefind, "'%s' was removed - no chance of being the right plugin",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory));
|
||||||
|
free_entry (entry);
|
||||||
|
} else if (entry->probability >= typefind->max_probability) {
|
||||||
|
/* wooha, got caps */
|
||||||
|
GstCaps *found_caps = entry->caps;
|
||||||
|
guint probability = entry->probability;
|
||||||
|
|
||||||
|
gst_caps_ref (found_caps);
|
||||||
|
GST_INFO_OBJECT (typefind, "'%s' returned %u/%u probability, using it NOW",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), probability, typefind->max_probability);
|
||||||
|
while (walk) {
|
||||||
|
free_entry ((TypeFindEntry *) walk->data);
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
}
|
||||||
|
walk = typefind->possibilities;
|
||||||
|
while (walk) {
|
||||||
|
free_entry (walk->data);
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
}
|
||||||
|
typefind->possibilities = NULL;
|
||||||
|
g_list_free (typefind->possibilities);
|
||||||
|
g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0, probability, found_caps);
|
||||||
|
gst_caps_unref (found_caps);
|
||||||
|
} else {
|
||||||
|
typefind->possibilities = g_list_prepend (typefind->possibilities, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_list_free (entries);
|
||||||
|
/* we may now already have caps or we might be left without functions to try */
|
||||||
|
if (typefind->caps) {
|
||||||
|
stop_typefinding (typefind);
|
||||||
|
} else if (typefind->possibilities == NULL) {
|
||||||
|
gst_element_error (GST_ELEMENT (typefind), "media type could not be detected");
|
||||||
|
} else {
|
||||||
|
/* set up typefind element for next iteration */
|
||||||
|
typefind->possibilities = g_list_sort (typefind->possibilities, compare_type_find_entry);
|
||||||
|
|
||||||
|
walk = typefind->possibilities;
|
||||||
|
while (walk) {
|
||||||
|
entry = (TypeFindEntry *) walk->data;
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
if (entry->requested_size > 0) {
|
||||||
|
/* FIXME: need heuristic to find out if we should seek */
|
||||||
|
gint64 seek_offset;
|
||||||
|
GstEvent *event;
|
||||||
|
|
||||||
|
seek_offset = entry->requested_offset > 0 ? entry->requested_offset :
|
||||||
|
find_element_get_length (entry) + entry->requested_offset;
|
||||||
|
seek_offset += gst_buffer_store_get_size (typefind->store, seek_offset);
|
||||||
|
event = gst_event_new_seek (GST_FORMAT_BYTES | GST_SEEK_METHOD_SET, seek_offset);
|
||||||
|
if (gst_pad_send_event (GST_PAD_PEER (typefind->sink), event)) {
|
||||||
|
/* done seeking */
|
||||||
|
GST_DEBUG_OBJECT (typefind, "'%s' was reset - seeked to %"G_GINT64_FORMAT,
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), seek_offset);
|
||||||
|
break;
|
||||||
|
} else if (entry->requested_offset < 0) {
|
||||||
|
/* impossible to seek */
|
||||||
|
GST_DEBUG_OBJECT (typefind, "'%s' was reset - couldn't seek to %"G_GINT64_FORMAT,
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), seek_offset);
|
||||||
|
entry->requested_size = 0;
|
||||||
|
entry->requested_offset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* throw out all entries that can't get more data */
|
||||||
|
walk = g_list_next (typefind->possibilities);
|
||||||
|
while (walk) {
|
||||||
|
GList *cur = walk;
|
||||||
|
entry = (TypeFindEntry *) walk->data;
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
if (entry->requested_size == 0) {
|
||||||
|
GST_DEBUG_OBJECT (typefind, "'%s' was removed - higher possibilities available",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory));
|
||||||
|
free_entry (entry);
|
||||||
|
typefind->possibilities = g_list_delete_link (typefind->possibilities, cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (g_list_next (typefind->possibilities) == NULL) {
|
||||||
|
entry = (TypeFindEntry *) typefind->possibilities->data;
|
||||||
|
if (entry->probability > typefind->min_probability) {
|
||||||
|
GST_INFO_OBJECT (typefind, "'%s' is the only typefind left, using it now (probability %u)",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), entry->probability);
|
||||||
|
g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0, entry->probability, entry->caps);
|
||||||
|
free_entry (entry);
|
||||||
|
g_list_free (typefind->possibilities);
|
||||||
|
typefind->possibilities = NULL;
|
||||||
|
stop_typefinding (typefind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static GstElementStateReturn
|
||||||
|
gst_type_find_element_change_state (GstElement *element)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind;
|
||||||
|
|
||||||
|
typefind = GST_TYPE_FIND_ELEMENT (element);
|
||||||
|
|
||||||
|
switch (GST_STATE_TRANSITION (element)) {
|
||||||
|
case GST_STATE_READY_TO_PAUSED:
|
||||||
|
start_typefinding (typefind);
|
||||||
|
break;
|
||||||
|
case GST_STATE_PAUSED_TO_READY:
|
||||||
|
stop_typefinding (typefind);
|
||||||
|
gst_caps_replace (&typefind->caps, NULL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||||
|
}
|
78
plugins/elements/gsttypefind.h
Normal file
78
plugins/elements/gsttypefind.h
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
|
*
|
||||||
|
* gsttypefind.h: element that detects type of stream
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __GST_TYPE_FIND_ELEMENT_H__
|
||||||
|
#define __GST_TYPE_FIND_ELEMENT_H__
|
||||||
|
|
||||||
|
#include <gst/gstinfo.h>
|
||||||
|
#include <gst/gstelement.h>
|
||||||
|
/* #include <gst/gstbufferstore.h> */
|
||||||
|
#include "gstbufferstore.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_EXTERN(gst_type_find_element_debug);
|
||||||
|
|
||||||
|
extern GstElementDetails gst_type_find_element_details;
|
||||||
|
|
||||||
|
#define GST_TYPE_TYPE_FIND_ELEMENT (gst_type_find_element_get_type ())
|
||||||
|
#define GST_TYPE_FIND_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TYPE_FIND_ELEMENT, GstTypeFindElement))
|
||||||
|
#define GST_IS_TYPE_FIND_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TYPE_FIND_ELEMENT))
|
||||||
|
#define GST_TYPE_FIND_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_TYPE_FIND_ELEMENT, GstTypeFindElementClass))
|
||||||
|
#define GST_IS_TYPE_FIND_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_TYPE_FIND_ELEMENT))
|
||||||
|
#define GST_TYPE_FIND_ELEMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_TYPE_FIND_ELEMENT, GstTypeFindElementClass))
|
||||||
|
|
||||||
|
typedef struct _GstTypeFindElement GstTypeFindElement;
|
||||||
|
typedef struct _GstTypeFindElementClass GstTypeFindElementClass;
|
||||||
|
|
||||||
|
struct _GstTypeFindElement {
|
||||||
|
GstElement element;
|
||||||
|
|
||||||
|
GstPad * sink;
|
||||||
|
GstPad * src;
|
||||||
|
|
||||||
|
guint min_probability;
|
||||||
|
guint max_probability;
|
||||||
|
GstCaps * caps;
|
||||||
|
|
||||||
|
guint mode;
|
||||||
|
GstBufferStore * store;
|
||||||
|
guint64 stream_length;
|
||||||
|
gboolean stream_length_available;
|
||||||
|
|
||||||
|
GList * possibilities;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GstTypeFindElementClass {
|
||||||
|
GstElementClass parent_class;
|
||||||
|
|
||||||
|
/* signals */
|
||||||
|
void (*have_type) (GstTypeFindElement *element,
|
||||||
|
guint probability,
|
||||||
|
GstCaps * caps);
|
||||||
|
};
|
||||||
|
|
||||||
|
GType gst_type_find_element_get_type (void);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __GST_TYPE_FIND_ELEMENT_H__ */
|
669
plugins/elements/gsttypefindelement.c
Normal file
669
plugins/elements/gsttypefindelement.c
Normal file
|
@ -0,0 +1,669 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
|
*
|
||||||
|
* gsttypefind.c: element that detects type of stream
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* FIXME: need a better solution for non-seekable streams */
|
||||||
|
|
||||||
|
/* way of operation:
|
||||||
|
* 1) get a list of all typefind functions sorted best to worst
|
||||||
|
* 2) if all elements have been called with all requested data goto 8
|
||||||
|
* 3) call all functions once with all available data
|
||||||
|
* 4) if a function returns a value >= ARG_MAXIMUM goto 8
|
||||||
|
* 5) all functions with a result > ARG_MINIMUM or functions that did not get
|
||||||
|
* all requested data (where peek returned NULL) stay in list
|
||||||
|
* 6) seek to requested offset of best function that still has open data
|
||||||
|
* requests
|
||||||
|
* 7) goto 2
|
||||||
|
* 8) take best available result and use its caps
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "gsttypefindelement.h"
|
||||||
|
#include "gst/gst_private.h"
|
||||||
|
|
||||||
|
#include <gst/gsttypefind.h>
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY (gst_type_find_element_debug);
|
||||||
|
#define GST_CAT_DEFAULT gst_type_find_element_debug
|
||||||
|
|
||||||
|
GstElementDetails gst_type_find_element_details = {
|
||||||
|
"TypeFind",
|
||||||
|
"Generic",
|
||||||
|
"LGPL",
|
||||||
|
"Finds the media type of a stream",
|
||||||
|
VERSION,
|
||||||
|
"Benjamin Otte <in7y118@public.uni-hamburg.de>",
|
||||||
|
"(C) 2003",
|
||||||
|
};
|
||||||
|
|
||||||
|
/* generic templates */
|
||||||
|
GST_PAD_TEMPLATE_FACTORY (type_find_element_sink_factory,
|
||||||
|
"sink",
|
||||||
|
GST_PAD_SINK,
|
||||||
|
GST_PAD_ALWAYS,
|
||||||
|
GST_CAPS_ANY
|
||||||
|
);
|
||||||
|
GST_PAD_TEMPLATE_FACTORY (type_find_element_src_factory,
|
||||||
|
"src",
|
||||||
|
GST_PAD_SRC,
|
||||||
|
GST_PAD_ALWAYS,
|
||||||
|
GST_CAPS_ANY
|
||||||
|
);
|
||||||
|
|
||||||
|
/* TypeFind signals and args */
|
||||||
|
enum {
|
||||||
|
HAVE_TYPE,
|
||||||
|
LAST_SIGNAL
|
||||||
|
};
|
||||||
|
enum {
|
||||||
|
ARG_0,
|
||||||
|
ARG_CAPS,
|
||||||
|
ARG_MINIMUM,
|
||||||
|
ARG_MAXIMUM
|
||||||
|
};
|
||||||
|
enum {
|
||||||
|
MODE_NORMAL, /* act as identity */
|
||||||
|
MODE_TYPEFIND, /* do typefinding */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void gst_type_find_element_class_init (gpointer g_class,
|
||||||
|
gpointer class_data);
|
||||||
|
static void gst_type_find_element_init (GTypeInstance *instance,
|
||||||
|
gpointer g_class);
|
||||||
|
static void gst_type_find_element_dispose (GObject * object);
|
||||||
|
static void gst_type_find_element_set_property (GObject * object,
|
||||||
|
guint prop_id,
|
||||||
|
const GValue * value,
|
||||||
|
GParamSpec * pspec);
|
||||||
|
static void gst_type_find_element_get_property (GObject * object,
|
||||||
|
guint prop_id,
|
||||||
|
GValue * value,
|
||||||
|
GParamSpec * pspec);
|
||||||
|
|
||||||
|
static const GstEventMask *
|
||||||
|
gst_type_find_element_src_event_mask (GstPad * pad);
|
||||||
|
static gboolean gst_type_find_element_src_event (GstPad * pad,
|
||||||
|
GstEvent * event);
|
||||||
|
|
||||||
|
static void gst_type_find_element_chain (GstPad * sinkpad,
|
||||||
|
GstData * data);
|
||||||
|
static GstElementStateReturn
|
||||||
|
gst_type_find_element_change_state (GstElement * element);
|
||||||
|
|
||||||
|
static GstElementClass *parent_class = NULL;
|
||||||
|
static guint gst_type_find_element_signals[LAST_SIGNAL] = { 0 };
|
||||||
|
|
||||||
|
GType
|
||||||
|
gst_type_find_element_get_type (void)
|
||||||
|
{
|
||||||
|
static GType typefind_type = 0;
|
||||||
|
|
||||||
|
if (!typefind_type) {
|
||||||
|
static const GTypeInfo typefind_info = {
|
||||||
|
sizeof (GstTypeFindElementClass),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
gst_type_find_element_class_init,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
sizeof (GstTypeFindElement),
|
||||||
|
0,
|
||||||
|
gst_type_find_element_init,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
typefind_type = g_type_register_static (GST_TYPE_ELEMENT,
|
||||||
|
"GstTypeFindElement",
|
||||||
|
&typefind_info, 0);
|
||||||
|
}
|
||||||
|
return typefind_type;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_have_type (GstTypeFindElement *typefind, guint probability, GstCaps *caps)
|
||||||
|
{
|
||||||
|
gchar *caps_str;
|
||||||
|
|
||||||
|
g_assert (typefind->caps == NULL);
|
||||||
|
g_assert (caps != NULL);
|
||||||
|
|
||||||
|
caps_str = gst_caps_to_string (caps);
|
||||||
|
GST_INFO_OBJECT (typefind, "found caps %s", caps_str);
|
||||||
|
g_free (caps_str);
|
||||||
|
gst_caps_replace (&typefind->caps, caps);
|
||||||
|
if (gst_pad_try_set_caps (typefind->src, caps) < GST_PAD_LINK_OK) {
|
||||||
|
gst_element_error (GST_ELEMENT (typefind), "could not set caps on source pad");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_class_init (gpointer g_class, gpointer class_data)
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class;
|
||||||
|
GstElementClass *gstelement_class;
|
||||||
|
GstTypeFindElementClass *typefind_class;
|
||||||
|
|
||||||
|
gobject_class = G_OBJECT_CLASS (g_class);
|
||||||
|
gstelement_class = GST_ELEMENT_CLASS (g_class);
|
||||||
|
typefind_class = GST_TYPE_FIND_ELEMENT_CLASS (g_class);
|
||||||
|
|
||||||
|
parent_class = g_type_class_peek_parent (g_class);
|
||||||
|
|
||||||
|
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_type_find_element_set_property);
|
||||||
|
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_type_find_element_get_property);
|
||||||
|
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_type_find_element_dispose);
|
||||||
|
|
||||||
|
typefind_class->have_type = gst_type_find_element_have_type;
|
||||||
|
|
||||||
|
g_object_class_install_property (gobject_class, ARG_CAPS,
|
||||||
|
g_param_spec_boxed ("caps", _("caps"), _("detected capabilities in stream"),
|
||||||
|
GST_TYPE_CAPS, G_PARAM_READABLE));
|
||||||
|
g_object_class_install_property (gobject_class, ARG_MINIMUM,
|
||||||
|
g_param_spec_uint ("minimum", _("minimum"), "minimum probability required to accept caps",
|
||||||
|
GST_TYPE_FIND_MINIMUM, GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MINIMUM, G_PARAM_READWRITE));
|
||||||
|
g_object_class_install_property (gobject_class, ARG_MINIMUM,
|
||||||
|
g_param_spec_uint ("maximum", _("maximum"), "probability to stop typefinding",
|
||||||
|
GST_TYPE_FIND_MINIMUM, GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MAXIMUM, G_PARAM_READWRITE));
|
||||||
|
|
||||||
|
gst_type_find_element_signals[HAVE_TYPE] = g_signal_new ("have_type",
|
||||||
|
G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_LAST,
|
||||||
|
G_STRUCT_OFFSET (GstTypeFindElementClass, have_type), NULL, NULL,
|
||||||
|
gst_marshal_VOID__UINT_BOXED, G_TYPE_NONE, 2,
|
||||||
|
G_TYPE_UINT, GST_TYPE_CAPS);
|
||||||
|
|
||||||
|
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_type_find_element_change_state);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_init (GTypeInstance *instance, gpointer g_class)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (instance);
|
||||||
|
|
||||||
|
/* sinkpad */
|
||||||
|
typefind->sink = gst_pad_new_from_template (
|
||||||
|
GST_PAD_TEMPLATE_GET (type_find_element_sink_factory), "sink");
|
||||||
|
gst_pad_set_chain_function (typefind->sink,
|
||||||
|
gst_type_find_element_chain);
|
||||||
|
gst_element_add_pad (GST_ELEMENT (typefind), typefind->sink);
|
||||||
|
/* srcpad */
|
||||||
|
typefind->src = gst_pad_new_from_template (
|
||||||
|
GST_PAD_TEMPLATE_GET (type_find_element_src_factory), "src");
|
||||||
|
gst_pad_set_event_function (typefind->src, gst_type_find_element_src_event);
|
||||||
|
gst_pad_set_event_mask_function (typefind->src, gst_type_find_element_src_event_mask);
|
||||||
|
gst_element_add_pad (GST_ELEMENT (typefind), typefind->src);
|
||||||
|
|
||||||
|
typefind->caps = NULL;
|
||||||
|
typefind->min_probability = 1;
|
||||||
|
typefind->max_probability = GST_TYPE_FIND_MAXIMUM;
|
||||||
|
|
||||||
|
typefind->store = gst_buffer_store_new ();
|
||||||
|
|
||||||
|
GST_FLAG_SET (typefind, GST_ELEMENT_EVENT_AWARE);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_dispose (GObject *object)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (object);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||||
|
|
||||||
|
if (typefind->store) {
|
||||||
|
g_object_unref (typefind->store);
|
||||||
|
typefind->store = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_set_property (GObject *object, guint prop_id,
|
||||||
|
const GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind;
|
||||||
|
|
||||||
|
g_return_if_fail (GST_IS_TYPE_FIND_ELEMENT (object));
|
||||||
|
|
||||||
|
typefind = GST_TYPE_FIND_ELEMENT (object);
|
||||||
|
|
||||||
|
switch (prop_id) {
|
||||||
|
case ARG_MINIMUM:
|
||||||
|
typefind->min_probability = g_value_get_uint (value);
|
||||||
|
g_object_notify (object, "minimum");
|
||||||
|
break;
|
||||||
|
case ARG_MAXIMUM:
|
||||||
|
typefind->max_probability = g_value_get_uint (value);
|
||||||
|
g_object_notify (object, "maximum");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_get_property (GObject *object, guint prop_id,
|
||||||
|
GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind;
|
||||||
|
|
||||||
|
g_return_if_fail (GST_IS_TYPE_FIND_ELEMENT (object));
|
||||||
|
|
||||||
|
typefind = GST_TYPE_FIND_ELEMENT (object);
|
||||||
|
|
||||||
|
switch (prop_id) {
|
||||||
|
case ARG_CAPS:
|
||||||
|
g_value_set_boxed (value, typefind->caps);
|
||||||
|
break;
|
||||||
|
case ARG_MINIMUM:
|
||||||
|
g_value_set_uint (value, typefind->min_probability);
|
||||||
|
break;
|
||||||
|
case ARG_MAXIMUM:
|
||||||
|
g_value_set_uint (value, typefind->max_probability);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static const GstEventMask *
|
||||||
|
gst_type_find_element_src_event_mask (GstPad *pad)
|
||||||
|
{
|
||||||
|
static const GstEventMask mask[] = {
|
||||||
|
{ GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_END | GST_SEEK_FLAG_FLUSH},
|
||||||
|
/* add more if you want, event masks suck and need to die anyway */
|
||||||
|
{ 0, }
|
||||||
|
};
|
||||||
|
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
static gboolean
|
||||||
|
gst_type_find_element_src_event (GstPad *pad, GstEvent *event)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
|
||||||
|
|
||||||
|
if (typefind->mode == MODE_TYPEFIND) {
|
||||||
|
/* need to do more? */
|
||||||
|
gst_data_unref (GST_DATA (event));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return gst_pad_event_default (pad, event);
|
||||||
|
}
|
||||||
|
typedef struct {
|
||||||
|
GstTypeFindFactory * factory;
|
||||||
|
gint probability;
|
||||||
|
GstCaps * caps;
|
||||||
|
gint64 requested_offset;
|
||||||
|
guint requested_size;
|
||||||
|
|
||||||
|
GList * buffers;
|
||||||
|
GstTypeFindElement * self;
|
||||||
|
} TypeFindEntry;
|
||||||
|
static void
|
||||||
|
free_entry_buffers (TypeFindEntry *entry)
|
||||||
|
{
|
||||||
|
g_list_foreach (entry->buffers, (GFunc) gst_data_unref, NULL);
|
||||||
|
g_list_free (entry->buffers);
|
||||||
|
entry->buffers = NULL;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
free_entry (TypeFindEntry *entry)
|
||||||
|
{
|
||||||
|
free_entry_buffers (entry);
|
||||||
|
|
||||||
|
if (entry->caps)
|
||||||
|
gst_caps_unref (entry->caps);
|
||||||
|
g_free (entry);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
start_typefinding (GstTypeFindElement *typefind)
|
||||||
|
{
|
||||||
|
g_assert (typefind->caps == NULL);
|
||||||
|
g_assert (typefind->possibilities == NULL);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (typefind, "starting typefinding");
|
||||||
|
typefind->mode = MODE_TYPEFIND;
|
||||||
|
typefind->stream_length_available = TRUE;
|
||||||
|
typefind->stream_length = 0;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
stop_typefinding (GstTypeFindElement *typefind)
|
||||||
|
{
|
||||||
|
/* stop all typefinding and set mode back to normal */
|
||||||
|
gboolean push_cached_buffers = gst_element_get_state (GST_ELEMENT (typefind)) == GST_STATE_PLAYING;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (typefind, "stopping typefinding%s", push_cached_buffers ? " and pushing cached buffers" : "");
|
||||||
|
if (typefind->possibilities != NULL) {
|
||||||
|
/* this should only happen on PAUSED => READY or EOS */
|
||||||
|
GST_LOG_OBJECT (typefind, "freeing remaining %u typefind functions", g_list_length (typefind->possibilities));
|
||||||
|
g_list_foreach (typefind->possibilities, (GFunc) free_entry, NULL);
|
||||||
|
g_list_free (typefind->possibilities);
|
||||||
|
typefind->possibilities = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
typefind->mode = MODE_NORMAL;
|
||||||
|
|
||||||
|
if (push_cached_buffers) {
|
||||||
|
GstBuffer *buffer;
|
||||||
|
guint size = gst_buffer_store_get_size (typefind->store, 0);
|
||||||
|
if (size && (buffer = gst_buffer_store_get_buffer (typefind->store, 0, size))) {
|
||||||
|
gst_pad_push (typefind->src, GST_DATA (buffer));
|
||||||
|
} else {
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
GST_LOG_OBJECT (typefind, "seeking back to current position %u", size);
|
||||||
|
if (!gst_pad_send_event (GST_PAD_PEER (typefind->sink),
|
||||||
|
gst_event_new_seek (GST_SEEK_METHOD_SET | GST_FORMAT_BYTES, size))) {
|
||||||
|
GST_WARNING_OBJECT (typefind, "could not seek to required position %u, hope for the best", size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gst_buffer_store_clear (typefind->store);
|
||||||
|
}
|
||||||
|
static guint64
|
||||||
|
find_element_get_length (gpointer data)
|
||||||
|
{
|
||||||
|
TypeFindEntry *entry = (TypeFindEntry *) data;
|
||||||
|
GstTypeFindElement *typefind = entry->self;
|
||||||
|
GstFormat format = GST_FORMAT_BYTES;
|
||||||
|
|
||||||
|
if (!typefind->stream_length_available) {
|
||||||
|
GST_LOG_OBJECT (entry->self, "'%s' called get_length () but we know it's not available",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (entry->self->stream_length == 0) {
|
||||||
|
typefind->stream_length_available = gst_pad_query (GST_PAD_PEER (entry->self->sink), GST_QUERY_TOTAL,
|
||||||
|
&format, &entry->self->stream_length);
|
||||||
|
if (format != GST_FORMAT_BYTES)
|
||||||
|
typefind->stream_length_available = FALSE;
|
||||||
|
if (!typefind->stream_length_available) {
|
||||||
|
GST_DEBUG_OBJECT (entry->self, "'%s' called get_length () but it's not available",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory));
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
GST_DEBUG_OBJECT (entry->self, "'%s' called get_length () and it's %"G_GUINT64_FORMAT" bytes",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), entry->self->stream_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry->self->stream_length;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_handle_event (GstPad *pad, GstEvent *event)
|
||||||
|
{
|
||||||
|
TypeFindEntry *entry;
|
||||||
|
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
|
||||||
|
|
||||||
|
if (typefind->mode == MODE_TYPEFIND) {
|
||||||
|
/* need to do more? */
|
||||||
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_EOS:
|
||||||
|
/* this should only happen when we got all available data */
|
||||||
|
entry = (TypeFindEntry *) typefind->possibilities ? typefind->possibilities->data : NULL;
|
||||||
|
if (entry && entry->probability >= typefind->min_probability) {
|
||||||
|
GST_INFO_OBJECT (typefind, "'%s' is the best typefind left after we got all data, using it now (probability %u)",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), entry->probability);
|
||||||
|
g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0, entry->probability, entry->caps);
|
||||||
|
}
|
||||||
|
stop_typefinding (typefind);
|
||||||
|
gst_pad_event_default (pad, event);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
gst_data_unref (GST_DATA (event));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
gst_pad_event_default (pad, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static guint8 *
|
||||||
|
find_peek (gpointer data, gint64 offset, guint size)
|
||||||
|
{
|
||||||
|
GstBuffer *buf;
|
||||||
|
TypeFindEntry *entry = (TypeFindEntry *) data;
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (entry->self, "'%s' called peek (%"G_GINT64_FORMAT", %u)",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), offset, size);
|
||||||
|
if (offset >= 0) {
|
||||||
|
buf = gst_buffer_store_get_buffer (entry->self->store, offset, size);
|
||||||
|
} else {
|
||||||
|
/* FIXME: can we do this easily without querying length? */
|
||||||
|
guint64 length = find_element_get_length (data);
|
||||||
|
|
||||||
|
if (length == 0) {
|
||||||
|
buf = NULL;
|
||||||
|
} else {
|
||||||
|
buf = gst_buffer_store_get_buffer (entry->self->store, length + offset, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf) {
|
||||||
|
entry->buffers = g_list_prepend (entry->buffers, buf);
|
||||||
|
return GST_BUFFER_DATA (buf);
|
||||||
|
} else {
|
||||||
|
if (entry->requested_size == 0) {
|
||||||
|
GST_LOG_OBJECT (entry->self, "setting requested peek (%"G_GINT64_FORMAT", %u) on '%s'",
|
||||||
|
offset, size, GST_PLUGIN_FEATURE_NAME (entry->factory));
|
||||||
|
entry->requested_offset = offset;
|
||||||
|
entry->requested_size = size;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
find_suggest (gpointer data, guint probability, GstCaps *caps)
|
||||||
|
{
|
||||||
|
gchar *str;
|
||||||
|
TypeFindEntry *entry = (TypeFindEntry *) data;
|
||||||
|
|
||||||
|
str = gst_caps_to_string (caps);
|
||||||
|
GST_LOG_OBJECT (entry->self, "'%s' called suggest (%u, %s)",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), probability, str);
|
||||||
|
g_free (str);
|
||||||
|
if (((gint) probability) > entry->probability) {
|
||||||
|
entry->probability = probability;
|
||||||
|
gst_caps_replace (&entry->caps, caps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static gint
|
||||||
|
compare_type_find_entry (gconstpointer a, gconstpointer b)
|
||||||
|
{
|
||||||
|
TypeFindEntry *one = (TypeFindEntry *) a;
|
||||||
|
TypeFindEntry *two = (TypeFindEntry *) b;
|
||||||
|
|
||||||
|
if (one->probability == two->probability) {
|
||||||
|
/* FIXME: can be improved by analyzing requests */
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return two->probability - one->probability;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static gint
|
||||||
|
compare_type_find_factory (gconstpointer fac1, gconstpointer fac2)
|
||||||
|
{
|
||||||
|
return GST_PLUGIN_FEATURE (fac1)->rank - GST_PLUGIN_FEATURE (fac2)->rank;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_type_find_element_chain (GstPad *pad, GstData *data)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind;
|
||||||
|
GList *entries;
|
||||||
|
TypeFindEntry *entry;
|
||||||
|
GList *walk;
|
||||||
|
GstTypeFind find = {find_peek, find_suggest, NULL, find_element_get_length };
|
||||||
|
|
||||||
|
typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
|
||||||
|
if (GST_IS_EVENT (data)) {
|
||||||
|
gst_type_find_element_handle_event (pad, GST_EVENT (data));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (typefind->mode) {
|
||||||
|
case MODE_NORMAL:
|
||||||
|
gst_pad_push (typefind->src, data);
|
||||||
|
return;
|
||||||
|
case MODE_TYPEFIND: {
|
||||||
|
gst_buffer_store_add_buffer (typefind->store, GST_BUFFER (data));
|
||||||
|
gst_data_unref (data);
|
||||||
|
if (typefind->possibilities == NULL) {
|
||||||
|
/* not yet started, get all typefinding functions into our "queue" */
|
||||||
|
GList *all_factories = gst_type_find_factory_get_list ();
|
||||||
|
GST_INFO_OBJECT (typefind, "starting with %u typefinding functions",
|
||||||
|
g_list_length ((GList *) all_factories));
|
||||||
|
|
||||||
|
all_factories = g_list_sort (all_factories, compare_type_find_factory);
|
||||||
|
walk = all_factories;
|
||||||
|
while (all_factories) {
|
||||||
|
entry = g_new0 (TypeFindEntry, 1);
|
||||||
|
|
||||||
|
entry->factory = GST_TYPE_FIND_FACTORY (all_factories->data);
|
||||||
|
entry->self = typefind;
|
||||||
|
entry->probability = 0;
|
||||||
|
typefind->possibilities = g_list_prepend (typefind->possibilities, entry);
|
||||||
|
all_factories = g_list_next (all_factories);
|
||||||
|
}
|
||||||
|
g_list_free (all_factories);
|
||||||
|
}
|
||||||
|
/* call every typefind function once */
|
||||||
|
walk = entries = typefind->possibilities;
|
||||||
|
GST_INFO_OBJECT (typefind, "iterating %u typefinding functions", g_list_length (entries));
|
||||||
|
typefind->possibilities = NULL;
|
||||||
|
while (walk) {
|
||||||
|
find.data = entry = (TypeFindEntry *) walk->data;
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
entry->probability = 0;
|
||||||
|
entry->requested_offset = 0;
|
||||||
|
entry->requested_size = 0;
|
||||||
|
gst_type_find_factory_call_function (entry->factory, &find);
|
||||||
|
free_entry_buffers (entry);
|
||||||
|
if (entry->probability == 0 && entry->requested_size == 0) {
|
||||||
|
GST_DEBUG_OBJECT (typefind, "'%s' was removed - no chance of being the right plugin",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory));
|
||||||
|
free_entry (entry);
|
||||||
|
} else if (entry->probability >= typefind->max_probability) {
|
||||||
|
/* wooha, got caps */
|
||||||
|
GstCaps *found_caps = entry->caps;
|
||||||
|
guint probability = entry->probability;
|
||||||
|
|
||||||
|
gst_caps_ref (found_caps);
|
||||||
|
GST_INFO_OBJECT (typefind, "'%s' returned %u/%u probability, using it NOW",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), probability, typefind->max_probability);
|
||||||
|
while (walk) {
|
||||||
|
free_entry ((TypeFindEntry *) walk->data);
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
}
|
||||||
|
walk = typefind->possibilities;
|
||||||
|
while (walk) {
|
||||||
|
free_entry (walk->data);
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
}
|
||||||
|
typefind->possibilities = NULL;
|
||||||
|
g_list_free (typefind->possibilities);
|
||||||
|
g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0, probability, found_caps);
|
||||||
|
gst_caps_unref (found_caps);
|
||||||
|
} else {
|
||||||
|
typefind->possibilities = g_list_prepend (typefind->possibilities, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_list_free (entries);
|
||||||
|
/* we may now already have caps or we might be left without functions to try */
|
||||||
|
if (typefind->caps) {
|
||||||
|
stop_typefinding (typefind);
|
||||||
|
} else if (typefind->possibilities == NULL) {
|
||||||
|
gst_element_error (GST_ELEMENT (typefind), "media type could not be detected");
|
||||||
|
} else {
|
||||||
|
/* set up typefind element for next iteration */
|
||||||
|
typefind->possibilities = g_list_sort (typefind->possibilities, compare_type_find_entry);
|
||||||
|
|
||||||
|
walk = typefind->possibilities;
|
||||||
|
while (walk) {
|
||||||
|
entry = (TypeFindEntry *) walk->data;
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
if (entry->requested_size > 0) {
|
||||||
|
/* FIXME: need heuristic to find out if we should seek */
|
||||||
|
gint64 seek_offset;
|
||||||
|
GstEvent *event;
|
||||||
|
|
||||||
|
seek_offset = entry->requested_offset > 0 ? entry->requested_offset :
|
||||||
|
find_element_get_length (entry) + entry->requested_offset;
|
||||||
|
seek_offset += gst_buffer_store_get_size (typefind->store, seek_offset);
|
||||||
|
event = gst_event_new_seek (GST_FORMAT_BYTES | GST_SEEK_METHOD_SET, seek_offset);
|
||||||
|
if (gst_pad_send_event (GST_PAD_PEER (typefind->sink), event)) {
|
||||||
|
/* done seeking */
|
||||||
|
GST_DEBUG_OBJECT (typefind, "'%s' was reset - seeked to %"G_GINT64_FORMAT,
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), seek_offset);
|
||||||
|
break;
|
||||||
|
} else if (entry->requested_offset < 0) {
|
||||||
|
/* impossible to seek */
|
||||||
|
GST_DEBUG_OBJECT (typefind, "'%s' was reset - couldn't seek to %"G_GINT64_FORMAT,
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), seek_offset);
|
||||||
|
entry->requested_size = 0;
|
||||||
|
entry->requested_offset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* throw out all entries that can't get more data */
|
||||||
|
walk = g_list_next (typefind->possibilities);
|
||||||
|
while (walk) {
|
||||||
|
GList *cur = walk;
|
||||||
|
entry = (TypeFindEntry *) walk->data;
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
if (entry->requested_size == 0) {
|
||||||
|
GST_DEBUG_OBJECT (typefind, "'%s' was removed - higher possibilities available",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory));
|
||||||
|
free_entry (entry);
|
||||||
|
typefind->possibilities = g_list_delete_link (typefind->possibilities, cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (g_list_next (typefind->possibilities) == NULL) {
|
||||||
|
entry = (TypeFindEntry *) typefind->possibilities->data;
|
||||||
|
if (entry->probability > typefind->min_probability) {
|
||||||
|
GST_INFO_OBJECT (typefind, "'%s' is the only typefind left, using it now (probability %u)",
|
||||||
|
GST_PLUGIN_FEATURE_NAME (entry->factory), entry->probability);
|
||||||
|
g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0, entry->probability, entry->caps);
|
||||||
|
free_entry (entry);
|
||||||
|
g_list_free (typefind->possibilities);
|
||||||
|
typefind->possibilities = NULL;
|
||||||
|
stop_typefinding (typefind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static GstElementStateReturn
|
||||||
|
gst_type_find_element_change_state (GstElement *element)
|
||||||
|
{
|
||||||
|
GstTypeFindElement *typefind;
|
||||||
|
|
||||||
|
typefind = GST_TYPE_FIND_ELEMENT (element);
|
||||||
|
|
||||||
|
switch (GST_STATE_TRANSITION (element)) {
|
||||||
|
case GST_STATE_READY_TO_PAUSED:
|
||||||
|
start_typefinding (typefind);
|
||||||
|
break;
|
||||||
|
case GST_STATE_PAUSED_TO_READY:
|
||||||
|
stop_typefinding (typefind);
|
||||||
|
gst_caps_replace (&typefind->caps, NULL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||||
|
}
|
78
plugins/elements/gsttypefindelement.h
Normal file
78
plugins/elements/gsttypefindelement.h
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
|
*
|
||||||
|
* gsttypefind.h: element that detects type of stream
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __GST_TYPE_FIND_ELEMENT_H__
|
||||||
|
#define __GST_TYPE_FIND_ELEMENT_H__
|
||||||
|
|
||||||
|
#include <gst/gstinfo.h>
|
||||||
|
#include <gst/gstelement.h>
|
||||||
|
/* #include <gst/gstbufferstore.h> */
|
||||||
|
#include "gstbufferstore.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_EXTERN(gst_type_find_element_debug);
|
||||||
|
|
||||||
|
extern GstElementDetails gst_type_find_element_details;
|
||||||
|
|
||||||
|
#define GST_TYPE_TYPE_FIND_ELEMENT (gst_type_find_element_get_type ())
|
||||||
|
#define GST_TYPE_FIND_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TYPE_FIND_ELEMENT, GstTypeFindElement))
|
||||||
|
#define GST_IS_TYPE_FIND_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TYPE_FIND_ELEMENT))
|
||||||
|
#define GST_TYPE_FIND_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_TYPE_FIND_ELEMENT, GstTypeFindElementClass))
|
||||||
|
#define GST_IS_TYPE_FIND_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_TYPE_FIND_ELEMENT))
|
||||||
|
#define GST_TYPE_FIND_ELEMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_TYPE_FIND_ELEMENT, GstTypeFindElementClass))
|
||||||
|
|
||||||
|
typedef struct _GstTypeFindElement GstTypeFindElement;
|
||||||
|
typedef struct _GstTypeFindElementClass GstTypeFindElementClass;
|
||||||
|
|
||||||
|
struct _GstTypeFindElement {
|
||||||
|
GstElement element;
|
||||||
|
|
||||||
|
GstPad * sink;
|
||||||
|
GstPad * src;
|
||||||
|
|
||||||
|
guint min_probability;
|
||||||
|
guint max_probability;
|
||||||
|
GstCaps * caps;
|
||||||
|
|
||||||
|
guint mode;
|
||||||
|
GstBufferStore * store;
|
||||||
|
guint64 stream_length;
|
||||||
|
gboolean stream_length_available;
|
||||||
|
|
||||||
|
GList * possibilities;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GstTypeFindElementClass {
|
||||||
|
GstElementClass parent_class;
|
||||||
|
|
||||||
|
/* signals */
|
||||||
|
void (*have_type) (GstTypeFindElement *element,
|
||||||
|
guint probability,
|
||||||
|
GstCaps * caps);
|
||||||
|
};
|
||||||
|
|
||||||
|
GType gst_type_find_element_get_type (void);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __GST_TYPE_FIND_ELEMENT_H__ */
|
|
@ -112,18 +112,11 @@ print_props (GstProps *properties, const gchar *pfx)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
print_caps (const GstCaps *caps, const gchar *pfx)
|
print_caps (GstCaps *caps, const gchar *pfx)
|
||||||
{
|
{
|
||||||
while (caps) {
|
while (caps) {
|
||||||
GstType *type;
|
|
||||||
|
|
||||||
g_print ("%s'%s': (%sfixed)\n", pfx, caps->name, (GST_CAPS_IS_FIXED (caps) ? "" : "NOT "));
|
g_print ("%s'%s': (%sfixed)\n", pfx, caps->name, (GST_CAPS_IS_FIXED (caps) ? "" : "NOT "));
|
||||||
|
g_print ("%s MIME type: '%s':\n", pfx, gst_caps_get_mime (caps));
|
||||||
type = gst_type_find_by_id (caps->id);
|
|
||||||
if (type)
|
|
||||||
g_print ("%s MIME type: '%s':\n", pfx, type->mime);
|
|
||||||
else
|
|
||||||
g_print ("%s MIME type: 'unknown/unknown':\n", pfx);
|
|
||||||
|
|
||||||
if (caps->properties) {
|
if (caps->properties) {
|
||||||
gchar *prefix = g_strdup_printf ("%s ", pfx);
|
gchar *prefix = g_strdup_printf ("%s ", pfx);
|
||||||
|
@ -863,20 +856,19 @@ print_element_list (void)
|
||||||
GST_PLUGIN_FEATURE_NAME (factory), factory->longdesc);
|
GST_PLUGIN_FEATURE_NAME (factory), factory->longdesc);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else if (GST_IS_TYPE_FACTORY (feature)) {
|
else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
|
||||||
GstTypeFactory *factory;
|
GstTypeFindFactory *factory;
|
||||||
|
|
||||||
factory = GST_TYPE_FACTORY (feature);
|
factory = GST_TYPE_FIND_FACTORY (feature);
|
||||||
if (factory->exts)
|
if (factory->extensions) {
|
||||||
g_print ("%s type: %s: %s\n", plugin->name,
|
guint i;
|
||||||
factory->mime, factory->exts);
|
g_print ("%s type: ", plugin->name);
|
||||||
else
|
while (factory->extensions[i]) {
|
||||||
g_print ("%s type: %s: N/A\n", plugin->name,
|
g_print ("%s%s", i > 0 ? ", " : "", factory->extensions[i]);
|
||||||
factory->mime);
|
i++;
|
||||||
|
}
|
||||||
if (factory->typefindfunc)
|
} else
|
||||||
g_print (" Has typefind function: %s\n",
|
g_print ("%s type: N/A\n", plugin->name);
|
||||||
GST_DEBUG_FUNCPTR_NAME (factory->typefindfunc));
|
|
||||||
}
|
}
|
||||||
else if (GST_IS_SCHEDULER_FACTORY (feature)) {
|
else if (GST_IS_SCHEDULER_FACTORY (feature)) {
|
||||||
GstSchedulerFactory *factory;
|
GstSchedulerFactory *factory;
|
||||||
|
@ -957,15 +949,20 @@ print_plugin_info (GstPlugin *plugin)
|
||||||
num_indexes++;
|
num_indexes++;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else if (GST_IS_TYPE_FACTORY (feature)) {
|
else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
|
||||||
GstTypeFactory *factory;
|
GstTypeFindFactory *factory;
|
||||||
|
|
||||||
factory = GST_TYPE_FACTORY (feature);
|
factory = GST_TYPE_FIND_FACTORY (feature);
|
||||||
g_print (" %s: %s\n", factory->mime, factory->exts);
|
if (factory->extensions) {
|
||||||
|
guint i;
|
||||||
|
g_print ("%s type: ", plugin->name);
|
||||||
|
while (factory->extensions[i]) {
|
||||||
|
g_print ("%s%s", i > 0 ? ", " : "", factory->extensions[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
g_print ("%s type: N/A\n", plugin->name);
|
||||||
|
|
||||||
if (factory->typefindfunc)
|
|
||||||
g_print (" Has typefind function: %s\n",
|
|
||||||
GST_DEBUG_FUNCPTR_NAME (factory->typefindfunc));
|
|
||||||
num_types++;
|
num_types++;
|
||||||
}
|
}
|
||||||
else if (GST_IS_SCHEDULER_FACTORY (feature)) {
|
else if (GST_IS_SCHEDULER_FACTORY (feature)) {
|
||||||
|
@ -1066,9 +1063,9 @@ main (int argc, char *argv[])
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
feature = gst_registry_pool_find_feature (argv[1],
|
feature = gst_registry_pool_find_feature (argv[1],
|
||||||
GST_TYPE_TYPE_FACTORY);
|
GST_TYPE_TYPE_FIND_FACTORY);
|
||||||
if (feature) {
|
if (feature) {
|
||||||
g_print ("%s: an type\n", argv[1]);
|
g_print ("%s: a typefind function\n", argv[1]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#ifndef GST_DISABLE_URI
|
#ifndef GST_DISABLE_URI
|
||||||
|
|
|
@ -132,7 +132,7 @@ int main (int argc,char *argv[])
|
||||||
|
|
||||||
dir_list = gst_registry_get_path_list(registry);
|
dir_list = gst_registry_get_path_list(registry);
|
||||||
for(iter = dir_list; iter; iter = iter->next) {
|
for(iter = dir_list; iter; iter = iter->next) {
|
||||||
dir = g_build_filename((const char *)iter->data, "register-scripts");
|
dir = g_build_filename((const char *)iter->data, "register-scripts", NULL);
|
||||||
spawn_all_in_dir(dir);
|
spawn_all_in_dir(dir);
|
||||||
g_free(dir);
|
g_free(dir);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,26 +12,27 @@
|
||||||
**/
|
**/
|
||||||
|
|
||||||
gboolean FOUND = FALSE;
|
gboolean FOUND = FALSE;
|
||||||
int iterations;
|
gchar *filename = NULL;
|
||||||
int max_iterations = 100;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
gst_caps_print (GstCaps *caps)
|
gst_caps_print (const char *filename, GstCaps *caps)
|
||||||
{
|
{
|
||||||
g_print ("%s\n", gst_caps_to_string (caps));
|
gchar *caps_str = gst_caps_to_string (caps);
|
||||||
|
g_print ("%s - %s\n", filename, caps_str);
|
||||||
|
g_free (caps_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
have_type_handler (GstElement *typefind, gpointer data)
|
have_type_handler (GstElement *typefind, guint probability, GstCaps *caps, gpointer unused)
|
||||||
{
|
{
|
||||||
GstCaps *caps = (GstCaps *) data;
|
gst_caps_print (filename, caps);
|
||||||
gst_caps_print (caps);
|
|
||||||
FOUND = TRUE;
|
FOUND = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char *argv[])
|
main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
guint i = 1;
|
||||||
GstElement *pipeline;
|
GstElement *pipeline;
|
||||||
GstElement *source, *typefind;
|
GstElement *source, *typefind;
|
||||||
|
|
||||||
|
@ -41,12 +42,12 @@ main (int argc, char *argv[])
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
g_print ("Please give a filename to typefind\n\n");
|
g_print ("Please give a filename to typefind\n\n");
|
||||||
exit (1);
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pipeline = gst_pipeline_new (NULL);
|
pipeline = gst_pipeline_new (NULL);
|
||||||
source = gst_element_factory_make ("filesrc", "source");
|
source = gst_element_factory_make ("filesrc", "source");
|
||||||
g_assert (GST_IS_ELEMENT (source));
|
g_assert (GST_IS_ELEMENT (source));
|
||||||
g_object_set (source, "location", argv[1], NULL);
|
|
||||||
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_many (GST_BIN (pipeline), source, typefind, NULL);
|
||||||
|
@ -54,19 +55,23 @@ main (int argc, char *argv[])
|
||||||
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);
|
||||||
|
|
||||||
/* set to play */
|
while (i < argc) {
|
||||||
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
|
FOUND = FALSE;
|
||||||
|
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
|
||||||
|
filename = argv[i];
|
||||||
|
g_object_set (source, "location", filename, NULL);
|
||||||
|
/* set to play */
|
||||||
|
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
|
||||||
|
|
||||||
while (!FOUND){
|
while (!FOUND) {
|
||||||
gst_bin_iterate (GST_BIN (pipeline));
|
if (!gst_bin_iterate (GST_BIN (pipeline)))
|
||||||
iterations++;
|
break;
|
||||||
if(iterations >= max_iterations){
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
if (!FOUND) {
|
||||||
|
g_print ("%s - No type found\n", argv[i]);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
if (!FOUND) {
|
g_object_unref (pipeline);
|
||||||
g_print ("No type found\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,7 +159,7 @@ print_props (GstProps *properties, gint pfx)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
print_caps (const GstCaps *caps, gint pfx)
|
print_caps (GstCaps *caps, gint pfx)
|
||||||
{
|
{
|
||||||
if (!caps)
|
if (!caps)
|
||||||
return;
|
return;
|
||||||
|
@ -167,16 +167,10 @@ print_caps (const GstCaps *caps, gint pfx)
|
||||||
PUT_START_TAG (pfx, "capscomp");
|
PUT_START_TAG (pfx, "capscomp");
|
||||||
|
|
||||||
while (caps) {
|
while (caps) {
|
||||||
GstType *type;
|
|
||||||
|
|
||||||
PUT_START_TAG (pfx + 1, "caps");
|
PUT_START_TAG (pfx + 1, "caps");
|
||||||
PUT_ESCAPED (pfx + 2, "name", caps->name);
|
PUT_ESCAPED (pfx + 2, "name", caps->name);
|
||||||
|
|
||||||
type = gst_type_find_by_id (caps->id);
|
PUT_ESCAPED (pfx + 2, "type", gst_caps_get_mime (caps));
|
||||||
if (type)
|
|
||||||
PUT_ESCAPED (pfx + 2, "type", type->mime);
|
|
||||||
else
|
|
||||||
PUT_ESCAPED (pfx + 2, "type", "unkown/unknown");
|
|
||||||
|
|
||||||
if (caps->properties) {
|
if (caps->properties) {
|
||||||
print_props(caps->properties, pfx + 2);
|
print_props(caps->properties, pfx + 2);
|
||||||
|
@ -855,16 +849,19 @@ print_element_list (void)
|
||||||
GST_PLUGIN_FEATURE_NAME (factory), factory->longdesc);
|
GST_PLUGIN_FEATURE_NAME (factory), factory->longdesc);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else if (GST_IS_TYPE_FACTORY (feature)) {
|
else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
|
||||||
GstTypeFactory *factory;
|
GstTypeFindFactory *factory;
|
||||||
|
|
||||||
factory = GST_TYPE_FACTORY (feature);
|
factory = GST_TYPE_FIND_FACTORY (feature);
|
||||||
g_print ("%s type: %s: %s\n", plugin->name,
|
if (factory->extensions) {
|
||||||
factory->mime, factory->exts);
|
guint i;
|
||||||
|
g_print ("%s type: ", plugin->name);
|
||||||
if (factory->typefindfunc)
|
while (factory->extensions[i]) {
|
||||||
g_print (" Has typefind function: %s\n",
|
g_print ("%s%s", i > 0 ? ", " : "", factory->extensions[i]);
|
||||||
GST_DEBUG_FUNCPTR_NAME (factory->typefindfunc));
|
i++;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
g_print ("%s type: N/A\n", plugin->name);
|
||||||
}
|
}
|
||||||
else if (GST_IS_SCHEDULER_FACTORY (feature)) {
|
else if (GST_IS_SCHEDULER_FACTORY (feature)) {
|
||||||
GstSchedulerFactory *factory;
|
GstSchedulerFactory *factory;
|
||||||
|
@ -945,15 +942,19 @@ print_plugin_info (GstPlugin *plugin)
|
||||||
num_indexes++;
|
num_indexes++;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else if (GST_IS_TYPE_FACTORY (feature)) {
|
else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
|
||||||
GstTypeFactory *factory;
|
GstTypeFindFactory *factory;
|
||||||
|
|
||||||
factory = GST_TYPE_FACTORY (feature);
|
factory = GST_TYPE_FIND_FACTORY (feature);
|
||||||
g_print (" %s: %s\n", factory->mime, factory->exts);
|
if (factory->extensions) {
|
||||||
|
guint i;
|
||||||
if (factory->typefindfunc)
|
g_print ("%s type: ", plugin->name);
|
||||||
g_print (" Has typefind function: %s\n",
|
while (factory->extensions[i]) {
|
||||||
GST_DEBUG_FUNCPTR_NAME (factory->typefindfunc));
|
g_print ("%s%s", i > 0 ? ", " : "", factory->extensions[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
g_print ("%s type: N/A\n", plugin->name);
|
||||||
num_types++;
|
num_types++;
|
||||||
}
|
}
|
||||||
else if (GST_IS_SCHEDULER_FACTORY (feature)) {
|
else if (GST_IS_SCHEDULER_FACTORY (feature)) {
|
||||||
|
@ -1059,9 +1060,9 @@ main (int argc, char *argv[])
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
feature = gst_registry_pool_find_feature (argv[1],
|
feature = gst_registry_pool_find_feature (argv[1],
|
||||||
GST_TYPE_TYPE_FACTORY);
|
GST_TYPE_TYPE_FIND_FACTORY);
|
||||||
if (feature) {
|
if (feature) {
|
||||||
g_print ("%s: an type\n", argv[1]);
|
g_print ("%s: a type find function\n", argv[1]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#ifndef GST_DISABLE_URI
|
#ifndef GST_DISABLE_URI
|
||||||
|
|
Loading…
Reference in a new issue