merge from EVENTS1 on 20011016

Original commit message from CVS:
merge from EVENTS1 on 20011016
This commit is contained in:
Erik Walthinsen 2001-10-17 10:21:27 +00:00
parent b81c9eb858
commit d574ab8126
135 changed files with 10416 additions and 3922 deletions

View file

@ -191,10 +191,14 @@ automake --add-missing || {
# now remove the cache, because it can be considered dangerous in this case
rm -f config.cache
# The new configure options for busy application developers (Hadess)
#./configure --enable-maintainer-mode --enable-debug --enable-DEBUG "$@" || {
CONFIGURE_OPT='--enable-maintainer-mode --enable-plugin-builddir --enable-debug --enable-DEBUG'
./configure --enable-maintainer-mode --enable-plugin-builddir --enable-debug --enable-DEBUG "$@" || {
echo
echo "./configure default flags: $CONFIGURE_OPT"
echo "using: $CONFIGURE_OPT $@"
echo
./configure $CONFIGURE_OPT "$@" || {
echo
echo "configure failed"
exit 1

View file

@ -216,13 +216,6 @@ GST_CHECK_FEATURE(GLIB2, [use of glib-2.0 and GObject], , [
])
AC_SUBST(USE_GLIB2)
dnl FIXME: check for gtk2 and gnome2 - these conditionals are currently
dnl always false.
AM_CONDITIONAL(USE_GTK2, test "x$USE_GTK2" = "xyes")
AC_SUBST(USE_GTK2)
AM_CONDITIONAL(USE_GNOME2, test "x$USE_GNOME2" = "xyes")
AC_SUBST(USE_GNOME2)
if test x$USE_GLIB2 = xno; then
dnl Check for glib and gtk
AM_PATH_GLIB(1.2.0,,
@ -230,11 +223,24 @@ if test x$USE_GLIB2 = xno; then
glib gmodule gthread)
AM_PATH_GTK(1.2.0,,
AC_MSG_ERROR(Cannot find gtk: Is gtk-config in path?))
HAVE_GTK=yes
CORE_LIBS="$CORE_LIBS $GLIB_LIBS $GTK_LIBS"
CORE_CFLAGS="$CORE_CFLAGS $GLIB_CFLAGS $GTK_CFLAGS"
else
PKG_CHECK_MODULES(GTK2, gtk+-2.0, HAVE_GTK=yes, HAVE_GTK=no)
GTK_FLAGS=$GTK2_CFLAGS
GTK_LIBS=$GTK2_LIBS
dnl FIXME: check for gnome2 - this conditional is currently
dnl always false.
AM_CONDITIONAL(USE_GNOME2, test "x$USE_GNOME2" = "xyes")
AC_SUBST(USE_GNOME2)
fi
AC_SUBST(GTK_LIBS)
AC_SUBST(GTK_CFLAGS)
dnl Check for libxml
AC_PATH_PROG(XML_CONFIG, xml-config, no)
@ -926,12 +932,16 @@ if test "x$USE_DEBUG" = xyes; then
fi
if test "x$USE_PROFILING" = xyes; then
CFLAGS="$CFLAGS -pg"
CFLAGS="$CFLAGS -pg -fprofile-arcs"
FOMIT_FRAME_POINTER=""
else
FOMIT_FRAME_POINTER="-fomit-frame-pointer"
fi
dnl
dnl AC_SUBST(FOMIT_FRAME_POINTER)
dnl
if test "x$HAVE_LIBXV" = xyes; then
AC_DEFINE(HAVE_LIBXV)
fi
@ -1024,6 +1034,7 @@ AM_CONDITIONAL(HAVE_NASM, test "x$HAVE_NASM" = "xyes")
AM_CONDITIONAL(HAVE_LIBGLADE_GNOME, test "x$HAVE_LIBGLADE_GNOME" = "xyes")
AM_CONDITIONAL(HAVE_GNOME, test "x$HAVE_GNOME" = "xyes")
AM_CONDITIONAL(HAVE_LIBXV, test "x$HAVE_LIBXV" = "xyes")
AM_CONDITIONAL(HAVE_GTK, test "x$HAVE_GTK" = "xyes")
AM_CONDITIONAL(HAVE_GTK_DOC, $HAVE_GTK_DOC)
AM_CONDITIONAL(BUILD_DOCS, test "x$BUILD_DOCS" = "xyes")
AM_CONDITIONAL(BUILD_TESTS, test "x$BUILD_TESTS" = "xyes")
@ -1176,6 +1187,7 @@ libs/getbits/Makefile
libs/putbits/Makefile
libs/idct/Makefile
libs/audio/Makefile
libs/bytestream/Makefile
libs/control/Makefile
plugins/Makefile
plugins/a52dec/Makefile
@ -1285,6 +1297,8 @@ test/Makefile
test/xml/Makefile
test/bindings/Makefile
dnl someone should fix this test/misc/Makefile
test/memchunk/Makefile
test/events/Makefile
tests/Makefile
tests/sched/Makefile
tests/eos/Makefile

View file

@ -116,7 +116,7 @@ The type of the autoplugger.
</para>
@name:
@feature:
@longdesc:
@type:
@ -207,22 +207,3 @@ The type of the autoplugger.
@Returns:
<!-- ##### FUNCTION gst_autoplugfactory_save_thyself ##### -->
<para>
</para>
@factory:
@parent:
@Returns:
<!-- ##### FUNCTION gst_autoplugfactory_load_thyself ##### -->
<para>
</para>
@parent:
@Returns:

View file

@ -239,6 +239,7 @@ used when data in a stream has been skipped
</para>
@data_type:
@lock:
@data:
@size:
@ -265,6 +266,8 @@ used when data in a stream has been skipped
</para>
@pool:
@location:
@size:
@Returns:
@ -293,9 +296,12 @@ used when data in a stream has been skipped
</para>
@buf:
@buf2:
@Returns:
<!-- # Unused Parameters # -->
@buffer:
@append:
@Returns:
<!-- ##### FUNCTION gst_buffer_ref ##### -->

View file

@ -52,30 +52,10 @@ A bufferpool can be requested from a pad with the gst_pad_get_bufferpool() funct
</para>
@lock:
@new_user_data:
@destroy_user_data:
@destroy_buffer:
<!-- ##### USER_FUNCTION GstBufferPoolCreateFunction ##### -->
<para>
The function called when a buffer has to be created for this pool.
</para>
@pool: the pool from which to create the buffer
@user_data: any user data
@Returns: a new buffer from the pool
<!-- ##### USER_FUNCTION GstBufferPoolDestroyFunction ##### -->
<para>
This function will be called when the given buffer has to be returned to
the pool.
</para>
@pool: the pool to return the buffer to
@buffer: the buffer to return
@user_data: any user data
@buffer_free:
@buffer_copy:
@destroy_hook:
@user_data:
<!-- ##### FUNCTION gst_buffer_pool_new ##### -->
<para>
@ -85,24 +65,6 @@ the pool.
@Returns:
<!-- ##### FUNCTION gst_buffer_pool_new_buffer ##### -->
<para>
</para>
@pool:
@Returns:
<!-- ##### FUNCTION gst_buffer_pool_destroy_buffer ##### -->
<para>
</para>
@pool:
@buffer:
<!-- ##### FUNCTION gst_buffer_pool_ref ##### -->
<para>
@ -130,26 +92,6 @@ the pool.
@pool:
<!-- ##### FUNCTION gst_buffer_pool_set_create_function ##### -->
<para>
</para>
@pool:
@create:
@user_data:
<!-- ##### FUNCTION gst_buffer_pool_set_destroy_function ##### -->
<para>
</para>
@pool:
@destroy:
@user_data:
<!-- ##### FUNCTION gst_buffer_pool_destroy ##### -->
<para>
@ -163,9 +105,10 @@ the pool.
</para>
@oldpool:
@buffer_size:
@pool_size:
@Returns:
<!-- # Unused Parameters # -->
@oldpool:

View file

@ -47,8 +47,8 @@ Specify how many bytes to read at a time.
Get/set the current offset in the file.
</para>
<!-- ##### ARG GstDiskSrc:size ##### -->
<!-- ##### ARG GstDiskSrc:filesize ##### -->
<para>
Get the size of the file.
</para>

View file

@ -225,7 +225,7 @@ of the element, the GtkType value for it, as well as a pointer to the
GstElementDetails struct for the element.
</para>
@name:
@feature:
@type:
@details:
@padtemplates:
@ -241,14 +241,6 @@ circumstances.
@element: The element in question.
<!-- ##### FUNCTION gst_element_new ##### -->
<para>
</para>
@Returns:
<!-- ##### MACRO gst_element_destroy ##### -->
<para>
@ -503,14 +495,6 @@ circumstances.
@Returns:
<!-- ##### FUNCTION gst_elementfactory_destroy ##### -->
<para>
</para>
@elementfactory:
<!-- ##### FUNCTION gst_elementfactory_add_padtemplate ##### -->
<para>
@ -580,25 +564,6 @@ circumstances.
@Returns:
<!-- ##### FUNCTION gst_elementfactory_save_thyself ##### -->
<para>
</para>
@factory:
@parent:
@Returns:
<!-- ##### FUNCTION gst_elementfactory_load_thyself ##### -->
<para>
</para>
@parent:
@Returns:
<!-- ##### SIGNAL GstElement::state-change ##### -->
<para>
Is trigered whenever the state of an element changes

View file

@ -24,7 +24,7 @@ with the buffer. (fakesink)
@gstfakesink: the object which received the signal.
@arg1:
<!-- ##### ARG GstFakeSink:num_sinks ##### -->
<!-- ##### ARG GstFakeSink:num-sinks ##### -->
<para>
</para>

View file

@ -22,12 +22,12 @@ The <classname>GstFakeSrc</classname> generates empty buffers. (fakesrc)
@gstfakesrc: the object which received the signal.
@arg1:
<!-- ##### ARG GstFakeSrc:num_sources ##### -->
<!-- ##### ARG GstFakeSrc:num-sources ##### -->
<para>
</para>
<!-- ##### ARG GstFakeSrc:loop_based ##### -->
<!-- ##### ARG GstFakeSrc:loop-based ##### -->
<para>
</para>
@ -42,7 +42,7 @@ The <classname>GstFakeSrc</classname> generates empty buffers. (fakesrc)
</para>
<!-- ##### ARG GstFakeSrc:num_buffers ##### -->
<!-- ##### ARG GstFakeSrc:num-buffers ##### -->
<para>
</para>

View file

@ -22,12 +22,12 @@ Pass data without modification.
@gstidentity: the object which received the signal.
@arg1:
<!-- ##### ARG GstIdentity:loop_based ##### -->
<!-- ##### ARG GstIdentity:loop-based ##### -->
<para>
</para>
<!-- ##### ARG GstIdentity:sleep_time ##### -->
<!-- ##### ARG GstIdentity:sleep-time ##### -->
<para>
</para>

View file

@ -141,14 +141,6 @@ Check if the object has been destroyed.
@obj: The Object to check
<!-- ##### FUNCTION gst_object_new ##### -->
<para>
</para>
@Returns:
<!-- ##### FUNCTION gst_object_check_uniqueness ##### -->
<para>

View file

@ -189,24 +189,6 @@ a start/stop timecode pair.
@size: the size of the region to get
<!-- ##### USER_FUNCTION GstPadQoSFunction ##### -->
<para>
The function that will be called when a QoS message is sent.
</para>
@pad: the pad that sent the QoS message
@qos_message: the message
<!-- ##### USER_FUNCTION GstPadEOSFunction ##### -->
<para>
The function that will be called in an EOS case.
</para>
@pad: the pad that needs to be set to EOS state
@Returns: TRUE if EOS was successful, FALSE otherwise
<!-- ##### USER_FUNCTION GstPadNewCapsFunction ##### -->
<para>
The function that will be called when the caps of the pad has
@ -247,25 +229,6 @@ The function that will be called when negotiating.
@Returns: The result of the negotiation process
<!-- ##### USER_FUNCTION GstPadPushFunction ##### -->
<para>
The function that will be called when pushing a buffers.
</para>
@pad: the pad to push
@buf: a GstBuffer to push
<!-- ##### USER_FUNCTION GstPadPullFunction ##### -->
<para>
The function that will be called when pulling buffers.
</para>
@pad: the pad to pull
@Returns: a GstBuffer
<!-- ##### ENUM GstRegionType ##### -->
<para>
the region types for #gst_pad_pullregion.
@ -383,24 +346,6 @@ Destroy the pad.
@nego:
<!-- ##### FUNCTION gst_pad_set_qos_function ##### -->
<para>
</para>
@pad:
@qos:
<!-- ##### FUNCTION gst_pad_set_eos_function ##### -->
<para>
</para>
@pad:
@eos:
<!-- ##### FUNCTION gst_pad_set_newcaps_function ##### -->
<para>
@ -627,32 +572,6 @@ Destroy the pad.
@Returns:
<!-- ##### FUNCTION gst_pad_set_eos ##### -->
<para>
</para>
@pad:
@Returns:
<!-- ##### FUNCTION gst_pad_handle_qos ##### -->
<para>
</para>
@pad:
@qos_message:
<!-- ##### MACRO gst_pad_eos ##### -->
<para>
Call the EOS function of the pad
</para>
@pad: the pad to call the eos function of.
<!-- ##### FUNCTION gst_pad_load_and_connect ##### -->
<para>
@ -706,15 +625,6 @@ Call the EOS function of the pad
@Returns:
<!-- ##### FUNCTION gst_pad_eos_func ##### -->
<para>
</para>
@pad:
@Returns:
<!-- ##### STRUCT GstRealPad ##### -->
<para>
@ -731,12 +641,12 @@ Call the EOS function of the pad
@len:
@sched:
@chainfunc:
@chainhandler:
@getfunc:
@gethandler:
@eventfunc:
@eventhandler:
@getregionfunc:
@qosfunc:
@eosfunc:
@pushfunc:
@pullfunc:
@pullregionfunc:
@negotiatefunc:
@newcapsfunc:
@ -831,22 +741,6 @@ Get the getregion function of the real pad.
@pad: the real pad to query.
<!-- ##### MACRO GST_RPAD_PUSHFUNC ##### -->
<para>
Get the pushfunction of the real pad.
</para>
@pad: the real pad to query.
<!-- ##### MACRO GST_RPAD_PULLFUNC ##### -->
<para>
Get the pullfunction of the real pad.
</para>
@pad: the real pad to query.
<!-- ##### MACRO GST_RPAD_PULLREGIONFUNC ##### -->
<para>
Get the pullregion function of the real pad.
@ -855,22 +749,6 @@ Get the pullregion function of the real pad.
@pad: the real pad to query.
<!-- ##### MACRO GST_RPAD_QOSFUNC ##### -->
<para>
Get the QoS function of the real pad.
</para>
@pad: the real pad to query.
<!-- ##### MACRO GST_RPAD_EOSFUNC ##### -->
<para>
Get the EOS function of the real pad.
</para>
@pad: the real pad to query.
<!-- ##### MACRO GST_RPAD_NEGOTIATEFUNC ##### -->
<para>
Get the negotiate function from the real pad.

View file

@ -63,11 +63,9 @@ to bring it into memory.
@name:
@longname:
@filename:
@types:
@numtypes:
@elements:
@numelements:
@numautopluggers:
@features:
@numfeatures:
@module:
<!-- ##### USER_FUNCTION GstPluginInitFunc ##### -->
<para>
@ -198,33 +196,6 @@ loaded will use this variable to initialize the plugin.
@Returns:
<!-- ##### FUNCTION gst_plugin_add_factory ##### -->
<para>
</para>
@plugin:
@factory:
<!-- ##### FUNCTION gst_plugin_add_type ##### -->
<para>
</para>
@plugin:
@factory:
<!-- ##### FUNCTION gst_plugin_add_autoplugger ##### -->
<para>
</para>
@plugin:
@factory:
<!-- ##### FUNCTION gst_plugin_find ##### -->
<para>
@ -242,59 +213,6 @@ loaded will use this variable to initialize the plugin.
@Returns:
<!-- ##### FUNCTION gst_plugin_get_factory_list ##### -->
<para>
</para>
@plugin:
@Returns:
<!-- ##### FUNCTION gst_plugin_get_type_list ##### -->
<para>
</para>
@plugin:
@Returns:
<!-- ##### FUNCTION gst_plugin_get_autoplug_list ##### -->
<para>
</para>
@plugin:
@Returns:
<!-- ##### FUNCTION gst_plugin_load_elementfactory ##### -->
<para>
</para>
@name:
@Returns:
<!-- ##### FUNCTION gst_plugin_load_typefactory ##### -->
<para>
</para>
@mime:
<!-- ##### FUNCTION gst_plugin_load_autoplugfactory ##### -->
<para>
</para>
@name:
@Returns:
<!-- ##### FUNCTION gst_plugin_load_thyself ##### -->
<para>

View file

@ -35,7 +35,7 @@ The queue blocks by default.
Get the number of buffers in the queue.
</para>
<!-- ##### ARG GstQueue:max_level ##### -->
<!-- ##### ARG GstQueue:max-level ##### -->
<para>
Specify the maximum number of buffers in the queue before the queue
blocks.

File diff suppressed because it is too large Load diff

View file

@ -14,7 +14,7 @@ A tee can be used to split out the filter graph.
</para>
<!-- ##### ARG GstTee:num_pads ##### -->
<!-- ##### ARG GstTee:num-pads ##### -->
<para>
</para>

View file

@ -45,7 +45,7 @@ Thread flags:
@Returns:
<!-- ##### ARG GstThread:create_thread ##### -->
<!-- ##### ARG GstThread:create-thread ##### -->
<para>
TRUE if the thread should be created.

View file

@ -71,13 +71,14 @@ A type.
@id:
@mime:
@exts:
@typefindfuncs:
@factories:
<!-- ##### STRUCT GstTypeFactory ##### -->
<para>
The struct with the typefactory information.
</para>
@feature:
@mime:
@exts:
@typefindfunc:
@ -126,22 +127,3 @@ The struct with the typefactory information.
@Returns:
<!-- ##### FUNCTION gst_typefactory_load_thyself ##### -->
<para>
</para>
@parent:
@Returns:
<!-- ##### FUNCTION gst_typefactory_save_thyself ##### -->
<para>
</para>
@factory:
@parent:
@Returns:

View file

@ -1,140 +1,138 @@
some random ramblings about the event system:
This is a round up from our IRC session on events. It's open for
discussion of course.
Possible candidates for events
Definition
----------
The event system is designed to be a mechanism for _inter_plugin_
communication. Their scope is therefore limited in a way that they do
not serve as a way to communicate between plugins and the app (signals
and properties are still used for plugin-app communication).
Events will be generated by either a plugin or the app. It should be
possible for a plugin to generate an event on one of its pads and it
should be possible for an app to insert an event on an abitrary pad in
the pipeline.
Event handling
--------------
Events can both travel upstream or downstream. Some events, by nature,
only travel in one direction.
* downstream events
- Travel in the same way buffers do. This includes that they are handled
by the scheduler. The rationale is that the events should be kept
as close to the buffers are possible.
- plugins should check the type of the GstData passed in the _chain
or _loop function and act appropriatly. This can be done by either
doing their own stuff or by calling the default handler.
- are handled on the sink pad.
* upstream events
- are handled with an event handler attached to the srcpad. A default
handler will be implemented for pads that don't implement their own
handler.
- travel as fast as possible. the rationale is that a seek event should
get to the src element ASAP.
Possible candidates for events
------------------------------
- QoS
quality of service. Plugins can notify other plugins about the quality
of the pipeline. A video element can for example say that it receives
too much frames and that plugins connected to it need to slow down.
- EOS
A plugin can notify other plugins that it has run out-of-data.
- Seek
- caps nego??
- bufferpool get??
Used to notify plugins that they need to seek to a certain byte offset
or timestamp.
- discontinuous
A plugin has detected a discontinuity in the stream. Other plugins
might need to resync.
- flush
Plugins need to get rid of any buffered data ASAP.
- caps nego??
- bufferpool get??
- ...
Assumptions for events
----------------------
- They are tied to a pad.
- get rid of gst_pad_set_*_function (except for the chain/get ones)
- occur async to dataflow. (need locking?)
- fixed set of events only for core features. (elements cannot abuse
events for doing dataflow)
application generated events
----------------------------
Questions
The application can insert events into the pipeline at arbirary
places. This will be done by calling gst_pad_event() on a pad.
A first implementation will only cover inserting events on src pads
since inserting events on sinkpads needs changes to the scheduler.
Effects of events on plugins
----------------------------
some events are going to change the state of an element. The EOS event
will for example change the state of an element to the PAUSED state. Not
sure when or how this will happen.
use cases
---------
limit the valid directions an event can travel in? ie. Can EOS only
travel downstream (left to right)?
1) filesrc ! fakesink
eg. Seek travels upstream, but it makes sense to also make it travel
downstream (the case of a disksink, where we overwrite the header)
filesrc will read until it reaches EOF. It will then create a GstEvent
of type EOS and return it in the _get function. The event will travel
downstream and will reach the fakesink element. Fakesink will detect
the event in the _chain function and will call the default handler. The
default handler will set the element to the paused state. filesrc will
eventually change its state to PAUSED, probably before sending out the
event (TBD)
2) filesrc ! fakesink
The app wants to perform a seek on filesrc. It'll call the gst_pad_event()
on filesrcs src pad with the SEEK event type. The event handler will
react and change filesrcs internal status. filesrc will return a DISCONT
event before returning the buffer with the new offset.
3) filesrc ! mpeg2parse video_0! queue ! { mpeg2dec ! xvideosink }
lost of possibilities here: The app can choose to insert a seek event
on the filesrc element (byte offset), it can insert a byte/time offset
seek on the video_0 pad of mpeg2parse or it can insert a time seek event
on mpeg2decs src pad.
the event will travel upstream using the handlers and the intermediate
elements can convert the event from a time to a byte offset (possibly
using GstTimeCache to speed up things).
Filesrc will get a byte seek event on its src pad and will proceed as
in case 2.
As can be seen from this example the app will generate an event in another
context than those of the plugins, so this will need proper locking.
The app can also choose to insert a flush event on one of the src
pads. The plugins would clear their cached data and forward the event
to their upstream peer pad(s).
4)...
Insert impossible case here..
Setting an event function
-------------------------
void gst_pad_set_event_function (GstPad *pad, gint event_mask,
GstEventFunction *function);
event masks:
typedef enum {
GST_EVENT_EOS = (1 << 0),
GST_EVENT_QOS = (1 << 1),
GST_EVENT_SEEK = (1 << 2),
GST_EVENT_CAPS = (1 << 3),
} GstEventType;
Event structure
---------------
typedef struct {
GstEventType type;
GstEventMinorType minor;
guint64 timestamp; /* also sequence number ?? */
union {
/* EOS stuff */
/* QoS stuff */
/* Seek stuff */
GstSeekType type; /* time, bytes, ... */
gint64 offset;
gint64 lenth;
/* Caps stuff */
GstCaps *caps;
} data;
} GstEvent;
typedef enum {
GST_EVENT_MINOR_NONE,
/* EOS stuff */
/* QoS stuff */
/* Seek stuff */
GST_EVENT_MINOR_OFFSET,
GST_EVENT_MINOR_TIME,
/* caps nego stuff */
GST_EVENT_MINOR_CAPS_TRY,
GST_EVENT_MINOR_CAPS_START,
GST_EVENT_MINOR_CAPS_FINAL,
} GstEventMinorType;
Receiving events
----------------
a sample GstEventFunction, the event functions returns TRUE if the event is handled,
FALSE otherwise.
gboolean
gst_anelement_handle_event (GstPad *pad, GstEvent *event)
{
if (event->type == GST_EVENT_EOS) {
/* do something */
return TRUE;
}
else if (event->type == GST_EVENT_CAPS) {
if (event->minor == GST_EVENT_CAPS_TRY) {
/* try using this caps structure */
return TRUE; /* return FALSE to proxy ???*/
}
}
return FALSE;
}
Default event handler for pads
------------------------------
gboolean
gst_pad_handle_event (GstPad *pad, GstEvent *event)
{
GstElement *element;
GList *pads;
GstPad *srcpad;
gboolean result = TRUE;
GstPadDirection dir = GST_PAD_DIRECTION (pad);
g_return_val_if_fail (pad != NULL, FALSE);
g_return_val_if_fail (GST_IS_REAL_PAD(pad), FALSE); // NOTE the restriction
element = GST_ELEMENT (gst_object_get_parent (GST_OBJECT (pad)));
/* send out the events to all pad with opposite direction */
pads = gst_element_get_pad_list(element);
while (pads) {
otherpad = GST_PAD(pads->data);
pads = g_list_next(pads);
if (gst_pad_get_direction(otherpad) != dir) {
result &= gst_pad_send_event (GST_REAL_PAD(otherpad), event);
}
}
/* result is combined result of all handlers? */
return result;
}

140
docs/random/wtay/events2 Normal file
View file

@ -0,0 +1,140 @@
some random ramblings about the event system:
Possible candidates for events
------------------------------
- QoS
- EOS
- Seek
- caps nego??
- bufferpool get??
- ...
Assumptions for events
----------------------
- They are tied to a pad.
- get rid of gst_pad_set_*_function (except for the chain/get ones)
- occur async to dataflow. (need locking?)
- fixed set of events only for core features. (elements cannot abuse
events for doing dataflow)
Questions
---------
limit the valid directions an event can travel in? ie. Can EOS only
travel downstream (left to right)?
eg. Seek travels upstream, but it makes sense to also make it travel
downstream (the case of a disksink, where we overwrite the header)
Setting an event function
-------------------------
void gst_pad_set_event_function (GstPad *pad, gint event_mask,
GstEventFunction *function);
event masks:
typedef enum {
GST_EVENT_EOS = (1 << 0),
GST_EVENT_QOS = (1 << 1),
GST_EVENT_SEEK = (1 << 2),
GST_EVENT_CAPS = (1 << 3),
} GstEventType;
Event structure
---------------
typedef struct {
GstEventType type;
GstEventMinorType minor;
guint64 timestamp; /* also sequence number ?? */
union {
/* EOS stuff */
/* QoS stuff */
/* Seek stuff */
GstSeekType type; /* time, bytes, ... */
gint64 offset;
gint64 lenth;
/* Caps stuff */
GstCaps *caps;
} data;
} GstEvent;
typedef enum {
GST_EVENT_MINOR_NONE,
/* EOS stuff */
/* QoS stuff */
/* Seek stuff */
GST_EVENT_MINOR_OFFSET,
GST_EVENT_MINOR_TIME,
/* caps nego stuff */
GST_EVENT_MINOR_CAPS_TRY,
GST_EVENT_MINOR_CAPS_START,
GST_EVENT_MINOR_CAPS_FINAL,
} GstEventMinorType;
Receiving events
----------------
a sample GstEventFunction, the event functions returns TRUE if the event is handled,
FALSE otherwise.
gboolean
gst_anelement_handle_event (GstPad *pad, GstEvent *event)
{
if (event->type == GST_EVENT_EOS) {
/* do something */
return TRUE;
}
else if (event->type == GST_EVENT_CAPS) {
if (event->minor == GST_EVENT_CAPS_TRY) {
/* try using this caps structure */
return TRUE; /* return FALSE to proxy ???*/
}
}
return FALSE;
}
Default event handler for pads
------------------------------
gboolean
gst_pad_handle_event (GstPad *pad, GstEvent *event)
{
GstElement *element;
GList *pads;
GstPad *srcpad;
gboolean result = TRUE;
GstPadDirection dir = GST_PAD_DIRECTION (pad);
g_return_val_if_fail (pad != NULL, FALSE);
g_return_val_if_fail (GST_IS_REAL_PAD(pad), FALSE); // NOTE the restriction
element = GST_ELEMENT (gst_object_get_parent (GST_OBJECT (pad)));
/* send out the events to all pad with opposite direction */
pads = gst_element_get_pad_list(element);
while (pads) {
otherpad = GST_PAD(pads->data);
pads = g_list_next(pads);
if (gst_pad_get_direction(otherpad) != dir) {
result &= gst_pad_send_event (GST_REAL_PAD(otherpad), event);
}
}
/* result is combined result of all handlers? */
return result;
}

View file

@ -120,6 +120,7 @@ gst_editor_project_new (void)
GstEditorProject *
gst_editor_project_new_from_file (const guchar *fname)
{
#ifndef GST_DISABLE_LOADSAVE
GstEditorProject *editorproject;
GstXML *xml;
GList *elements;
@ -140,8 +141,10 @@ gst_editor_project_new_from_file (const guchar *fname)
elements = g_list_next (elements);
}
return editorproject;
#else
return NULL;
#endif
}
void
@ -162,7 +165,9 @@ gst_editor_project_save_as (GstEditorProject *project, const guchar *fname)
while (elements) {
GstElement *element = (GstElement *) elements->data;
#ifndef GST_DISABLE_LOADSAVE
xmlSaveFile (fname, gst_xml_write (element));
#endif
elements = g_list_next (elements);
}

View file

@ -5,10 +5,16 @@ else
GNOME_SUBDS =
endif
SUBDIRS = $(GNOME_SUBDS) \
if GST_DISABLE_LOADSAVE
GST_LOADSAVE_DIRS =
else
GST_LOADSAVE_DIRS = xml typefind
endif
SUBDIRS = $(GNOME_SUBDS) $(GST_LOADSAVE_DIRS) \
helloworld helloworld2 \
queue queue2 queue3 queue4 \
launch thread xml plugins typefind mixer cutter
launch thread plugins mixer cutter
DIST_SUBDIRS = autoplug \
helloworld helloworld2 \

View file

@ -94,7 +94,9 @@ gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline)
gst_element_set_state (pipeline, GST_STATE_PLAYING);
#ifndef GST_DISABLE_LOADSAVE
xmlSaveFile("xmlTest.gst", gst_xml_write (GST_ELEMENT (pipeline)));
#endif
}
gboolean

View file

@ -182,7 +182,9 @@ int main(int argc,char *argv[])
}
env_register_cp (channel_in->volenv, num_channels * 10.0 , 1.0 / num_channels); /* to end level */
#ifndef GST_DISABLE_LOADSAVE
xmlSaveFile("mixer.xml", gst_xml_write(GST_ELEMENT(main_bin)));
#endif
/* start playing */
gst_element_set_state(main_bin, GST_STATE_PLAYING);
@ -356,7 +358,9 @@ create_input_channel (int id, char* location)
gst_element_get_pad (decoder, "src"), "src_00");
#endif
#ifndef GST_DISABLE_LOADSAVE
xmlSaveFile ("mixer.gst", gst_xml_write (new_element));
#endif
gst_bin_add (GST_BIN(channel->pipe), channel->volenv);
gst_bin_add (GST_BIN (channel->pipe), new_element);

View file

@ -8,6 +8,8 @@ else
GSTARCH_SRCS =
endif
#GST_INSTRUMENT_FLAGS = -finstrument-functions -DGST_ENABLE_FUNC_INSTRUMENTATION
if USE_GLIB2
GST_OBJECT_MODEL_SRC = gstmarshal.c
GST_OBJECT_MODEL_HDR = gstmarshal.h
@ -67,6 +69,7 @@ libgst_la_SOURCES = \
gstcpu.c \
gstelement.c \
gstelementfactory.c \
gstevent.c \
gstextratypes.c \
gstinfo.c \
gstpad.c \
@ -154,6 +157,7 @@ libgstincludedir = $(includedir)/gst
libgstinclude_HEADERS = \
cothreads.h \
gst.h \
gstconfig.h \
$(GST_OBJECT_MODEL_HDR) \
gstobject.h \
gsttypes.h \
@ -164,6 +168,7 @@ libgstinclude_HEADERS = \
gstcaps.h \
gstclock.h \
gstcpu.h \
gstdata.h \
gstelement.h \
gstevent.h \
gstextratypes.h \
@ -203,6 +208,7 @@ CFLAGS = \
-Wnested-externs \
-Winline -Wno-unused
CFLAGS = $(LIBGST_CFLAGS) -D_GNU_SOURCE -DGST_CONFIG_DIR=\""$(GST_CONFIG_DIR)"\" -Wall
LIBS = $(LIBGST_LIBS)
LDFLAGS = ""
libgst_la_LDFLAGS = -version-info $(GST_LIBVERSION)

View file

@ -430,7 +430,7 @@ gst_autoplugger_cache_empty(GstElement *element, GstAutoplugger *autoplugger)
// try to PLAY the whole thing
gst_element_set_state(GST_ELEMENT_SCHED(autoplugger)->parent,GST_STATE_PLAYING);
xmlSaveFile("autoplugger.gst", gst_xml_write(GST_ELEMENT_SCHED(autoplugger)->parent));
// xmlSaveFile("autoplugger.gst", gst_xml_write(GST_ELEMENT_SCHED(autoplugger)->parent));
GST_INFO(GST_CAT_AUTOPLUG, "autoplugger_cache_empty finished");
}

View file

@ -8,6 +8,8 @@ else
GSTHTTPSRC=
endif
#CFLAGS += -O2 -Wall -finstrument-functions -DGST_ENABLE_FUNC_INSTRUMENTATION
libgstelements_la_DEPENDENCIES = ../libgst.la
libgstelements_la_SOURCES = \
gstelements.c \
@ -37,8 +39,10 @@ noinst_HEADERS = \
gstfdsink.h \
gstpipefilter.h \
gsttee.h \
gstaggregator.h
CFLAGS += -O2 -Wall
gstaggregator.h \
gstsinesrc.h
CFLAGS += -O2 -Wall
LDFLAGS += -lm
libgstelements_la_LIBADD = $(GHTTP_LIBS)

View file

@ -76,7 +76,8 @@ gst_aggregator_sched_get_type (void)
static void gst_aggregator_class_init (GstAggregatorClass *klass);
static void gst_aggregator_init (GstAggregator *aggregator);
static GstPad* gst_aggregator_request_new_pad (GstElement *element, GstPadTemplate *temp);
static GstPad* gst_aggregator_request_new_pad (GstElement *element, GstPadTemplate *temp, const
gchar *unused);
static void gst_aggregator_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec);
@ -150,7 +151,7 @@ gst_aggregator_init (GstAggregator *aggregator)
}
static GstPad*
gst_aggregator_request_new_pad (GstElement *element, GstPadTemplate *templ)
gst_aggregator_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *unused)
{
gchar *name;
GstPad *sinkpad;

View file

@ -64,8 +64,8 @@ static void gst_disksrc_set_property (GObject *object, guint prop_id,
static void gst_disksrc_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec);
static GstBuffer * gst_disksrc_get (GstPad *pad);
static GstBuffer * gst_disksrc_get_region (GstPad *pad,GstRegionType type,guint64 offset,guint64 len);
static GstBuffer* gst_disksrc_get (GstPad *pad);
static GstBufferPool* gst_disksrc_get_bufferpool (GstPad *pad);
static GstElementStateReturn
gst_disksrc_change_state (GstElement *element);
@ -73,7 +73,7 @@ static GstElementStateReturn
static gboolean gst_disksrc_open_file (GstDiskSrc *src);
static void gst_disksrc_close_file (GstDiskSrc *src);
static GstElementClass *parent_class = NULL;
static GstElementClass* parent_class = NULL;
//static guint gst_disksrc_signals[LAST_SIGNAL] = { 0 };
GType
@ -133,8 +133,8 @@ gst_disksrc_init (GstDiskSrc *disksrc)
// GST_FLAG_SET (disksrc, GST_SRC_);
disksrc->srcpad = gst_pad_new ("src", GST_PAD_SRC);
gst_pad_set_get_function (disksrc->srcpad,gst_disksrc_get);
gst_pad_set_getregion_function (disksrc->srcpad,gst_disksrc_get_region);
gst_pad_set_get_function (disksrc->srcpad, gst_disksrc_get);
gst_pad_set_bufferpool_function (disksrc->srcpad, gst_disksrc_get_bufferpool);
gst_element_add_pad (GST_ELEMENT (disksrc), disksrc->srcpad);
disksrc->filename = NULL;
@ -220,6 +220,56 @@ gst_disksrc_get_property (GObject *object, guint prop_id, GValue *value, GParamS
}
}
static GstBuffer*
gst_disksrc_buffer_new (GstBufferPool *pool, gint64 location, gint size, gpointer user_data)
{
GstDiskSrc *src;
GstBuffer *buf;
src = GST_DISKSRC (user_data);
buf = gst_buffer_new ();
g_return_val_if_fail (buf != NULL, NULL);
/* simply set the buffer to point to the correct region of the file */
GST_BUFFER_DATA (buf) = src->map + location;
GST_BUFFER_OFFSET (buf) = location;
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_DONTFREE);
if ((location + size) > src->size)
GST_BUFFER_SIZE (buf) = src->size - location;
else
GST_BUFFER_SIZE (buf) = size;
GST_DEBUG (0,"map %p, offset %ld (%p), size %d\n", src->map, src->curoffset,
src->map + src->curoffset, GST_BUFFER_SIZE (buf));
return buf;
}
static void
gst_disksrc_buffer_free (GstBuffer *buf)
{
// FIXME do something here
}
static GstBufferPool*
gst_disksrc_get_bufferpool (GstPad *pad)
{
GstDiskSrc *src;
src = GST_DISKSRC (gst_pad_get_parent (pad));
if (!src->bufferpool) {
src->bufferpool = gst_buffer_pool_new ();
gst_buffer_pool_set_buffer_new_function (src->bufferpool, gst_disksrc_buffer_new);
gst_buffer_pool_set_buffer_free_function (src->bufferpool, gst_disksrc_buffer_free);
gst_buffer_pool_set_user_data (src->bufferpool, src);
}
return src->bufferpool;
}
/**
* gst_disksrc_get:
* @pad: #GstPad to push a buffer from
@ -246,28 +296,10 @@ gst_disksrc_get (GstPad *pad)
return buf;
}
/* create the buffer */
// FIXME: should eventually use a bufferpool for this
buf = gst_buffer_new ();
g_return_val_if_fail (buf != NULL, NULL);
/* simply set the buffer to point to the correct region of the file */
GST_BUFFER_DATA (buf) = src->map + src->curoffset;
GST_BUFFER_OFFSET (buf) = src->curoffset;
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_DONTFREE);
if ((src->curoffset + src->bytes_per_read) > src->size) {
GST_BUFFER_SIZE (buf) = src->size - src->curoffset;
// FIXME: set the buffer's EOF bit here
} else
GST_BUFFER_SIZE (buf) = src->bytes_per_read;
GST_DEBUG (0,"map %p, offset %ld (%p), size %d\n", src->map, src->curoffset,
src->map + src->curoffset, GST_BUFFER_SIZE (buf));
// FIXME use a bufferpool
buf = gst_disksrc_buffer_new (NULL, src->curoffset, src->bytes_per_read, src);
//gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
src->curoffset += GST_BUFFER_SIZE (buf);
if (src->new_seek) {
@ -280,61 +312,6 @@ gst_disksrc_get (GstPad *pad)
return buf;
}
/**
* gst_disksrc_get_region:
* @src: #GstSrc to push a buffer from
* @offset: offset in file
* @size: number of bytes
*
* Push a new buffer from the disksrc of given size at given offset.
*/
static GstBuffer *
gst_disksrc_get_region (GstPad *pad, GstRegionType type,guint64 offset,guint64 len)
{
GstDiskSrc *src;
GstBuffer *buf;
g_return_val_if_fail (pad != NULL, NULL);
g_return_val_if_fail (type == GST_REGION_OFFSET_LEN, NULL);
src = GST_DISKSRC (gst_pad_get_parent (pad));
g_return_val_if_fail (GST_IS_DISKSRC (src), NULL);
g_return_val_if_fail (GST_FLAG_IS_SET (src, GST_DISKSRC_OPEN), NULL);
/* deal with EOF state */
if (offset >= src->size) {
gst_pad_event (pad, GST_EVENT_EOS, 0LL, 0);
GST_DEBUG (0,"map offset %lld >= size %ld --> eos\n", offset, src->size);
//FIXME
buf = gst_buffer_new();
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_EOS);
return buf;
}
/* create the buffer */
// FIXME: should eventually use a bufferpool for this
buf = gst_buffer_new ();
g_return_val_if_fail (buf != NULL, NULL);
/* simply set the buffer to point to the correct region of the file */
GST_BUFFER_DATA (buf) = src->map + offset;
GST_BUFFER_OFFSET (buf) = offset;
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_DONTFREE);
if ((offset + len) > src->size) {
GST_BUFFER_SIZE (buf) = src->size - offset;
// FIXME: set the buffer's EOF bit here
} else
GST_BUFFER_SIZE (buf) = len;
GST_DEBUG (0,"map %p, offset %lld, size %d\n", src->map, offset, GST_BUFFER_SIZE (buf));
/* we're done, return the buffer off now */
return buf;
}
/* open the file and mmap it, necessary to go to READY state */
static gboolean
gst_disksrc_open_file (GstDiskSrc *src)

View file

@ -64,6 +64,7 @@ struct _GstDiskSrc {
gchar *filename;
/* fd */
gint fd;
GstBufferPool *bufferpool;
/* mapping parameters */
gulong size; /* how long is the file? */

View file

@ -45,6 +45,7 @@ enum {
ARG_0,
ARG_NUM_SINKS,
ARG_SILENT,
ARG_DUMP,
};
GST_PADTEMPLATE_FACTORY (fakesink_sink_factory,
@ -58,7 +59,8 @@ GST_PADTEMPLATE_FACTORY (fakesink_sink_factory,
static void gst_fakesink_class_init (GstFakeSinkClass *klass);
static void gst_fakesink_init (GstFakeSink *fakesink);
static GstPad* gst_fakesink_request_new_pad (GstElement *element, GstPadTemplate *templ);
static GstPad* gst_fakesink_request_new_pad (GstElement *element, GstPadTemplate *templ, const
gchar *unused);
static void gst_fakesink_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec);
@ -66,7 +68,6 @@ static void gst_fakesink_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec);
static void gst_fakesink_chain (GstPad *pad, GstBuffer *buf);
static gboolean gst_fakesink_event (GstPad *pad, GstEventType event, guint64 timestamp, guint32 data);
static GstElementClass *parent_class = NULL;
static guint gst_fakesink_signals[LAST_SIGNAL] = { 0 };
@ -109,6 +110,9 @@ gst_fakesink_class_init (GstFakeSinkClass *klass)
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
g_param_spec_boolean ("silent", "silent", "silent",
FALSE, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DUMP,
g_param_spec_boolean ("dump", "dump", "dump",
FALSE, G_PARAM_READWRITE));
gst_fakesink_signals[SIGNAL_HANDOFF] =
g_signal_new ("handoff", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
@ -129,15 +133,15 @@ gst_fakesink_init (GstFakeSink *fakesink)
pad = gst_pad_new ("sink", GST_PAD_SINK);
gst_element_add_pad (GST_ELEMENT (fakesink), pad);
gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_fakesink_chain));
gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_fakesink_event));
fakesink->sinkpads = g_slist_prepend (NULL, pad);
fakesink->numsinkpads = 1;
fakesink->silent = FALSE;
fakesink->dump = FALSE;
}
static GstPad*
gst_fakesink_request_new_pad (GstElement *element, GstPadTemplate *templ)
gst_fakesink_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *unused)
{
gchar *name;
GstPad *sinkpad;
@ -175,6 +179,9 @@ gst_fakesink_set_property (GObject *object, guint prop_id, const GValue *value,
case ARG_SILENT:
sink->silent = g_value_get_boolean (value);
break;
case ARG_DUMP:
sink->dump = g_value_get_boolean (value);
break;
default:
break;
}
@ -197,6 +204,9 @@ gst_fakesink_get_property (GObject *object, guint prop_id, GValue *value, GParam
case ARG_SILENT:
g_value_set_boolean (value, sink->silent);
break;
case ARG_DUMP:
g_value_set_boolean (value, sink->dump);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -206,9 +216,9 @@ gst_fakesink_get_property (GObject *object, guint prop_id, GValue *value, GParam
/**
* gst_fakesink_chain:
* @pad: the pad this faksink is connected to
* @buf: the buffer that has to be absorbed
* @buffer: the buffer or event that has to be absorbed
*
* take the buffer from the pad and unref it without doing
* Take the buffer or event from the pad and unref it without doing
* anything with it.
*/
static void
@ -221,12 +231,33 @@ gst_fakesink_chain (GstPad *pad, GstBuffer *buf)
g_return_if_fail (buf != NULL);
fakesink = GST_FAKESINK (gst_pad_get_parent (pad));
if (GST_IS_EVENT(buf)) {
GstEvent *event = GST_EVENT (buf);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_EOS:
g_print("fakesink: have EOS event!\n");
gst_element_set_state (GST_ELEMENT (fakesink), GST_STATE_PAUSED);
break;
default:
g_print("fakesink: have unhandled event!\n");
break;
}
gst_event_free (event);
return;
}
if (!fakesink->silent)
g_print("fakesink: chain ******* (%s:%s)< (%d bytes, %lld) \n",
GST_DEBUG_PAD_NAME (pad), GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf));
g_signal_emit (G_OBJECT (fakesink), gst_fakesink_signals[SIGNAL_HANDOFF], 0,
buf);
g_print("fakesink: chain ******* (%s:%s)< (%d bytes, %lld) %p\n",
GST_DEBUG_PAD_NAME (pad), GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf), buf);
g_signal_emit (G_OBJECT (fakesink), gst_fakesink_signals[SIGNAL_HANDOFF], 0, buf, pad);
if (fakesink->dump)
{
gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
}
gst_buffer_unref (buf);
}
@ -238,14 +269,3 @@ gst_fakesink_factory_init (GstElementFactory *factory)
return TRUE;
}
static gboolean
gst_fakesink_event (GstPad *pad, GstEventType event, guint64 timestamp, guint32 data)
{
GST_DEBUG (GST_CAT_EVENT, "fakesink has event %d on pad %s:%s\n",event,GST_DEBUG_PAD_NAME(pad));
if (event == GST_EVENT_EOS) {
GST_DEBUG(GST_CAT_EVENT, "have EOS\n");
}
}

View file

@ -57,6 +57,7 @@ struct _GstFakeSink {
GSList *sinkpads;
gint numsinkpads;
gboolean silent;
gboolean dump;
};
struct _GstFakeSinkClass {

View file

@ -21,6 +21,9 @@
*/
#include <stdlib.h>
#include <string.h>
#include <gstfakesrc.h>
@ -47,10 +50,17 @@ enum {
ARG_NUM_SOURCES,
ARG_LOOP_BASED,
ARG_OUTPUT,
ARG_DATA,
ARG_SIZETYPE,
ARG_SIZEMIN,
ARG_SIZEMAX,
ARG_FILLTYPE,
ARG_PATTERN,
ARG_NUM_BUFFERS,
ARG_EOS,
ARG_SILENT
ARG_SILENT,
ARG_DUMP,
ARG_PARENTSIZE
};
GST_PADTEMPLATE_FACTORY (fakesrc_src_factory,
@ -82,12 +92,69 @@ gst_fakesrc_output_get_type (void)
return fakesrc_output_type;
}
#define GST_TYPE_FAKESRC_DATA (gst_fakesrc_data_get_type())
static GType
gst_fakesrc_data_get_type (void)
{
static GType fakesrc_data_type = 0;
static GEnumValue fakesrc_data[] = {
{ FAKESRC_DATA_ALLOCATE, "2", "Allocate data"},
{ FAKESRC_DATA_SUBBUFFER, "3", "Subbuffer data"},
{0, NULL, NULL},
};
if (!fakesrc_data_type) {
fakesrc_data_type = g_enum_register_static ("GstFakeSrcData", fakesrc_data);
}
return fakesrc_data_type;
}
#define GST_TYPE_FAKESRC_SIZETYPE (gst_fakesrc_sizetype_get_type())
static GType
gst_fakesrc_sizetype_get_type (void)
{
static GType fakesrc_sizetype_type = 0;
static GEnumValue fakesrc_sizetype[] = {
{ FAKESRC_SIZETYPE_NULL, "1", "Send empty buffers"},
{ FAKESRC_SIZETYPE_FIXED, "2", "Fixed size buffers (sizemax sized)"},
{ FAKESRC_SIZETYPE_RANDOM, "3", "Random sized buffers (sizemin <= size <= sizemax)"},
{0, NULL, NULL},
};
if (!fakesrc_sizetype_type) {
fakesrc_sizetype_type = g_enum_register_static ("GstFakeSrcSizeType", fakesrc_sizetype);
}
return fakesrc_sizetype_type;
}
#define GST_TYPE_FAKESRC_FILLTYPE (gst_fakesrc_filltype_get_type())
static GType
gst_fakesrc_filltype_get_type (void)
{
static GType fakesrc_filltype_type = 0;
static GEnumValue fakesrc_filltype[] = {
{ FAKESRC_FILLTYPE_NOTHING, "1", "Leave data as malloced"},
{ FAKESRC_FILLTYPE_NULL, "2", "Fill buffers with zeros"},
{ FAKESRC_FILLTYPE_RANDOM, "3", "Fill buffers with random crap"},
{ FAKESRC_FILLTYPE_PATTERN, "4", "Fill buffers with pattern 0x00 -> 0xff"},
{ FAKESRC_FILLTYPE_PATTERN_CONT, "5", "Fill buffers with pattern 0x00 -> 0xff that spans buffers"},
{0, NULL, NULL},
};
if (!fakesrc_filltype_type) {
fakesrc_filltype_type = g_enum_register_static ("GstFakeSrcFillType", fakesrc_filltype);
}
return fakesrc_filltype_type;
}
static void gst_fakesrc_class_init (GstFakeSrcClass *klass);
static void gst_fakesrc_init (GstFakeSrc *fakesrc);
static GstPad* gst_fakesrc_request_new_pad (GstElement *element, GstPadTemplate *templ);
static void gst_fakesrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
static void gst_fakesrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
static void gst_fakesrc_update_functions (GstFakeSrc *src);
static void gst_fakesrc_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec);
static void gst_fakesrc_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec);
static GstElementStateReturn gst_fakesrc_change_state (GstElement *element);
static GstBuffer* gst_fakesrc_get (GstPad *pad);
static void gst_fakesrc_loop (GstElement *element);
@ -137,6 +204,24 @@ gst_fakesrc_class_init (GstFakeSrcClass *klass)
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_OUTPUT,
g_param_spec_enum("output","output","output",
GST_TYPE_FAKESRC_OUTPUT,FAKESRC_FIRST_LAST_LOOP,G_PARAM_READWRITE)); // CHECKME!
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DATA,
g_param_spec_enum ("data", "data", "data",
GST_TYPE_FAKESRC_DATA, FAKESRC_DATA_ALLOCATE, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIZETYPE,
g_param_spec_enum ("sizetype", "sizetype", "sizetype",
GST_TYPE_FAKESRC_SIZETYPE, FAKESRC_SIZETYPE_NULL, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIZEMIN,
g_param_spec_int ("sizemin","sizemin","sizemin",
0, G_MAXINT, 0, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIZEMAX,
g_param_spec_int ("sizemax","sizemax","sizemax",
0, G_MAXINT, 4096, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PARENTSIZE,
g_param_spec_int ("parentsize","parentsize","parentsize",
0, G_MAXINT, 4096 * 10, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FILLTYPE,
g_param_spec_enum ("filltype", "filltype", "filltype",
GST_TYPE_FAKESRC_FILLTYPE, FAKESRC_FILLTYPE_NULL, G_PARAM_READWRITE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_PATTERN,
g_param_spec_string("pattern","pattern","pattern",
NULL, G_PARAM_READWRITE)); // CHECKME
@ -149,6 +234,9 @@ gst_fakesrc_class_init (GstFakeSrcClass *klass)
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SILENT,
g_param_spec_boolean("silent","silent","silent",
FALSE, G_PARAM_READWRITE)); // CHECKME
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DUMP,
g_param_spec_boolean ("dump","dump","dump",
FALSE, G_PARAM_READWRITE));
gst_fakesrc_signals[SIGNAL_HANDOFF] =
g_signal_new ("handoff", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
@ -159,7 +247,8 @@ gst_fakesrc_class_init (GstFakeSrcClass *klass)
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesrc_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesrc_get_property);
gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR (gst_fakesrc_request_new_pad);
gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR (gst_fakesrc_request_new_pad);
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_fakesrc_change_state);
}
static void
@ -176,17 +265,21 @@ gst_fakesrc_init (GstFakeSrc *fakesrc)
fakesrc->srcpads = g_slist_append (NULL, pad);
fakesrc->loop_based = FALSE;
if (fakesrc->loop_based)
gst_element_set_loop_function (GST_ELEMENT (fakesrc), GST_DEBUG_FUNCPTR (gst_fakesrc_loop));
else
gst_pad_set_get_function (pad, GST_DEBUG_FUNCPTR (gst_fakesrc_get));
gst_fakesrc_update_functions (fakesrc);
fakesrc->num_buffers = -1;
fakesrc->buffer_count = 0;
fakesrc->silent = FALSE;
// we're ready right away, since we don't have any args...
// gst_element_set_state(GST_ELEMENT(fakesrc),GST_STATE_READY);
fakesrc->dump = FALSE;
fakesrc->pattern_byte = 0x00;
fakesrc->need_flush = FALSE;
fakesrc->data = FAKESRC_DATA_ALLOCATE;
fakesrc->sizetype = FAKESRC_SIZETYPE_NULL;
fakesrc->filltype = FAKESRC_FILLTYPE_NOTHING;
fakesrc->sizemin = 0;
fakesrc->sizemax = 4096;
fakesrc->parent = NULL;
fakesrc->parentsize = 4096 * 10;
}
static GstPad*
@ -216,6 +309,34 @@ gst_fakesrc_request_new_pad (GstElement *element, GstPadTemplate *templ)
return srcpad;
}
static gboolean
gst_fakesrc_event_handler (GstPad *pad, GstEvent *event)
{
GstFakeSrc *src;
src = GST_FAKESRC (gst_pad_get_parent (pad));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK:
g_print("fakesrc: have seek event\n");
src->buffer_count = GST_EVENT_SEEK_OFFSET (event);
if (!GST_EVENT_SEEK_FLUSH (event)) {
gst_event_free (event);
break;
}
// else we do a flush too
case GST_EVENT_FLUSH:
g_print("fakesrc: have flush event\n");
src->need_flush = TRUE;
break;
default:
g_print("fakesrc: have unhandled event\n");
break;
}
return TRUE;
}
static void
gst_fakesrc_update_functions (GstFakeSrc *src)
{
@ -238,10 +359,25 @@ gst_fakesrc_update_functions (GstFakeSrc *src)
else {
gst_pad_set_get_function (pad, GST_DEBUG_FUNCPTR (gst_fakesrc_get));
}
gst_pad_set_event_function (pad, gst_fakesrc_event_handler);
pads = g_slist_next (pads);
}
}
static void
gst_fakesrc_alloc_parent (GstFakeSrc *src)
{
GstBuffer *buf;
buf = gst_buffer_new ();
GST_BUFFER_DATA (buf) = g_malloc (src->parentsize);
GST_BUFFER_SIZE (buf) = src->parentsize;
src->parent = buf;
src->parentoffset = 0;
}
static void
gst_fakesrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
@ -257,6 +393,37 @@ gst_fakesrc_set_property (GObject *object, guint prop_id, const GValue *value, G
break;
case ARG_OUTPUT:
break;
case ARG_DATA:
src->data = g_value_get_int (value);
switch (src->data) {
case FAKESRC_DATA_ALLOCATE:
if (src->parent) {
gst_buffer_unref (src->parent);
src->parent = NULL;
}
break;
case FAKESRC_DATA_SUBBUFFER:
if (!src->parent)
gst_fakesrc_alloc_parent (src);
default:
break;
}
break;
case ARG_SIZETYPE:
src->sizetype = g_value_get_int (value);
break;
case ARG_SIZEMIN:
src->sizemin = g_value_get_int (value);
break;
case ARG_SIZEMAX:
src->sizemax = g_value_get_int (value);
break;
case ARG_PARENTSIZE:
src->parentsize = g_value_get_int (value);
break;
case ARG_FILLTYPE:
src->filltype = g_value_get_int (value);
break;
case ARG_PATTERN:
break;
case ARG_NUM_BUFFERS:
@ -269,6 +436,9 @@ GST_INFO (0, "will EOS on next buffer");
case ARG_SILENT:
src->silent = g_value_get_boolean (value);
break;
case ARG_DUMP:
src->dump = g_value_get_boolean (value);
break;
default:
break;
}
@ -294,6 +464,24 @@ gst_fakesrc_get_property (GObject *object, guint prop_id, GValue *value, GParamS
case ARG_OUTPUT:
g_value_set_int (value, src->output);
break;
case ARG_DATA:
g_value_set_int (value, src->data);
break;
case ARG_SIZETYPE:
g_value_set_int (value, src->sizetype);
break;
case ARG_SIZEMIN:
g_value_set_int (value, src->sizemin);
break;
case ARG_SIZEMAX:
g_value_set_int (value, src->sizemax);
break;
case ARG_PARENTSIZE:
g_value_set_int (value, src->parentsize);
break;
case ARG_FILLTYPE:
g_value_set_int (value, src->filltype);
break;
case ARG_PATTERN:
g_value_set_string (value, src->pattern);
break;
@ -306,21 +494,150 @@ gst_fakesrc_get_property (GObject *object, guint prop_id, GValue *value, GParamS
case ARG_SILENT:
g_value_set_boolean (value, src->silent);
break;
case ARG_DUMP:
g_value_set_boolean (value, src->dump);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_fakesrc_prepare_buffer (GstFakeSrc *src, GstBuffer *buf)
{
if (GST_BUFFER_SIZE (buf) == 0)
return;
switch (src->filltype) {
case FAKESRC_FILLTYPE_NULL:
memset (GST_BUFFER_DATA (buf), 0, GST_BUFFER_SIZE (buf));
break;
case FAKESRC_FILLTYPE_RANDOM:
{
gint i;
guint8 *ptr = GST_BUFFER_DATA (buf);
for (i = GST_BUFFER_SIZE (buf); i; i--) {
*ptr++ = (gint8)((255.0)*rand()/(RAND_MAX));
}
break;
}
case FAKESRC_FILLTYPE_PATTERN:
src->pattern_byte = 0x00;
case FAKESRC_FILLTYPE_PATTERN_CONT:
{
gint i;
guint8 *ptr = GST_BUFFER_DATA (buf);
for (i = GST_BUFFER_SIZE (buf); i; i--) {
*ptr++ = src->pattern_byte++;
}
break;
}
case FAKESRC_FILLTYPE_NOTHING:
default:
break;
}
}
static GstBuffer*
gst_fakesrc_alloc_buffer (GstFakeSrc *src, guint size)
{
GstBuffer *buf;
buf = gst_buffer_new ();
GST_BUFFER_SIZE(buf) = size;
if (size != 0) {
switch (src->filltype) {
case FAKESRC_FILLTYPE_NOTHING:
GST_BUFFER_DATA(buf) = g_malloc (size);
break;
case FAKESRC_FILLTYPE_NULL:
GST_BUFFER_DATA(buf) = g_malloc0 (size);
break;
case FAKESRC_FILLTYPE_RANDOM:
case FAKESRC_FILLTYPE_PATTERN:
case FAKESRC_FILLTYPE_PATTERN_CONT:
default:
GST_BUFFER_DATA(buf) = g_malloc (size);
gst_fakesrc_prepare_buffer (src, buf);
break;
}
}
return buf;
}
static guint
gst_fakesrc_get_size (GstFakeSrc *src)
{
guint size;
switch (src->sizetype) {
case FAKESRC_SIZETYPE_FIXED:
size = src->sizemax;
break;
case FAKESRC_SIZETYPE_RANDOM:
size = src->sizemin + (guint8)(((gfloat)src->sizemax)*rand()/(RAND_MAX + (gfloat)src->sizemin));
break;
case FAKESRC_SIZETYPE_NULL:
default:
size = 0;
break;
}
return size;
}
static GstBuffer *
gst_fakesrc_create_buffer (GstFakeSrc *src)
{
GstBuffer *buf;
guint size;
gboolean dump = src->dump;
size = gst_fakesrc_get_size (src);
if (size == 0)
return gst_buffer_new();
switch (src->data) {
case FAKESRC_DATA_ALLOCATE:
buf = gst_fakesrc_alloc_buffer (src, size);
break;
case FAKESRC_DATA_SUBBUFFER:
// see if we have a parent to subbuffer
if (!src->parent) {
gst_fakesrc_alloc_parent (src);
g_assert (src->parent);
}
// see if it's large enough
if ((GST_BUFFER_SIZE (src->parent) - src->parentoffset) >= size) {
buf = gst_buffer_create_sub (src->parent, src->parentoffset, size);
src->parentoffset += size;
}
else {
// the parent is useless now
gst_buffer_unref (src->parent);
src->parent = NULL;
// try again (this will allocate a new parent)
return gst_fakesrc_create_buffer (src);
}
gst_fakesrc_prepare_buffer (src, buf);
break;
default:
g_warning ("fakesrc: dunno how to allocate buffers !");
buf = gst_buffer_new();
break;
}
if (dump) {
gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
}
return buf;
}
/**
* gst_fakesrc_get:
* @src: the faksesrc to get
*
* generate an empty buffer and return it
*
* Returns: a new empty buffer
*/
static GstBuffer *
gst_fakesrc_get(GstPad *pad)
{
@ -333,9 +650,16 @@ gst_fakesrc_get(GstPad *pad)
g_return_val_if_fail (GST_IS_FAKESRC (src), NULL);
if (src->need_flush) {
src->need_flush = FALSE;
g_print("fakesrc: sending FLUSH\n");
return GST_BUFFER(gst_event_new (GST_EVENT_FLUSH));
}
if (src->num_buffers == 0) {
gst_pad_event (pad, GST_EVENT_EOS, 0LL, 0);
return NULL;
g_print("fakesrc: sending EOS\n");
gst_element_set_state (GST_ELEMENT (src), GST_STATE_PAUSED);
return GST_BUFFER(gst_event_new (GST_EVENT_EOS));
}
else {
if (src->num_buffers > 0)
@ -344,11 +668,11 @@ gst_fakesrc_get(GstPad *pad)
if (src->eos) {
GST_INFO (0, "fakesrc is setting eos on pad");
gst_pad_event (pad, GST_EVENT_EOS, 0LL, 0);
return NULL;
g_print("fakesrc: sending EOS\n");
return GST_BUFFER(gst_event_new (GST_EVENT_EOS));
}
buf = gst_buffer_new();
buf = gst_fakesrc_create_buffer (src);
GST_BUFFER_TIMESTAMP (buf) = src->buffer_count++;
if (!src->silent)
@ -356,7 +680,7 @@ gst_fakesrc_get(GstPad *pad)
GST_DEBUG_PAD_NAME (pad), GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf));
g_signal_emit (G_OBJECT (src), gst_fakesrc_signals[SIGNAL_HANDOFF], 0,
buf);
buf, pad);
return buf;
}
@ -387,21 +711,20 @@ gst_fakesrc_loop(GstElement *element)
GstBuffer *buf;
if (src->num_buffers == 0) {
gst_pad_event (pad, GST_EVENT_EOS, 0LL, 0);
return;
src->eos = TRUE;
}
else {
if (src->num_buffers > 0)
src->num_buffers--;
if (src->num_buffers > 0)
src->num_buffers--;
}
if (src->eos) {
GST_INFO (0, "fakesrc is setting eos on pad");
gst_pad_event (pad, GST_EVENT_EOS, 0LL, 0);
return;
gst_pad_push(pad, GST_BUFFER(gst_event_new (GST_EVENT_EOS)));
return;
}
buf = gst_buffer_new();
buf = gst_fakesrc_create_buffer (src);
GST_BUFFER_TIMESTAMP (buf) = src->buffer_count++;
if (!src->silent)
@ -409,7 +732,7 @@ gst_fakesrc_loop(GstElement *element)
GST_DEBUG_PAD_NAME (pad), GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf));
g_signal_emit (G_OBJECT (src), gst_fakesrc_signals[SIGNAL_HANDOFF], 0,
buf);
buf, pad);
gst_pad_push (pad, buf);
pads = g_slist_next (pads);
@ -417,6 +740,31 @@ gst_fakesrc_loop(GstElement *element)
} while (!GST_ELEMENT_IS_COTHREAD_STOPPING (element));
}
static GstElementStateReturn
gst_fakesrc_change_state (GstElement *element)
{
GstFakeSrc *fakesrc;
g_return_val_if_fail (GST_IS_FAKESRC (element), GST_STATE_FAILURE);
fakesrc = GST_FAKESRC (element);
if (GST_STATE_PENDING (element) == GST_STATE_READY) {
fakesrc->buffer_count = 0;
fakesrc->pattern_byte = 0x00;
fakesrc->need_flush = FALSE;
if (fakesrc->parent) {
gst_buffer_unref (fakesrc->parent);
fakesrc->parent = NULL;
}
}
if (GST_ELEMENT_CLASS (parent_class)->change_state)
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
return GST_STATE_SUCCESS;
}
gboolean
gst_fakesrc_factory_init (GstElementFactory *factory)
{

View file

@ -47,6 +47,25 @@ typedef enum {
FAKESRC_GET_ALWAYS_SUCEEDS,
} GstFakeSrcOutputType;
typedef enum {
FAKESRC_DATA_ALLOCATE = 1,
FAKESRC_DATA_SUBBUFFER,
} GstFakeSrcDataType;
typedef enum {
FAKESRC_SIZETYPE_NULL = 1,
FAKESRC_SIZETYPE_FIXED,
FAKESRC_SIZETYPE_RANDOM
} GstFakeSrcSizeType;
typedef enum {
FAKESRC_FILLTYPE_NOTHING = 1,
FAKESRC_FILLTYPE_NULL,
FAKESRC_FILLTYPE_RANDOM,
FAKESRC_FILLTYPE_PATTERN,
FAKESRC_FILLTYPE_PATTERN_CONT
} GstFakeSrcFillType;
#define GST_TYPE_FAKESRC \
(gst_fakesrc_get_type())
#define GST_FAKESRC(obj) \
@ -64,16 +83,29 @@ typedef struct _GstFakeSrcClass GstFakeSrcClass;
struct _GstFakeSrc {
GstElement element;
gboolean loop_based;
gboolean eos;
gint numsrcpads;
GSList *srcpads;
gboolean loop_based;
gboolean eos;
gint numsrcpads;
GSList *srcpads;
GstFakeSrcOutputType output;
gchar *pattern;
GList *patternlist;
gint num_buffers;
guint64 buffer_count;
gboolean silent;
GstFakeSrcDataType data;
GstFakeSrcSizeType sizetype;
GstFakeSrcFillType filltype;
guint sizemin;
guint sizemax;
GstBuffer *parent;
guint parentsize;
guint parentoffset;
guint8 pattern_byte;
gchar *pattern;
GList *patternlist;
gint num_buffers;
guint64 buffer_count;
gboolean silent;
gboolean dump;
gboolean need_flush;
};
struct _GstFakeSrcClass {

View file

@ -27,6 +27,7 @@
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
/**********************************************************************
@ -74,6 +75,9 @@ GstElementDetails gst_filesrc_details = {
"(C) 1999",
};
//#define fs_print(format,args...) g_print(format, ## args)
#define fs_print(format,args...)
#define GST_TYPE_FILESRC \
(gst_filesrc_get_type())
@ -110,10 +114,12 @@ struct _GstFileSrc {
gboolean touch; // whether to touch every page
GstBuffer *mapbuf;
off_t mapsize;
size_t mapsize;
GTree *map_regions;
GMutex *map_regions_lock;
gboolean seek_happened;
};
struct _GstFileSrcClass {
@ -135,6 +141,7 @@ enum {
ARG_BLOCKSIZE,
ARG_OFFSET,
ARG_MAPSIZE,
ARG_TOUCH,
};
@ -203,6 +210,9 @@ gst_filesrc_class_init (GstFileSrcClass *klass)
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MAPSIZE,
g_param_spec_ulong("mmapsize","mmap() Block Size","Size in bytes of mmap()d regions",
0,G_MAXULONG,4*1048576,G_PARAM_READWRITE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_TOUCH,
g_param_spec_boolean("touch","Touch read data","Touch data to force disk read before push()",
TRUE,G_PARAM_READWRITE));
gobject_class->set_property = gst_filesrc_set_property;
gobject_class->get_property = gst_filesrc_get_property;
@ -246,6 +256,8 @@ gst_filesrc_init (GstFileSrc *src)
src->map_regions = g_tree_new(gst_filesrc_bufcmp);
src->map_regions_lock = g_mutex_new();
src->seek_happened = FALSE;
}
@ -286,6 +298,9 @@ gst_filesrc_set_property (GObject *object, guint prop_id, const GValue *value, G
else
GST_INFO(0, "invalid mapsize, must a multiple of pagesize, which is %d\n",src->pagesize);
break;
case ARG_TOUCH:
src->touch = g_value_get_boolean (value);
break;
default:
break;
}
@ -320,6 +335,9 @@ gst_filesrc_get_property (GObject *object, guint prop_id, GValue *value, GParamS
case ARG_MAPSIZE:
g_value_set_ulong (value, src->mapsize);
break;
case ARG_TOUCH:
g_value_set_boolean (value, src->touch);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -331,7 +349,7 @@ gst_filesrc_free_parent_mmap (GstBuffer *buf)
{
GstFileSrc *src = GST_FILESRC(GST_BUFFER_POOL_PRIVATE(buf));
// fprintf(stderr,"freeing mmap()d buffer at %d+%d\n",GST_BUFFER_OFFSET(buf),GST_BUFFER_SIZE(buf));
fs_print ("freeing mmap()d buffer at %d+%d\n",GST_BUFFER_OFFSET(buf),GST_BUFFER_SIZE(buf));
// remove the buffer from the list of available mmap'd regions
g_mutex_lock(src->map_regions_lock);
@ -347,21 +365,24 @@ gst_filesrc_free_parent_mmap (GstBuffer *buf)
}
static GstBuffer *
gst_filesrc_map_region (GstFileSrc *src, off_t offset, off_t size)
gst_filesrc_map_region (GstFileSrc *src, off_t offset, size_t size)
{
GstBuffer *buf;
gint retval;
// fprintf(stderr,"mapping region %d+%d from file into memory\n",offset,size);
g_return_val_if_fail (offset >= 0, NULL);
fs_print ("mapping region %08lx+%08lx from file into memory\n",offset,size);
// time to allocate a new mapbuf
buf = gst_buffer_new();
// mmap() the data into this new buffer
GST_BUFFER_DATA(buf) = mmap (NULL, size, PROT_READ, MAP_SHARED, src->fd, offset);
if (GST_BUFFER_DATA(buf) == NULL) {
fprintf(stderr, "ERROR: gstfilesrc couldn't map file!\n");
} else if (GST_BUFFER_DATA(buf) == (void *)-1) {
perror("gstfilesrc:mmap()");
fprintf (stderr, "ERROR: gstfilesrc couldn't map file!\n");
} else if (GST_BUFFER_DATA(buf) == MAP_FAILED) {
g_error ("gstfilesrc mmap(0x%x, %d, 0x%llx) : %s",
size, src->fd, offset, sys_errlist[errno]);
}
// madvise to tell the kernel what to do with it
retval = madvise(GST_BUFFER_DATA(buf),GST_BUFFER_SIZE(buf),MADV_SEQUENTIAL);
@ -382,20 +403,27 @@ gst_filesrc_map_region (GstFileSrc *src, off_t offset, off_t size)
}
static GstBuffer *
gst_filesrc_map_small_region (GstFileSrc *src, off_t offset, off_t size)
gst_filesrc_map_small_region (GstFileSrc *src, off_t offset, size_t size)
{
int mod, mapbase, mapsize;
size_t mapsize;
off_t mod, mapbase;
GstBuffer *map;
// printf("attempting to map a small buffer at %d+%d\n",offset,size);
// if the offset starts at a non-page boundary, we have to special case
if ((mod = offset % src->pagesize)) {
GstBuffer *ret;
mapbase = offset - mod;
mapsize = ((size + mod + src->pagesize - 1) / src->pagesize) * src->pagesize;
// printf("not on page boundaries, resizing map to %d+%d\n",mapbase,mapsize);
map = gst_filesrc_map_region(src, mapbase, mapsize);
return gst_buffer_create_sub (map, offset - mapbase, size);
ret = gst_buffer_create_sub (map, offset - mapbase, size);
gst_buffer_unref (map);
return ret;
}
return gst_filesrc_map_region(src,offset,size);
@ -431,8 +459,8 @@ gst_filesrc_get (GstPad *pad)
{
GstFileSrc *src;
GstBuffer *buf = NULL, *map;
off_t readend,readsize,mapstart,mapend;
gboolean eof = FALSE;
size_t readsize;
off_t readend,mapstart,mapend;
GstFileSrcRegion region;
int i;
@ -440,6 +468,18 @@ gst_filesrc_get (GstPad *pad)
src = GST_FILESRC (gst_pad_get_parent (pad));
g_return_val_if_fail (GST_FLAG_IS_SET (src, GST_FILESRC_OPEN), NULL);
// check for seek
if (src->seek_happened) {
src->seek_happened = FALSE;
return gst_event_new(GST_EVENT_DISCONTINUOUS);
}
// check for EOF
if (src->curoffset == src->filelen) {
gst_element_set_state(src,GST_STATE_PAUSED);
return gst_event_new(GST_EVENT_EOS);
}
// calculate end pointers so we don't have to do so repeatedly later
readsize = src->block_size;
readend = src->curoffset + src->block_size; // note this is the byte *after* the read
@ -450,7 +490,6 @@ gst_filesrc_get (GstPad *pad)
if (readend > src->filelen) {
readsize = src->filelen - src->curoffset;
readend = src->curoffset;
eof = TRUE;
}
// if the start is past the mapstart
@ -458,15 +497,15 @@ gst_filesrc_get (GstPad *pad)
// 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)
if (readend <= mapend) {
// printf("read buf %d+%d lives in current mapbuf %d+%d, creating subbuffer of mapbuf\n",
// src->curoffset,readsize,GST_BUFFER_OFFSET(src->mapbuf),GST_BUFFER_SIZE(src->mapbuf));
fs_print ("read buf %d+%d lives in current mapbuf %d+%d, creating subbuffer of mapbuf\n",
src->curoffset,readsize,GST_BUFFER_OFFSET(src->mapbuf),GST_BUFFER_SIZE(src->mapbuf));
buf = gst_buffer_create_sub (src->mapbuf, src->curoffset - GST_BUFFER_OFFSET(src->mapbuf),
readsize);
// if the start actually is within the current mmap region, map an overlap buffer
} else if (src->curoffset < mapend) {
// printf("read buf %d+%d starts in mapbuf %d+%d but ends outside, creating new mmap\n",
// src->curoffset,readsize,GST_BUFFER_OFFSET(src->mapbuf),GST_BUFFER_SIZE(src->mapbuf));
fs_print ("read buf %d+%d starts in mapbuf %d+%d but ends outside, creating new mmap\n",
src->curoffset,readsize,GST_BUFFER_OFFSET(src->mapbuf),GST_BUFFER_SIZE(src->mapbuf));
buf = gst_filesrc_map_small_region (src, src->curoffset, readsize);
}
@ -478,37 +517,39 @@ gst_filesrc_get (GstPad *pad)
// either the read buffer overlaps the start of the 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
// printf("read buf %d+%d starts before mapbuf %d+%d, but overlaps it\n",
// src->curoffset,readsize,GST_BUFFER_OFFSET(src->mapbuf),GST_BUFFER_SIZE(src->mapbuf));
fs_print ("read buf %d+%d starts before mapbuf %d+%d, but overlaps it\n",
src->curoffset,readsize,GST_BUFFER_OFFSET(src->mapbuf),GST_BUFFER_SIZE(src->mapbuf));
buf = gst_filesrc_map_small_region (src, src->curoffset, readsize);
}
// then deal with the case where the read buffer is totally outside
if (buf == NULL) {
// first check to see if there's a map that covers the right region already
// printf("searching for mapbuf to cover %d+%d\n",src->curoffset,readsize);
fs_print ("searching for mapbuf to cover %d+%d\n",src->curoffset,readsize);
region.offset = src->curoffset;
region.size = readsize;
map = g_tree_search(src->map_regions,gst_filesrc_search_region_match,&region);
map = g_tree_search (src->map_regions,
(GCompareFunc) gst_filesrc_search_region_match,
&region);
// if we found an exact match, subbuffer it
if (map != NULL) {
// printf("found mapbuf at %d+%d, creating subbuffer\n",GST_BUFFER_OFFSET(map),GST_BUFFER_SIZE(map));
fs_print ("found mapbuf at %d+%d, creating subbuffer\n",GST_BUFFER_OFFSET(map),GST_BUFFER_SIZE(map));
buf = gst_buffer_create_sub (map, src->curoffset - GST_BUFFER_OFFSET(map), readsize);
// otherwise we need to create something out of thin air
} else {
// if the read buffer crosses a mmap region boundary, create a one-off region
if ((src->curoffset / src->mapsize) != (readend / src->mapsize)) {
// printf("read buf %d+%d crosses a %d-byte boundary, creating a one-off\n",
// src->curoffset,readsize,src->mapsize);
fs_print ("read buf %d+%d crosses a %d-byte boundary, creating a one-off\n",
src->curoffset,readsize,src->mapsize);
buf = gst_filesrc_map_small_region (src, src->curoffset, readsize);
// otherwise we will create a new mmap region and set it to the default
} else {
off_t nextmap = src->curoffset - (src->curoffset % src->mapsize);
// printf("read buf %d+%d in new mapbuf at %d+%d, mapping and subbuffering\n",
// src->curoffset,readsize,nextmap,src->mapsize);
fs_print ("read buf %d+%d in new mapbuf at %d+%d, mapping and subbuffering\n",
src->curoffset,readsize,nextmap,src->mapsize);
// first, we're done with the old mapbuf
gst_buffer_unref(src->mapbuf);
// create a new one
@ -525,8 +566,6 @@ gst_filesrc_get (GstPad *pad)
*(GST_BUFFER_DATA(buf)+i) = *(GST_BUFFER_DATA(buf)+i);
}
// if we hit EOF,
/* we're done, return the buffer */
src->curoffset += GST_BUFFER_SIZE(buf);
return buf;
@ -567,6 +606,7 @@ gst_filesrc_close_file (GstFileSrc *src)
{
g_return_if_fail (GST_FLAG_IS_SET (src, GST_FILESRC_OPEN));
g_print ("close\n");
/* close the file */
close (src->fd);
@ -613,6 +653,7 @@ gst_filesrc_srcpad_event(GstPad *pad, GstEventType event, gint64 location, guint
} else if (data == SEEK_END) {
src->curoffset = src->filelen - (guint64)location;
}
src->seek_happened = TRUE;
// push a discontinuous event?
return TRUE;
}

452
gst/elements/gstsinesrc.c Normal file
View file

@ -0,0 +1,452 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* 2001 Steve Baker <stevebaker_org@yahoo.co.uk>
*
* gstsinesrc.c:
*
* 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.
*/
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <gstsinesrc.h>
GstElementDetails gst_sinesrc_details = {
"Sine-wave src",
"Source/Audio",
"Create a sine wave of a given frequency and volume",
VERSION,
"Erik Walthinsen <omega@cse.ogi.edu>",
"(C) 1999",
};
/* SineSrc signals and args */
enum {
/* FILL ME */
LAST_SIGNAL
};
enum {
ARG_0,
ARG_VOLUME,
ARG_FORMAT,
ARG_SAMPLERATE,
ARG_FREQ,
ARG_TABLESIZE,
ARG_BUFFER_SIZE,
};
// FIXME: this is not core business...
GST_PADTEMPLATE_FACTORY (sinesrc_src_factory,
"src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_CAPS_NEW (
"sinesrc_src",
"audio/raw",
"format", GST_PROPS_STRING ("int"),
"law", GST_PROPS_INT (0),
"endianness", GST_PROPS_INT (G_BYTE_ORDER),
"signed", GST_PROPS_BOOLEAN (TRUE),
"width", GST_PROPS_INT (16),
"depth", GST_PROPS_INT (16),
"rate", GST_PROPS_INT_RANGE (8000, 48000),
"channels", GST_PROPS_INT (1)
)
);
static void gst_sinesrc_class_init (GstSineSrcClass *klass);
static void gst_sinesrc_init (GstSineSrc *src);
static GstPadNegotiateReturn gst_sinesrc_negotiate (GstPad *pad, GstCaps **caps, gpointer *data);
static void gst_sinesrc_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec);
static void gst_sinesrc_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec);
//static gboolean gst_sinesrc_change_state(GstElement *element,
// GstElementState state);
//static void gst_sinesrc_close_audio(GstSineSrc *src);
//static gboolean gst_sinesrc_open_audio(GstSineSrc *src);
static void gst_sinesrc_update_volume(GValue *value, gpointer data);
static void gst_sinesrc_update_freq(GValue *value, gpointer data);
static void gst_sinesrc_populate_sinetable (GstSineSrc *src);
static inline void gst_sinesrc_update_table_inc (GstSineSrc *src);
static inline void gst_sinesrc_update_vol_scale (GstSineSrc *src);
static void gst_sinesrc_force_caps (GstSineSrc *src);
static GstBuffer* gst_sinesrc_get (GstPad *pad);
static GstElementClass *parent_class = NULL;
//static guint gst_sinesrc_signals[LAST_SIGNAL] = { 0 };
GType
gst_sinesrc_get_type (void)
{
static GType sinesrc_type = 0;
if (!sinesrc_type) {
static const GTypeInfo sinesrc_info = {
sizeof(GstSineSrcClass),
NULL,
NULL,
(GClassInitFunc)gst_sinesrc_class_init,
NULL,
NULL,
sizeof(GstSineSrc),
0,
(GInstanceInitFunc)gst_sinesrc_init,
};
sinesrc_type = g_type_register_static (GST_TYPE_ELEMENT, "GstSineSrc", &sinesrc_info, 0);
}
return sinesrc_type;
}
static void
gst_sinesrc_class_init (GstSineSrcClass *klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass*)klass;
gstelement_class = (GstElementClass*)klass;
parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_VOLUME,
g_param_spec_double("volume","volume","volume",
0.0, 1.0, 0.0,G_PARAM_READWRITE)); // CHECKME
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FORMAT,
g_param_spec_int("format","format","format",
G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SAMPLERATE,
g_param_spec_int("samplerate","samplerate","samplerate",
G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_TABLESIZE,
g_param_spec_int("tablesize","tablesize","tablesize",
G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FREQ,
g_param_spec_double("freq","freq","freq",
0.0,G_MAXDOUBLE, 440.0,G_PARAM_READWRITE)); // CHECKME
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BUFFER_SIZE,
g_param_spec_int("buffersize","buffersize","buffersize",
0, G_MAXINT, 1024, G_PARAM_READWRITE));
gobject_class->set_property = gst_sinesrc_set_property;
gobject_class->get_property = gst_sinesrc_get_property;
// gstelement_class->change_state = gst_sinesrc_change_state;
}
static void
gst_sinesrc_init (GstSineSrc *src)
{
GstElement *element = GST_ELEMENT(src);
GstDParamManager *dpman;
src->srcpad = gst_pad_new_from_template (
GST_PADTEMPLATE_GET (sinesrc_src_factory), "src");
gst_element_add_pad(GST_ELEMENT(src), src->srcpad);
gst_pad_set_negotiate_function (src->srcpad, gst_sinesrc_negotiate);
gst_pad_set_get_function(src->srcpad, gst_sinesrc_get);
src->format = 16;
src->samplerate = 44100;
src->newcaps = TRUE;
src->table_pos = 0.0;
src->table_size = 1024;
src->buffer_size=1024;
src->seq = 0;
dpman = gst_dpman_new ("sinesrc_dpman", GST_ELEMENT(src));
gst_dpman_add_required_dparam (dpman, "volume", G_TYPE_FLOAT, gst_sinesrc_update_volume, src);
gst_dpman_add_required_dparam (dpman, "freq", G_TYPE_FLOAT, gst_sinesrc_update_freq, src);
gst_dpman_set_rate_change_pad(dpman, src->srcpad);
GST_ELEMENT_DPARAM_MANAGER(element) = dpman;
gst_sinesrc_update_vol_scale(src);
gst_sinesrc_populate_sinetable(src);
gst_sinesrc_update_table_inc(src);
}
static GstPadNegotiateReturn
gst_sinesrc_negotiate (GstPad *pad, GstCaps **caps, gpointer *data)
{
GstSineSrc *src;
if (*caps) {
g_return_val_if_fail (pad != NULL, GST_PAD_NEGOTIATE_FAIL);
src = GST_SINESRC(gst_pad_get_parent (pad));
src->samplerate = gst_caps_get_int (*caps, "rate");
gst_sinesrc_update_table_inc(src);
return GST_PAD_NEGOTIATE_AGREE;
}
return GST_PAD_NEGOTIATE_FAIL;
}
static GstBuffer *
gst_sinesrc_get(GstPad *pad)
{
GstSineSrc *src;
GstBuffer *buf;
GstDParamManager *dpman;
gint16 *samples;
gint i=0, frame_countdown;
g_return_val_if_fail (pad != NULL, NULL);
src = GST_SINESRC(gst_pad_get_parent (pad));
buf = gst_buffer_new();
g_return_val_if_fail (buf, NULL);
samples = g_new(gint16, src->buffer_size);
GST_BUFFER_DATA(buf) = (gpointer) samples;
GST_BUFFER_SIZE(buf) = 2 * src->buffer_size;
dpman = GST_ELEMENT_DPARAM_MANAGER(GST_ELEMENT(src));
frame_countdown = GST_DPMAN_FIRST_COUNTDOWN(dpman, src->buffer_size, 0LL);
while(GST_DPMAN_COUNTDOWN(dpman, frame_countdown, i)) {
src->table_lookup = (gint)(src->table_pos);
src->table_lookup_next = src->table_lookup + 1;
src->table_interp = src->table_pos - src->table_lookup;
// wrap the array lookups if we're out of bounds
if (src->table_lookup_next >= src->table_size){
src->table_lookup_next -= src->table_size;
if (src->table_lookup >= src->table_size){
src->table_lookup -= src->table_size;
src->table_pos -= src->table_size;
}
}
src->table_pos += src->table_inc;
//no interpolation
//samples[i] = src->table_data[src->table_lookup]
// * src->vol_scale;
//linear interpolation
samples[i++] = ((src->table_interp
*(src->table_data[src->table_lookup_next]
-src->table_data[src->table_lookup]
)
)+src->table_data[src->table_lookup]
)* src->vol_scale;
}
if (src->newcaps) {
gst_sinesrc_force_caps(src);
}
return buf;
}
static void
gst_sinesrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
GstSineSrc *src;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail(GST_IS_SINESRC(object));
src = GST_SINESRC(object);
switch (prop_id) {
case ARG_VOLUME:
src->volume = (gfloat)g_value_get_double (value);
gst_sinesrc_update_vol_scale(src);
break;
case ARG_FORMAT:
src->format = g_value_get_int (value);
src->newcaps=TRUE;
break;
case ARG_SAMPLERATE:
src->samplerate = g_value_get_int (value);
src->newcaps=TRUE;
gst_sinesrc_update_table_inc(src);
break;
case ARG_FREQ: {
if (g_value_get_double (value) <= 0.0 || g_value_get_double (value) > src->samplerate/2)
break;
src->freq = (gfloat)g_value_get_double (value);
gst_sinesrc_update_table_inc(src);
break;
case ARG_TABLESIZE:
src->table_size = g_value_get_int (value);
gst_sinesrc_populate_sinetable(src);
gst_sinesrc_update_table_inc(src);
break;
case ARG_BUFFER_SIZE:
src->buffer_size = g_value_get_int (value);
break;
}
default:
break;
}
}
static void
gst_sinesrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
GstSineSrc *src;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail(GST_IS_SINESRC(object));
src = GST_SINESRC(object);
switch (prop_id) {
case ARG_VOLUME:
g_value_set_double (value, (gdouble)(src->volume));
break;
case ARG_FORMAT:
g_value_set_int (value, src->format);
break;
case ARG_SAMPLERATE:
g_value_set_int (value, src->samplerate);
break;
case ARG_FREQ:
g_value_set_double (value, (gdouble)(src->freq));
break;
case ARG_TABLESIZE:
g_value_set_int (value, src->table_size);
break;
case ARG_BUFFER_SIZE:
g_value_set_int (value, src->buffer_size);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/*
static gboolean gst_sinesrc_change_state(GstElement *element,
GstElementState state) {
g_return_if_fail(GST_IS_SINESRC(element));
switch (state) {
case GST_STATE_RUNNING:
if (!gst_sinesrc_open_audio(GST_SINESRC(element)))
return FALSE;
break;
case ~GST_STATE_RUNNING:
gst_sinesrc_close_audio(GST_SINESRC(element));
break;
default:
break;
}
if (GST_ELEMENT_CLASS(parent_class)->change_state)
return GST_ELEMENT_CLASS(parent_class)->change_state(element,state);
return TRUE;
}
*/
static void
gst_sinesrc_populate_sinetable (GstSineSrc *src)
{
gint i;
gdouble pi2scaled = M_PI * 2 / src->table_size;
gfloat *table = g_new(gfloat, src->table_size);
for(i=0 ; i < src->table_size ; i++){
table[i] = (gfloat)sin(i * pi2scaled);
}
g_free(src->table_data);
src->table_data = table;
}
static void
gst_sinesrc_update_volume(GValue *value, gpointer data)
{
GstSineSrc *src = (GstSineSrc*)data;
g_return_if_fail(GST_IS_SINESRC(src));
src->volume = g_value_get_float(value);
src->vol_scale = 32767.0 * src->volume;
}
static void
gst_sinesrc_update_freq(GValue *value, gpointer data)
{
GstSineSrc *src = (GstSineSrc*)data;
g_return_if_fail(GST_IS_SINESRC(src));
src->freq = g_value_get_float(value);
src->table_inc = src->table_size * src->freq / src->samplerate;
}
static inline void
gst_sinesrc_update_table_inc (GstSineSrc *src)
{
src->table_inc = src->table_size * src->freq / src->samplerate;
}
static inline void
gst_sinesrc_update_vol_scale (GstSineSrc *src)
{
src->vol_scale = 32767.0 * src->volume;
}
static void
gst_sinesrc_force_caps(GstSineSrc *src) {
GstCaps *caps;
if (!src->newcaps)
return;
src->newcaps=FALSE;
caps = gst_caps_new (
"sinesrc_src_caps",
"audio/raw",
gst_props_new (
"format", GST_PROPS_STRING ("int"),
"law", GST_PROPS_INT (0),
"endianness", GST_PROPS_INT (G_BYTE_ORDER),
"signed", GST_PROPS_BOOLEAN (TRUE),
"width", GST_PROPS_INT (16),
"depth", GST_PROPS_INT (16),
"rate", GST_PROPS_INT (src->samplerate),
"channels", GST_PROPS_INT (1),
NULL
)
);
gst_pad_set_caps (src->srcpad, caps);
}
gboolean
gst_sinesrc_factory_init (GstElementFactory *factory)
{
gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (sinesrc_src_factory));
return TRUE;
}

96
gst/elements/gstsinesrc.h Normal file
View file

@ -0,0 +1,96 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
*
* gstsinesrc.h:
*
* 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_SINESRC_H__
#define __GST_SINESRC_H__
#include <config.h>
#include <gst/gst.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
GstElementDetails gst_sinesrc_details;
#define GST_TYPE_SINESRC \
(gst_sinesrc_get_type())
#define GST_SINESRC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SINESRC,GstSineSrc))
#define GST_SINESRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SINESRC,GstSineSrcClass))
#define GST_IS_SINESRC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SINESRC))
#define GST_IS_SINESRC_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SINESRC))
typedef struct _GstSineSrc GstSineSrc;
typedef struct _GstSineSrcClass GstSineSrcClass;
struct _GstSineSrc {
GstElement element;
/* pads */
GstPad *srcpad;
/* parameters */
gfloat volume;
gfloat freq;
gfloat vol_scale;
/* lookup table data */
gfloat *table_data;
gdouble table_pos;
gdouble table_inc;
gint table_size;
gdouble table_interp;
gint table_lookup;
gint table_lookup_next;
/* audio parameters */
gint format;
gint samplerate;
gint buffer_size;
gulong seq;
gboolean newcaps;
};
struct _GstSineSrcClass {
GstElementClass parent_class;
};
GType gst_sinesrc_get_type(void);
gboolean gst_sinesrc_factory_init (GstElementFactory *factory);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __GST_SINESRC_H__ */

View file

@ -56,7 +56,7 @@ GST_PADTEMPLATE_FACTORY (tee_src_factory,
static void gst_tee_class_init (GstTeeClass *klass);
static void gst_tee_init (GstTee *tee);
static GstPad* gst_tee_request_new_pad (GstElement *element, GstPadTemplate *temp);
static GstPad* gst_tee_request_new_pad (GstElement *element, GstPadTemplate *temp, const gchar *unused);
static void gst_tee_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec);
@ -127,7 +127,7 @@ gst_tee_init (GstTee *tee)
}
static GstPad*
gst_tee_request_new_pad (GstElement *element, GstPadTemplate *templ)
gst_tee_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *unused)
{
gchar *name;
GstPad *srcpad;

View file

@ -6,6 +6,24 @@
#include "gobject2gtk.h"
// list functions not in glib 1.2
GList *
g_list_delete_link (GList *list, GList *llink)
{
GList *temp = g_list_remove_link(list, llink);
g_list_free(llink);
return temp;
}
GSList *
g_slist_delete_link (GSList *list, GSList *llink)
{
GSList *temp = g_slist_remove_link(list, llink);
g_slist_free(llink);
return temp;
}
// GObject dummy implementation
static void
@ -324,4 +342,3 @@ gint* g_signal_list_ids (GType type, guint *n_ids)
return class->signals;
}

View file

@ -14,6 +14,12 @@
#define G_PI_4 0.78539816339744830962E0
#define G_SQRT2 1.4142135623730950488E0
// lists functions not in glib 1.2
GList *g_list_delete_link (GList *list, GList *llink);
GSList *g_slist_delete_link (GSList *list, GSList *llink);
// GObject
typedef struct _GObject GObject;
typedef struct _GObjectClass GObjectClass;
@ -53,35 +59,35 @@ typedef struct _GObjectClass GObjectClass;
#define G_TYPE_PARAM GTK_TYPE_PARAM
// marshallers
#define g_cclosure_marshal_VOID__VOID gtk_marshal_NONE__NONE
#define g_cclosure_marshal_VOID__BOOLEAN gtk_marshal_NONE__BOOL
#define g_cclosure_marshal_VOID__CHAR gtk_marshal_NONE__CHAR
#define g_cclosure_marshal_VOID__UCHAR gtk_marshal_NONE__UCHAR
#define g_cclosure_marshal_VOID__INT gtk_marshal_NONE__INT
#define g_cclosure_marshal_VOID__UINT gtk_marshal_NONE__UINT
#define g_cclosure_marshal_VOID__LONG gtk_marshal_NONE__LONG
#define g_cclosure_marshal_VOID__ULONG gtk_marshal_NONE__ULONG
#define g_cclosure_marshal_VOID__ENUM gtk_marshal_NONE__ENUM
#define g_cclosure_marshal_VOID__FLAGS gtk_marshal_NONE__FLAGS
#define g_cclosure_marshal_VOID__FLOAT gtk_marshal_NONE__FLOAT
#define g_cclosure_marshal_VOID__DOUBLE gtk_marshal_NONE__DOUBLE
#define g_cclosure_marshal_VOID__STRING gtk_marshal_NONE__STRING
#define g_cclosure_marshal_VOID__PARAM gtk_marshal_NONE__PARAM
#define g_cclosure_marshal_VOID__BOXED gtk_marshal_NONE__BOXED
#define g_cclosure_marshal_VOID__POINTER gtk_marshal_NONE__POINTER
#define g_cclosure_marshal_VOID__OBJECT gtk_marshal_NONE__OBJECT
#define g_cclosure_marshal_STRING__OBJECT_POINTER gtk_marshal_STRING__OBJECT_POINTER
#define g_cclosure_marshal_VOID__UINT_POINTER gtk_marshal_NONE__UINT_POINTER
#define g_cclosure_marshal_VOID__VOID gtk_marshal_NONE__NONE
#define g_cclosure_marshal_VOID__BOOLEAN gtk_marshal_NONE__BOOL
#define g_cclosure_marshal_VOID__CHAR gtk_marshal_NONE__CHAR
#define g_cclosure_marshal_VOID__UCHAR gtk_marshal_NONE__UCHAR
#define g_cclosure_marshal_VOID__INT gtk_marshal_NONE__INT
#define g_cclosure_marshal_VOID__UINT gtk_marshal_NONE__UINT
#define g_cclosure_marshal_VOID__LONG gtk_marshal_NONE__LONG
#define g_cclosure_marshal_VOID__ULONG gtk_marshal_NONE__ULONG
#define g_cclosure_marshal_VOID__ENUM gtk_marshal_NONE__ENUM
#define g_cclosure_marshal_VOID__FLAGS gtk_marshal_NONE__FLAGS
#define g_cclosure_marshal_VOID__FLOAT gtk_marshal_NONE__FLOAT
#define g_cclosure_marshal_VOID__DOUBLE gtk_marshal_NONE__DOUBLE
#define g_cclosure_marshal_VOID__STRING gtk_marshal_NONE__STRING
#define g_cclosure_marshal_VOID__PARAM gtk_marshal_NONE__PARAM
#define g_cclosure_marshal_VOID__BOXED gtk_marshal_NONE__BOXED
#define g_cclosure_marshal_VOID__POINTER gtk_marshal_NONE__POINTER
#define g_cclosure_marshal_VOID__OBJECT gtk_marshal_NONE__OBJECT
#define g_cclosure_marshal_STRING__OBJECT_POINTER gtk_marshal_STRING__POINTER_POINTER
#define g_cclosure_marshal_VOID__UINT_POINTER gtk_marshal_NONE__UINT_POINTER
#define gst_marshal_VOID__INT_INT gtk_marshal_NONE__INT_INT
#define gst_marshal_VOID__INT gtk_marshal_NONE__INT
#define gst_marshal_VOID__STRING gtk_marshal_NONE__STRING
#define gst_marshal_VOID__VOID gtk_marshal_NONE__NONE
#define gst_marshal_VOID__BOOLEAN gtk_marshal_NONE__BOOL
#define gst_marshal_VOID__INT gtk_marshal_NONE__INT
#define gst_marshal_VOID__INT_INT gtk_marshal_NONE__INT_INT
#define gst_marshal_VOID__STRING gtk_marshal_NONE__STRING
#define gst_marshal_VOID__POINTER gtk_marshal_NONE__POINTER
#define gst_marshal_VOID__OBJECT gtk_marshal_NONE__POINTER
#define gst_marshal_VOID__OBJECT_POINTER gtk_marshal_NONE__POINTER_POINTER
#define gst_marshal_VOID__INT_INT gtk_marshal_NONE__INT_INT
#define gst_marshal_VOID__OBJECT gtk_marshal_NONE__POINTER
#define gst_marshal_VOID__OBJECT_POINTER gtk_marshal_NONE__POINTER_POINTER
#define gst_marshal_VOID__INT_INT gtk_marshal_NONE__INT_INT
/* General macros */
#ifdef __cplusplus
@ -217,6 +223,10 @@ gtk_signal_handler_pending ((GtkObject *)object,name,may_block)
gint* g_signal_list_ids (GType type, guint *n_ids);
// lists
GSList* g_slist_delete_link (GSList *list, GSList *link) __attribute__ ((no_instrument_function));
// arguments/parameters
// first define GValue and GParamSpec

101
gst/gst.c
View file

@ -24,6 +24,7 @@
#include "gst_private.h"
#include "gstversion.h"
#include "gstcpu.h"
#include "gsttype.h"
#include "gstplugin.h"
@ -38,6 +39,7 @@
#endif
#define MAX_PATH_SPLIT 16
#define GST_PLUGIN_SEPARATOR ","
gchar *_gst_progname;
@ -47,6 +49,9 @@ extern gboolean _gst_plugin_spew;
static gboolean gst_init_check (int *argc, gchar ***argv);
static void load_plugin_func (gpointer data, gpointer user_data);
static GSList *preload_plugins = NULL;
const gchar *g_log_domain_gstreamer = "GStreamer";
@ -105,7 +110,12 @@ gst_init (int *argc, char **argv[])
GST_INFO (GST_CAT_GST_INIT, "Initializing GStreamer Core Library");
gst_object_get_type ();
gst_pad_get_type ();
gst_real_pad_get_type ();
gst_ghost_pad_get_type ();
gst_elementfactory_get_type ();
gst_element_get_type ();
gst_typefactory_get_type ();
#ifndef GST_DISABLE_AUTOPLUG
gst_autoplugfactory_get_type ();
@ -115,9 +125,17 @@ gst_init (int *argc, char **argv[])
_gst_props_initialize ();
_gst_caps_initialize ();
_gst_plugin_initialize ();
_gst_event_initialize ();
_gst_buffer_initialize ();
_gst_buffer_pool_initialize ();
/* if we need to preload plugins */
if (preload_plugins) {
g_slist_foreach (preload_plugins, load_plugin_func, NULL);
g_slist_free (preload_plugins);
preload_plugins = NULL;
}
/* register some standard builtin types */
gst_elementfactory_new ("bin", gst_bin_get_type (), &gst_bin_details);
gst_elementfactory_new ("pipeline", gst_pipeline_get_type (), &gst_pipeline_details);
@ -137,23 +155,23 @@ gst_init (int *argc, char **argv[])
}
static void
gst_add_paths_func (const gchar *pathlist)
split_and_iterate (const gchar *stringlist, gchar *separator, GFunc iterator)
{
gchar **paths;
gchar **strings;
gint j = 0;
gchar *lastpath = g_strdup (pathlist);
gchar *lastlist = g_strdup (stringlist);
while (lastpath) {
paths = g_strsplit (lastpath, G_SEARCHPATH_SEPARATOR_S, MAX_PATH_SPLIT);
g_free (lastpath);
lastpath = NULL;
while (lastlist) {
strings = g_strsplit (lastlist, separator, MAX_PATH_SPLIT);
//strings = g_strsplit (lastlist, G_SEARCHPATH_SEPARATOR_S, MAX_PATH_SPLIT);
g_free (lastlist);
lastlist = NULL;
while (paths[j]) {
GST_INFO (GST_CAT_GST_INIT, "Adding plugin path: \"%s\"", paths[j]);
gst_plugin_add_path (paths[j]);
while (strings[j]) {
iterator (strings[j], NULL);
if (++j == MAX_PATH_SPLIT) {
lastpath = g_strdup (paths[j]);
g_strfreev (paths);
lastlist = g_strdup (strings[j]);
g_strfreev (strings);
j=0;
break;
}
@ -161,6 +179,33 @@ gst_add_paths_func (const gchar *pathlist)
}
}
static void
add_path_func (gpointer data, gpointer user_data)
{
GST_INFO (GST_CAT_GST_INIT, "Adding plugin path: \"%s\"", (gchar *)data);
gst_plugin_add_path ((gchar *)data);
}
static void
prepare_for_load_plugin_func (gpointer data, gpointer user_data)
{
preload_plugins = g_slist_prepend (preload_plugins, data);
}
static void
load_plugin_func (gpointer data, gpointer user_data)
{
gboolean ret;
ret = gst_plugin_load ((gchar *)data);
if (ret)
GST_INFO (GST_CAT_GST_INIT, "Loaded plugin: \"%s\"", (gchar *)data);
else
GST_INFO (GST_CAT_GST_INIT, "Failed to load plugin: \"%s\"", (gchar *)data);
g_free (data);
}
/* returns FALSE if the program can be aborted */
static gboolean
gst_init_check (int *argc,
@ -226,7 +271,12 @@ gst_init_check (int *argc,
(*argv)[i] = NULL;
}
else if (!strncmp ("--gst-plugin-path=", (*argv)[i], 17)) {
gst_add_paths_func ((*argv)[i]+18);
split_and_iterate ((*argv)[i]+18, G_SEARCHPATH_SEPARATOR_S, add_path_func);
(*argv)[i] = NULL;
}
else if (!strncmp ("--gst-plugin-load=", (*argv)[i], 17)) {
split_and_iterate ((*argv)[i]+18, ",", prepare_for_load_plugin_func);
(*argv)[i] = NULL;
}
@ -257,7 +307,7 @@ gst_init_check (int *argc,
/* check for ENV variables */
{
const gchar *plugin_path = g_getenv("GST_PLUGIN_PATH");
gst_add_paths_func (plugin_path);
split_and_iterate (plugin_path, G_SEARCHPATH_SEPARATOR_S, add_path_func);
}
if (showhelp) {
@ -272,6 +322,8 @@ gst_init_check (int *argc,
g_print (" --gst-plugin-spew Enable printout of errors while loading GST plugins\n");
g_print (" --gst-plugin-path=PATH Add directories separated with '%s' to the plugin search path\n",
G_SEARCHPATH_SEPARATOR_S);
g_print (" --gst-plugin-load=PLUGINS Load plugins separated with '%s'\n",
GST_PLUGIN_SEPARATOR);
g_print ("\n Mask (to be OR'ed) info/debug FLAGS \n");
g_print ("--------------------------------------------------------\n");
@ -323,3 +375,24 @@ gst_main_quit (void)
gtk_main_quit ();
#endif
}
/**
* gst_version:
* @major: pointer to a guint to store the major version number
* @minor: pointer to a guint to store the minor version number
* @micro: pointer to a guint to store the micro version number
*
* Gets the version number of the GStreamer library
*/
void
gst_version (guint *major, guint *minor, guint *micro)
{
g_return_if_fail (major);
g_return_if_fail (minor);
g_return_if_fail (micro);
*major = GST_VERSION_MAJOR;
*minor = GST_VERSION_MINOR;
*micro = GST_VERSION_MICRO;
}

View file

@ -50,6 +50,7 @@
#include <gst/cothreads.h>
#include <gst/gstscheduler.h>
#include <gst/gsttimecache.h>
#include <gst/gstevent.h>
#include <gst/gstparse.h>
#include <gst/gstextratypes.h>

View file

@ -21,6 +21,9 @@
*/
//#define GST_DEBUG_ENABLED
#include <gst/gstconfig.h>
#include "gst_private.h"
#include "gstautoplug.h"
@ -168,8 +171,10 @@ gst_autoplug_to_renderers (GstAutoplug *autoplug, GstCaps *srccaps, GstElement *
static void gst_autoplugfactory_class_init (GstAutoplugFactoryClass *klass);
static void gst_autoplugfactory_init (GstAutoplugFactory *factory);
#ifndef GST_DISABLE_REGISTRY
static xmlNodePtr gst_autoplugfactory_save_thyself (GstObject *object, xmlNodePtr parent);
static void gst_autoplugfactory_restore_thyself (GstObject *object, xmlNodePtr parent);
#endif
static GstPluginFeatureClass *factory_parent_class = NULL;
//static guint gst_autoplugfactory_signals[LAST_SIGNAL] = { 0 };
@ -211,8 +216,10 @@ gst_autoplugfactory_class_init (GstAutoplugFactoryClass *klass)
factory_parent_class = g_type_class_ref (GST_TYPE_PLUGIN_FEATURE);
#ifndef GST_DISABLE_REGISTRY
gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_autoplugfactory_save_thyself);
gstobject_class->restore_thyself = GST_DEBUG_FUNCPTR (gst_autoplugfactory_restore_thyself);
#endif
_gst_autoplugfactories = NULL;
}
@ -361,6 +368,7 @@ gst_autoplugfactory_make (const gchar *name)
return gst_autoplugfactory_create (factory);;
}
#ifndef GST_DISABLE_REGISTRY
static xmlNodePtr
gst_autoplugfactory_save_thyself (GstObject *object, xmlNodePtr parent)
{
@ -407,3 +415,4 @@ gst_autoplugfactory_restore_thyself (GstObject *object, xmlNodePtr parent)
children = children->next;
}
}
#endif /* GST_DISABLE_REGISTRY */

View file

@ -113,16 +113,17 @@ gst_bin_class_init (GstBinClass *klass)
gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
GST_TYPE_ELEMENT);
klass->change_state_type = gst_bin_change_state_type;
klass->iterate = gst_bin_iterate_func;
klass->change_state_type = GST_DEBUG_FUNCPTR (gst_bin_change_state_type);
klass->iterate = GST_DEBUG_FUNCPTR (gst_bin_iterate_func);
#ifndef GST_DISABLE_LOADSAVE
gstobject_class->save_thyself = gst_bin_save_thyself;
gstobject_class->restore_thyself = gst_bin_restore_thyself;
gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_bin_save_thyself);
gstobject_class->restore_thyself = GST_DEBUG_FUNCPTR (gst_bin_restore_thyself);
#endif
gstelement_class->change_state = gst_bin_change_state;
gobject_class->dispose = gst_bin_dispose;
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_bin_change_state);
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_bin_dispose);
}
static void
@ -644,7 +645,7 @@ gst_bin_restore_thyself (GstObject *object,
field = field->next;
}
}
#endif // GST_DISABLE_LOADSAVE
#endif /* GST_DISABLE_LOADSAVE */
/**

View file

@ -27,6 +27,8 @@
#include "gstbuffer.h"
GType _gst_buffer_type;
static GMemChunk *_gst_buffer_chunk;
static GMutex *_gst_buffer_chunk_lock;
@ -34,6 +36,17 @@ void
_gst_buffer_initialize (void)
{
int buffersize = sizeof(GstBuffer);
static const GTypeInfo buffer_info = {
0, // sizeof(class),
NULL,
NULL,
NULL,
NULL,
NULL,
0, // sizeof(object),
0,
NULL,
};
// round up to the nearest 32 bytes for cache-line and other efficiencies
buffersize = (((buffersize-1) / 32) + 1) * 32;
@ -42,6 +55,8 @@ _gst_buffer_initialize (void)
buffersize * 32, G_ALLOC_AND_FREE);
_gst_buffer_chunk_lock = g_mutex_new ();
_gst_buffer_type = g_type_register_static (G_TYPE_INT, "GstBuffer", &buffer_info, 0);
}
/**
@ -52,7 +67,7 @@ _gst_buffer_initialize (void)
* Returns: new buffer
*/
GstBuffer*
gst_buffer_new(void)
gst_buffer_new (void)
{
GstBuffer *buffer;
@ -61,6 +76,8 @@ gst_buffer_new(void)
g_mutex_unlock (_gst_buffer_chunk_lock);
GST_INFO (GST_CAT_BUFFER,"creating new buffer %p",buffer);
GST_DATA_TYPE(buffer) = _gst_buffer_type;
buffer->lock = g_mutex_new ();
#ifdef HAVE_ATOMIC_H
atomic_set (&buffer->refcount, 1);
@ -78,7 +95,7 @@ gst_buffer_new(void)
buffer->pool_private = NULL;
buffer->free = NULL;
buffer->copy = NULL;
return buffer;
}
@ -91,18 +108,21 @@ gst_buffer_new(void)
* Returns: new buffer
*/
GstBuffer*
gst_buffer_new_from_pool (GstBufferPool *pool, guint64 location, gint size)
gst_buffer_new_from_pool (GstBufferPool *pool, guint32 offset, guint32 size)
{
GstBuffer *buffer;
g_return_val_if_fail (pool != NULL, NULL);
g_return_val_if_fail (pool->buffer_new != NULL, NULL);
buffer = pool->buffer_new (pool, location, size, pool->user_data);
buffer = pool->buffer_new (pool, offset, size, pool->user_data);
buffer->pool = pool;
buffer->free = pool->buffer_free;
buffer->copy = pool->buffer_copy;
GST_INFO (GST_CAT_BUFFER,"creating new buffer %p from pool %p (size %x, offset %x)",
buffer, pool, size, offset);
return buffer;
}
@ -124,13 +144,16 @@ gst_buffer_create_sub (GstBuffer *parent,
GstBuffer *buffer;
g_return_val_if_fail (parent != NULL, NULL);
g_return_val_if_fail (GST_BUFFER_REFCOUNT(parent) > 0, NULL);
g_return_val_if_fail (size > 0, NULL);
g_return_val_if_fail ((offset+size) <= parent->size, NULL);
g_mutex_lock (_gst_buffer_chunk_lock);
buffer = g_mem_chunk_alloc (_gst_buffer_chunk);
GST_DATA_TYPE(buffer) = _gst_buffer_type;
g_mutex_unlock (_gst_buffer_chunk_lock);
GST_INFO (GST_CAT_BUFFER,"creating new subbuffer %p from parent %p", buffer, parent);
GST_INFO (GST_CAT_BUFFER,"creating new subbuffer %p from parent %p (size %u, offset %u)",
buffer, parent, size, offset);
buffer->lock = g_mutex_new ();
#ifdef HAVE_ATOMIC_H
@ -166,7 +189,7 @@ gst_buffer_create_sub (GstBuffer *parent,
gst_buffer_ref (parent);
buffer->pool = NULL;
// return the new subbuffer
return buffer;
}
@ -192,6 +215,8 @@ gst_buffer_append (GstBuffer *buffer,
g_return_val_if_fail (buffer != NULL, NULL);
g_return_val_if_fail (append != NULL, NULL);
g_return_val_if_fail (buffer->pool == NULL, NULL);
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buffer) > 0, NULL);
g_return_val_if_fail (GST_BUFFER_REFCOUNT(append) > 0, NULL);
GST_INFO (GST_CAT_BUFFER,"appending buffers %p and %p",buffer,append);
@ -226,12 +251,15 @@ gst_buffer_append (GstBuffer *buffer,
*
* destroy the buffer
*/
void gst_buffer_destroy (GstBuffer *buffer)
void
gst_buffer_destroy (GstBuffer *buffer)
{
g_return_if_fail (buffer != NULL);
GST_INFO (GST_CAT_BUFFER,"freeing %sbuffer %p", (buffer->parent?"sub":""),buffer);
GST_INFO (GST_CAT_BUFFER, "freeing %sbuffer %p",
(buffer->parent?"sub":""),
buffer);
// free the data only if there is some, DONTFREE isn't set, and not sub
if (GST_BUFFER_DATA (buffer) &&
@ -252,6 +280,11 @@ void gst_buffer_destroy (GstBuffer *buffer)
g_mutex_free (buffer->lock);
//g_print("freed mutex\n");
#ifdef GST_DEBUG_ENABLED
// make it hard to reuse by mistake
memset (buffer, 0, sizeof (GstBuffer));
#endif
// remove it entirely from memory
g_mutex_lock (_gst_buffer_chunk_lock);
g_mem_chunk_free (_gst_buffer_chunk,buffer);
@ -268,44 +301,19 @@ void
gst_buffer_ref (GstBuffer *buffer)
{
g_return_if_fail (buffer != NULL);
g_return_if_fail (GST_BUFFER_REFCOUNT(buffer) > 0);
GST_DEBUG (0,"referencing buffer %p\n", buffer);
GST_INFO (GST_CAT_BUFFER, "ref buffer %p\n", buffer);
#ifdef HAVE_ATOMIC_H
//g_return_if_fail(atomic_read(&(buffer->refcount)) > 0);
atomic_inc (&(buffer->refcount));
#else
g_return_if_fail (buffer->refcount > 0);
GST_BUFFER_LOCK (buffer);
buffer->refcount++;
GST_BUFFER_UNLOCK (buffer);
#endif
}
/**
* gst_buffer_ref_by_count:
* @buffer: the GstBuffer to reference
* @count: a number
*
* Increment the refcount of this buffer by the given number.
*/
void
gst_buffer_ref_by_count (GstBuffer *buffer, int count)
{
g_return_if_fail (buffer != NULL);
g_return_if_fail (count > 0);
#ifdef HAVE_ATOMIC_H
g_return_if_fail (atomic_read (&(buffer->refcount)) > 0);
atomic_add (count, &(buffer->refcount));
#else
g_return_if_fail (buffer->refcount > 0);
GST_BUFFER_LOCK (buffer);
buffer->refcount += count;
GST_BUFFER_UNLOCK (buffer);
#endif
}
/**
* gst_buffer_unref:
* @buffer: the GstBuffer to unref
@ -319,14 +327,13 @@ gst_buffer_unref (GstBuffer *buffer)
gint zero;
g_return_if_fail (buffer != NULL);
g_return_if_fail (GST_BUFFER_REFCOUNT(buffer) > 0);
GST_DEBUG (0,"unreferencing buffer %p\n", buffer);
GST_INFO (GST_CAT_BUFFER, "unref buffer %p\n", buffer);
#ifdef HAVE_ATOMIC_H
g_return_if_fail (atomic_read (&(buffer->refcount)) > 0);
zero = atomic_dec_and_test (&(buffer->refcount));
#else
g_return_if_fail (buffer->refcount > 0);
GST_BUFFER_LOCK (buffer);
buffer->refcount--;
zero = (buffer->refcount == 0);
@ -352,6 +359,8 @@ gst_buffer_copy (GstBuffer *buffer)
{
GstBuffer *newbuf;
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buffer) > 0, NULL);
// if a copy function exists, use it, else copy the bytes
if (buffer->copy != NULL) {
newbuf = (buffer->copy)(buffer);
@ -391,7 +400,11 @@ gst_buffer_copy (GstBuffer *buffer)
gboolean
gst_buffer_is_span_fast (GstBuffer *buf1, GstBuffer *buf2)
{
return ((buf1->parent == buf2->parent) &&
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf1) > 0, FALSE);
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf2) > 0, FALSE);
return (buf1->parent && buf2->parent &&
(buf1->parent == buf2->parent) &&
((buf1->data + buf1->size) == buf2->data));
}
@ -420,38 +433,43 @@ gst_buffer_span (GstBuffer *buf1, guint32 offset, GstBuffer *buf2, guint32 len)
{
GstBuffer *newbuf;
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf1) > 0, NULL);
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf2) > 0, NULL);
// make sure buf1 has a lower address than buf2
if (buf1->data > buf2->data) {
GstBuffer *tmp = buf1;
g_print ("swapping buffers\n");
buf1 = buf2;
buf2 = tmp;
}
// if the two buffers have the same parent and are adjacent
// if ((buf1->parent == buf2->parent) &&
// ((buf1->data + buf1->size) == buf2->data)) {
if (gst_buffer_is_span_fast(buf1,buf2)) {
// we simply create a subbuffer of the common parent
return gst_buffer_create_sub(buf1->parent, buf1->data - (buf1->parent->data) + offset, len);
newbuf = gst_buffer_create_sub (buf1->parent, buf1->data - (buf1->parent->data) + offset, len);
}
else {
g_print ("slow path taken in buffer_span\n");
// otherwise we simply have to brute-force copy the buffers
newbuf = gst_buffer_new ();
// otherwise we simply have to brute-force copy the buffers
newbuf = gst_buffer_new();
// put in new size
newbuf->size = len;
// allocate space for the copy
newbuf->data = (guchar *)g_malloc(len);
// copy the first buffer's data across
memcpy(newbuf->data, buf1->data + offset, buf1->size - offset);
// copy the second buffer's data across
memcpy(newbuf->data + (buf1->size - offset), buf2->data, len - (buf1->size - offset));
// put in new size
newbuf->size = len;
// allocate space for the copy
newbuf->data = (guchar *)g_malloc(len);
// copy the first buffer's data across
memcpy(newbuf->data, buf1->data + offset, buf1->size - offset);
// copy the second buffer's data across
memcpy(newbuf->data + offset, buf2->data, len - (buf1->size - offset));
if (newbuf->offset != -1)
newbuf->offset = buf1->offset + offset;
newbuf->timestamp = buf1->timestamp;
if (buf2->maxage > buf1->maxage) newbuf->maxage = buf2->maxage;
else newbuf->maxage = buf1->maxage;
if (newbuf->offset != -1)
newbuf->offset = buf1->offset + offset;
newbuf->timestamp = buf1->timestamp;
if (buf2->maxage > buf1->maxage) newbuf->maxage = buf2->maxage;
else newbuf->maxage = buf1->maxage;
}
return newbuf;
}
@ -475,5 +493,5 @@ GstBuffer *
gst_buffer_merge (GstBuffer *buf1, GstBuffer *buf2)
{
// we're just a specific case of the more general gst_buffer_span()
return gst_buffer_span(buf1, 0, buf2, buf1->size + buf2->size);
return gst_buffer_span (buf1, 0, buf2, buf1->size + buf2->size);
}

View file

@ -24,6 +24,18 @@
#ifndef __GST_BUFFER_H__
#define __GST_BUFFER_H__
//
// Define this to add file:line info to each GstBuffer showing
// the location in the source code where the buffer was created.
//
// #define GST_BUFFER_WHERE
//
// Then in gdb, you can `call gst_buffer_print_live()' to get a list
// of allocated GstBuffers and also the file:line where they were
// allocated.
//
#include <gst/gstdata.h>
#include <gst/gstobject.h>
#ifdef HAVE_CONFIG_H
@ -39,18 +51,16 @@
extern "C" {
#endif /* __cplusplus */
extern GType _gst_buffer_type;
#define GST_BUFFER(buf) \
((GstBuffer *)(buf))
#define GST_TYPE_BUFFER (_gst_buffer_type)
#define GST_BUFFER(buf) ((GstBuffer *)(buf))
#define GST_IS_BUFFER(buf) (GST_DATA_TYPE(buf) == GST_TYPE_BUFFER)
#define GST_BUFFER_FLAGS(buf) \
(GST_BUFFER(buf)->flags)
#define GST_BUFFER_FLAG_IS_SET(buf,flag) \
(GST_BUFFER_FLAGS(buf) & (1<<(flag)))
#define GST_BUFFER_FLAG_SET(buf,flag) \
G_STMT_START{ (GST_BUFFER_FLAGS(buf) |= (1<<(flag))); }G_STMT_END
#define GST_BUFFER_FLAG_UNSET(buf,flag) \
G_STMT_START{ (GST_BUFFER_FLAGS(buf) &= ~(1<<(flag))); }G_STMT_END
#define GST_BUFFER_FLAGS(buf) (GST_BUFFER(buf)->flags)
#define GST_BUFFER_FLAG_IS_SET(buf,flag) (GST_BUFFER_FLAGS(buf) & (1<<(flag)))
#define GST_BUFFER_FLAG_SET(buf,flag) G_STMT_START{ (GST_BUFFER_FLAGS(buf) |= (1<<(flag))); }G_STMT_END
#define GST_BUFFER_FLAG_UNSET(buf,flag) G_STMT_START{ (GST_BUFFER_FLAGS(buf) &= ~(1<<(flag))); }G_STMT_END
#define GST_BUFFER_DATA(buf) (GST_BUFFER(buf)->data)
@ -82,7 +92,6 @@ typedef enum {
} GstBufferFlags;
typedef struct _GstBuffer GstBuffer;
@ -93,56 +102,56 @@ typedef GstBuffer *(*GstBufferCopyFunc) (GstBuffer *srcbuf);
#include <gst/gstbufferpool.h>
struct _GstBuffer {
GstData data_type;
/* locking */
GMutex *lock;
GMutex *lock;
/* refcounting */
#ifdef HAVE_ATOMIC_H
atomic_t refcount;
atomic_t refcount;
#define GST_BUFFER_REFCOUNT(buf) (atomic_read(&(GST_BUFFER((buf))->refcount)))
#else
int refcount;
int refcount;
#define GST_BUFFER_REFCOUNT(buf) (GST_BUFFER(buf)->refcount)
#endif
/* flags */
guint16 flags;
guint16 flags;
/* pointer to data, its size, and offset in original source if known */
guchar *data;
guint32 size;
guint32 maxsize;
guint32 offset;
guchar *data;
guint32 size;
guint32 maxsize;
guint32 offset;
/* timestamp */
gint64 timestamp;
/* max age */
gint64 maxage;
gint64 timestamp;
gint64 maxage;
/* subbuffer support, who's my parent? */
GstBuffer *parent;
GstBuffer *parent;
/* this is a pointer to the buffer pool (if any) */
GstBufferPool *pool;
gpointer pool_private;
GstBufferPool *pool;
gpointer pool_private;
/* utility function pointers */
GstBufferFreeFunc free; // free the data associated with the buffer
GstBufferCopyFunc copy; // copy the data from one buffer to another
GstBufferFreeFunc free; // free the data associated with the buffer
GstBufferCopyFunc copy; // copy the data from one buffer to another
};
/* initialisation */
void _gst_buffer_initialize (void);
/* creating a new buffer from scratch */
GstBuffer* gst_buffer_new (void);
GstBuffer* gst_buffer_new_from_pool (GstBufferPool *pool, guint64 location, gint size);
GstBuffer* gst_buffer_new_from_pool (GstBufferPool *pool, guint32 offset, guint32 size);
/* creating a subbuffer */
GstBuffer* gst_buffer_create_sub (GstBuffer *parent, guint32 offset, guint32 size);
/* refcounting */
void gst_buffer_ref (GstBuffer *buffer);
void gst_buffer_ref_by_count (GstBuffer *buffer, int count);
void gst_buffer_unref (GstBuffer *buffer);
/* destroying the buffer */

View file

@ -274,6 +274,13 @@ gst_buffer_pool_destroy (GstBufferPool *pool)
g_free(pool);
}
//
// This is so we don't get messed up by GST_BUFFER_WHERE.
//
static GstBuffer *
_pool_gst_buffer_copy (GstBuffer *buffer)
{ return gst_buffer_copy (buffer); }
/**
* gst_buffer_pool_get_default:
* @buffer_size: the number of bytes this buffer will store
@ -314,7 +321,7 @@ gst_buffer_pool_get_default (guint buffer_size, guint pool_size)
pool = gst_buffer_pool_new();
gst_buffer_pool_set_buffer_new_function (pool, gst_buffer_pool_default_buffer_new);
gst_buffer_pool_set_buffer_free_function (pool, gst_buffer_pool_default_buffer_free);
gst_buffer_pool_set_buffer_copy_function (pool, gst_buffer_copy);
gst_buffer_pool_set_buffer_copy_function (pool, _pool_gst_buffer_copy);
gst_buffer_pool_set_destroy_hook (pool, gst_buffer_pool_default_destroy_hook);
def = g_new0 (GstBufferPoolDefault, 1);

View file

@ -545,7 +545,7 @@ gst_caps_check_compatibility (GstCaps *fromcaps, GstCaps *tocaps)
return FALSE;
}
#if (! (defined(GST_DISABLE_LOADSAVE) && defined(GST_DISABLE_REGISTRY)) )
#ifndef GST_DISABLE_LOADSAVE_REGISTRY
/**
* gst_caps_save_thyself:
* @caps: a capabilty to save
@ -629,4 +629,4 @@ gst_caps_load_thyself (xmlNodePtr parent)
return result;
}
#endif /* (! (defined(GST_DISABLE_LOADSAVE) && defined(GST_DISABLE_REGISTRY)) ) */
#endif /* GST_DISABLE_LOADSAVE_REGISTRY */

View file

@ -24,14 +24,7 @@
#ifndef __GST_CAPS_H__
#define __GST_CAPS_H__
#include <parser.h> // NOTE: this is xml-config's fault
// Include compatability defines: if libxml hasn't already defined these,
// we have an old version 1.x
#ifndef xmlChildrenNode
#define xmlChildrenNode childs
#define xmlRootNode root
#endif
#include <gst/gstconfig.h>
#include <gst/gstprops.h>
@ -118,7 +111,9 @@ GstCaps* gst_caps_prepend (GstCaps *caps, GstCaps *capstoadd);
gboolean gst_caps_check_compatibility (GstCaps *fromcaps, GstCaps *tocaps);
#ifndef GST_DISABLE_LOADSAVE
xmlNodePtr gst_caps_save_thyself (GstCaps *caps, xmlNodePtr parent);
GstCaps* gst_caps_load_thyself (xmlNodePtr parent);
#endif
#endif /* __GST_CAPS_H__ */

32
gst/gstconfig.h Normal file
View file

@ -0,0 +1,32 @@
/* This header interprets the various GST_* macros that are typically *
* provided by the gstreamer-config or gstreamer.pc files. */
#ifndef __GST_CONFIG_H__
#define __GST_CONFIG_H__
/***** We include config.h in case someone perhaps used a gstreamer.m4 or
something else that provides funky overrides. BEWARE! *****/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
/***** Deal with XML stuff, we have to handle both loadsave and registry *****/
#if (! (defined(GST_DISABLE_LOADSAVE) && defined(GST_DISABLE_REGISTRY)) )
#include <parser.h>
// Include compatability defines: if libxml hasn't already defined these,
// we have an old version 1.x
#ifndef xmlChildrenNode
#define xmlChildrenNode childs
#define xmlRootNode root
#endif
#else
#define GST_DISABLE_LOADSAVE_REGISTRY
#endif
#endif /* __GST_CONFIG_H__ */

46
gst/gstdata.h Normal file
View file

@ -0,0 +1,46 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wim.taymans@chello.be>
*
* gstdata.h: Header for GstData objects (used for data passing)
*
* 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_DATA_H__
#define __GST_DATA_H__
#include <gst/gstobject.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#define GST_DATA(data) (GstData*)(data)
#define GST_DATA_TYPE(data) (((GstData*)(data))->type)
typedef struct _GstData GstData;
struct _GstData {
GType type;
};
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __GST_DATA_H__ */

View file

@ -65,13 +65,14 @@ static xmlNodePtr gst_element_save_thyself (GstObject *object, xmlNodePtr paren
GstElement* gst_element_restore_thyself (xmlNodePtr self, GstObject *parent);
#endif
GType _gst_element_type = 0;
static GstObjectClass *parent_class = NULL;
static guint gst_element_signals[LAST_SIGNAL] = { 0 };
GType gst_element_get_type(void) {
static GType element_type = 0;
if (!element_type) {
GType gst_element_get_type (void)
{
if (!_gst_element_type) {
static const GTypeInfo element_info = {
sizeof(GstElementClass),
(GBaseInitFunc)gst_element_base_class_init,
@ -84,9 +85,9 @@ GType gst_element_get_type(void) {
(GInstanceInitFunc)gst_element_init,
NULL
};
element_type = g_type_register_static(GST_TYPE_OBJECT, "GstElement", &element_info, G_TYPE_FLAG_ABSTRACT);
_gst_element_type = g_type_register_static(GST_TYPE_OBJECT, "GstElement", &element_info, G_TYPE_FLAG_ABSTRACT);
}
return element_type;
return _gst_element_type;
}
static void
@ -602,14 +603,14 @@ gst_element_get_padtemplate_by_compatible (GstElement *element, GstPadTemplate *
}
static GstPad*
gst_element_request_pad (GstElement *element, GstPadTemplate *templ)
gst_element_request_pad (GstElement *element, GstPadTemplate *templ, const gchar* name)
{
GstPad *newpad = NULL;
GstElementClass *oclass;
oclass = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS(element));
if (oclass->request_new_pad)
newpad = (oclass->request_new_pad)(element, templ);
newpad = (oclass->request_new_pad)(element, templ, name);
return newpad;
}
@ -638,7 +639,7 @@ gst_element_request_compatible_pad (GstElement *element, GstPadTemplate *templ)
templ_new = gst_element_get_padtemplate_by_compatible (element, templ);
if (templ_new != NULL)
pad = gst_element_request_pad (element, templ_new);
pad = gst_element_request_pad (element, templ_new, NULL);
return pad;
}
@ -658,19 +659,40 @@ gst_element_request_compatible_pad (GstElement *element, GstPadTemplate *templ)
GstPad*
gst_element_request_pad_by_name (GstElement *element, const gchar *name)
{
GstPadTemplate *templ;
GstPadTemplate *templ = NULL;
GstPad *pad;
const gchar *req_name = NULL;
gboolean templ_found = FALSE;
GList *list;
gint n;
g_return_val_if_fail (element != NULL, NULL);
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
g_return_val_if_fail (name != NULL, NULL);
templ = gst_element_get_padtemplate_by_name (element, name);
if (strstr (name, "%d")) {
templ = gst_element_get_padtemplate_by_name (element, name);
req_name = NULL;
} else {
list = gst_element_get_padtemplate_list(element);
while (!templ_found && list) {
templ = (GstPadTemplate*) list->data;
if (strstr (templ->name_template, "%d")) {
if (sscanf(name, templ->name_template, &n)) {
templ_found = TRUE;
req_name = name;
break;
}
}
list = list->next;
}
}
if (templ == NULL)
return NULL;
pad = gst_element_request_pad (element, templ);
return NULL;
pad = gst_element_request_pad (element, templ, req_name);
return pad;
}
@ -772,6 +794,14 @@ gst_element_error (GstElement *element, const gchar *error)
}
GstElementState
gst_element_get_state (GstElement *elem)
{
g_return_val_if_fail (GST_IS_ELEMENT (elem), GST_STATE_VOID_PENDING);
return GST_STATE (elem);
}
/**
* gst_element_set_state:
* @element: element to change state of
@ -836,7 +866,6 @@ gst_element_set_state (GstElement *element, GstElementState state)
}
}
/* this is redundant, really, it will always return SUCCESS */
return return_val;
}
@ -1157,7 +1186,7 @@ gst_element_restore_thyself (xmlNodePtr self, GstObject *parent)
return element;
}
#endif // GST_DISABLE_LOADSAVE
#endif /* GST_DISABLE_LOADSAVE */
/**
* gst_element_set_sched:

View file

@ -24,14 +24,7 @@
#ifndef __GST_ELEMENT_H__
#define __GST_ELEMENT_H__
#include <parser.h> // NOTE: this is xml-config's fault
// Include compatability defines: if libxml hasn't already defined these,
// we have an old version 1.x
#ifndef xmlChildrenNode
#define xmlChildrenNode childs
#define xmlRootNode root
#endif
#include <gst/gstconfig.h>
#include <gst/gstobject.h>
#include <gst/gstpad.h>
@ -72,16 +65,22 @@ typedef enum {
#define GST_STATE_PAUSED_TO_READY ((GST_STATE_PAUSED<<8) | GST_STATE_READY)
#define GST_STATE_READY_TO_NULL ((GST_STATE_READY<<8) | GST_STATE_NULL)
#define GST_TYPE_ELEMENT \
(gst_element_get_type())
#define GST_ELEMENT(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ELEMENT,GstElement))
#define GST_ELEMENT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ELEMENT,GstElementClass))
#define GST_IS_ELEMENT(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ELEMENT))
#define GST_IS_ELEMENT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ELEMENT))
extern GType _gst_element_type;
#define GST_TYPE_ELEMENT (_gst_element_type)
#define GST_ELEMENT_FAST(obj) ((GstElement*)(obj))
#define GST_ELEMENT_CLASS_FAST(klass) ((GstElementClass*)(klass))
#define GST_IS_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_ELEMENT))
#define GST_IS_ELEMENT_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_ELEMENT))
#ifdef GST_TYPE_PARANOID
# define GST_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_ELEMENT, GstElement))
# define GST_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_ELEMENT, GstElementClass))
#else
# define GST_ELEMENT GST_ELEMENT_FAST
# define GST_ELEMENT_CLASS GST_ELEMENT_CLASS_FAST
#endif
typedef enum {
/* element is complex (for some def.) and generally require a cothread */
@ -132,32 +131,32 @@ typedef struct _GstElementFactoryClass GstElementFactoryClass;
typedef void (*GstElementLoopFunction) (GstElement *element);
struct _GstElement {
GstObject object;
guint8 current_state;
guint8 pending_state;
GstObject object;
/* element state and scheduling */
guint8 current_state;
guint8 pending_state;
GstElement *manager;
GstSchedule *sched;
GstElementLoopFunction loopfunc;
cothread_state *threadstate;
GstPad *select_pad;
cothread_state *threadstate;
guint16 numpads;
guint16 numsrcpads;
guint16 numsinkpads;
GList *pads;
GstElement *manager;
GstSchedule *sched;
/* element pads */
guint16 numpads;
guint16 numsrcpads;
guint16 numsinkpads;
GList *pads;
GstPad *select_pad;
};
struct _GstElementClass {
GstObjectClass parent_class;
GstObjectClass parent_class;
/* the elementfactory that created us */
GstElementFactory *elementfactory;
GstElementFactory *elementfactory;
/* templates for our pads */
GList *padtemplates;
gint numpadtemplates;
GList *padtemplates;
gint numpadtemplates;
/* signal callbacks */
void (*state_change) (GstElement *element,GstElementState state);
@ -169,13 +168,13 @@ struct _GstElementClass {
void (*eos) (GstElement *element);
/* local pointers for get/set */
void (*set_property) (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
void (*get_property) (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
void (*set_property) (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
void (*get_property) (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
/* change the element state */
GstElementStateReturn (*change_state) (GstElement *element);
/* request a new pad */
GstPad* (*request_new_pad) (GstElement *element, GstPadTemplate *templ);
GstPad* (*request_new_pad) (GstElement *element, GstPadTemplate *templ, const gchar* name);
};
void gst_element_class_add_padtemplate (GstElementClass *element, GstPadTemplate *templ);
@ -215,6 +214,7 @@ void gst_element_disconnect (GstElement *src, const gchar *srcpadname,
void gst_element_signal_eos (GstElement *element);
GstElementState gst_element_get_state (GstElement *elem);
/* called by the app to set the state of the element */
gint gst_element_set_state (GstElement *element, GstElementState state);
const gchar * gst_element_statename (GstElementState state);
@ -223,8 +223,10 @@ void gst_element_error (GstElement *element, const gchar *error);
GstElementFactory* gst_element_get_factory (GstElement *element);
#ifndef GST_DISABLE_LOADSAVE
/* XML write and read */
GstElement* gst_element_restore_thyself (xmlNodePtr self, GstObject *parent);
#endif
/*
@ -243,16 +245,13 @@ struct _GstElementDetails {
gchar *copyright; /* copyright details (year, etc.) */
};
#define GST_TYPE_ELEMENTFACTORY \
(gst_elementfactory_get_type())
#define GST_ELEMENTFACTORY(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ELEMENTFACTORY,GstElementFactory))
#define GST_ELEMENTFACTORY_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ELEMENTFACTORY,GstElementFactoryClass))
#define GST_IS_ELEMENTFACTORY(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ELEMENTFACTORY))
#define GST_IS_ELEMENTFACTORY_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ELEMENTFACTORY))
#define GST_TYPE_ELEMENTFACTORY (gst_elementfactory_get_type())
#define GST_ELEMENTFACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ELEMENTFACTORY,\
GstElementFactory))
#define GST_ELEMENTFACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ELEMENTFACTORY,\
GstElementFactoryClass))
#define GST_IS_ELEMENTFACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ELEMENTFACTORY))
#define GST_IS_ELEMENTFACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ELEMENTFACTORY))
struct _GstElementFactory {
GstPluginFeature feature;

View file

@ -31,7 +31,7 @@ static void gst_elementfactory_init (GstElementFactory *factory);
#ifndef GST_DISABLE_REGISTRY
static void gst_elementfactory_restore_thyself (GstObject *object, xmlNodePtr parent);
static xmlNodePtr gst_elementfactory_save_thyself (GstObject *object, xmlNodePtr parent);
#endif /* GST_DISABLE_REGISTRY */
#endif
static void gst_elementfactory_unload_thyself (GstPluginFeature *feature);
@ -81,7 +81,7 @@ gst_elementfactory_class_init (GstElementFactoryClass *klass)
#ifndef GST_DISABLE_REGISTRY
gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_elementfactory_save_thyself);
gstobject_class->restore_thyself = GST_DEBUG_FUNCPTR (gst_elementfactory_restore_thyself);
#endif /* GST_DISABLE_REGISTRY */
#endif
gstpluginfeature_class->unload_thyself = GST_DEBUG_FUNCPTR (gst_elementfactory_unload_thyself);

96
gst/gstevent.c Normal file
View file

@ -0,0 +1,96 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wim.taymans@chello.be>
*
* gstevent.h: Header for GstEvent subsystem
*
* 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.
*/
#include "gst/gstinfo.h"
#include "gst/gstevent.h"
GType _gst_event_type;
static GMemChunk *_gst_event_chunk;
static GMutex *_gst_event_chunk_lock;
void
_gst_event_initialize (void)
{
gint eventsize = sizeof(GstEvent);
static const GTypeInfo event_info = {
0,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
0,
NULL,
};
// round up to the nearest 32 bytes for cache-line and other efficiencies
eventsize = (((eventsize-1) / 32) + 1) * 32;
_gst_event_chunk = g_mem_chunk_new ("GstEvent", eventsize,
eventsize * 32, G_ALLOC_AND_FREE);
_gst_event_chunk_lock = g_mutex_new ();
// register the type
_gst_event_type = g_type_register_static (G_TYPE_INT, "GstEvent", &event_info, 0);
}
GstEvent*
gst_event_new (GstEventType type)
{
GstEvent *event;
g_mutex_lock (_gst_event_chunk_lock);
event = g_mem_chunk_alloc (_gst_event_chunk);
g_mutex_unlock (_gst_event_chunk_lock);
GST_INFO (GST_CAT_EVENT, "creating new event %p", event);
GST_DATA_TYPE (event) = _gst_event_type;
GST_EVENT_TYPE (event) = type;
return event;
}
void
gst_event_free (GstEvent* event)
{
g_mutex_lock (_gst_event_chunk_lock);
g_mem_chunk_free (_gst_event_chunk, event);
g_mutex_unlock (_gst_event_chunk_lock);
}
/* seek stuff */
GstEvent*
gst_event_new_seek (GstSeekType type, guint64 offset, gboolean flush)
{
GstEvent *event;
event = gst_event_new (GST_EVENT_SEEK);
GST_EVENT_SEEK_TYPE (event) = type;
GST_EVENT_SEEK_OFFSET (event) = offset;
GST_EVENT_SEEK_FLUSH (event) = flush;
return event;
}

View file

@ -25,6 +25,7 @@
#define __GST_EVENT_H__
#include <gst/gstobject.h>
#include <gst/gstdata.h>
#ifdef __cplusplus
extern "C" {
@ -36,14 +37,57 @@ typedef enum {
GST_EVENT_FLUSH,
GST_EVENT_EMPTY,
GST_EVENT_SEEK,
GST_EVENT_DISCONTINUOUS
} GstEventType;
extern GType _gst_event_type;
#define GST_TYPE_EVENT (_gst_event_type)
#define GST_EVENT(event) ((GstEvent*)(event))
#define GST_IS_EVENT(event) (GST_DATA_TYPE(event) == GST_TYPE_EVENT)
#define GST_EVENT_TYPE(event) (GST_EVENT(event)->type)
#define GST_EVENT_TIMESTAMP(event) (GST_EVENT(event)->timstamp)
/* seek events */
typedef enum {
GST_SEEK_ANY,
GST_SEEK_TIMEOFFSET,
GST_SEEK_BYTEOFFSET
} GstSeekType;
#define GST_EVENT_SEEK_TYPE(event) (GST_EVENT(event)->event_data.seek.type)
#define GST_EVENT_SEEK_OFFSET(event) (GST_EVENT(event)->event_data.seek.offset)
#define GST_EVENT_SEEK_FLUSH(event) (GST_EVENT(event)->event_data.seek.flush)
typedef struct _GstEvent GstEvent;
struct _GstEvent {
GstEventType type;
GstData data;
GstEventType type;
guint64 timestamp;
union {
struct {
GstSeekType type;
guint64 offset;
gboolean flush;
} seek;
} event_data;
};
void _gst_event_initialize (void);
GstEvent* gst_event_new (GstEventType type);
void gst_event_free (GstEvent* event);
/* seek events */
GstEvent* gst_event_new_seek (GstSeekType type, guint64 offset, gboolean flush);
/* flush events */
#define gst_event_new_flush() gst_event_new(GST_EVENT_FLUSH)
#ifdef __cplusplus
}
#endif /* __cplusplus */

View file

@ -459,6 +459,8 @@ gst_default_error_handler (gchar *file, gchar *function,
/***** DEBUG system *****/
GHashTable *__gst_function_pointers = NULL;
// FIXME make this thread specific
static GSList* stack_trace = NULL;
gchar *_gst_debug_nameof_funcptr (void *ptr) __attribute__ ((no_instrument_function));
@ -479,15 +481,52 @@ _gst_debug_nameof_funcptr (void *ptr)
#ifdef GST_ENABLE_FUNC_INSTRUMENTATION
void __cyg_profile_func_enter(void *this_fn,void *call_site) __attribute__ ((no_instrument_function));
void __cyg_profile_func_enter(void *this_fn,void *call_site) {
GST_DEBUG(GST_CAT_CALL_TRACE, "entering function %s\n", _gst_debug_nameof_funcptr (this_fn));
void __cyg_profile_func_enter(void *this_fn,void *call_site)
{
gchar *name = _gst_debug_nameof_funcptr (this_fn);
gchar *site = _gst_debug_nameof_funcptr (call_site);
GST_DEBUG(GST_CAT_CALL_TRACE, "entering function %s from %s\n", name, site);
stack_trace = g_slist_prepend (stack_trace, g_strdup_printf ("%8p in %s from %p (%s)", this_fn, name, call_site, site));
g_free (name);
g_free (site);
}
void __cyg_profile_func_exit(void *this_fn,void *call_site) __attribute__ ((no_instrument_function));
void __cyg_profile_func_exit(void *this_fn,void *call_site) {
GST_DEBUG(GST_CAT_CALL_TRACE, "leavinging function %s\n", _gst_debug_nameof_funcptr (this_fn));
void __cyg_profile_func_exit(void *this_fn,void *call_site)
{
gchar *name = _gst_debug_nameof_funcptr (this_fn);
GST_DEBUG(GST_CAT_CALL_TRACE, "leaving function %s\n", name);
g_free (stack_trace->data);
stack_trace = g_slist_delete_link (stack_trace, stack_trace);
g_free (name);
}
void
gst_debug_print_stack_trace (void)
{
GSList *walk = stack_trace;
gint count = 0;
if (walk)
walk = g_slist_next (walk);
while (walk) {
gchar *name = (gchar *) walk->data;
g_print ("#%-2d %s\n", count++, name);
walk = g_slist_next (walk);
}
}
#else
void
gst_debug_print_stack_trace (void)
{
}
#endif /* GST_ENABLE_FUNC_INTSTRUMENTATION */

View file

@ -341,6 +341,8 @@ _gst_debug_register_funcptr (void *ptr, gchar *ptrname)
gchar *_gst_debug_nameof_funcptr (void *ptr);
void gst_debug_print_stack_trace (void);
#endif /* __GSTINFO_H__ */

View file

@ -27,7 +27,7 @@
/* Object signals and args */
enum {
PARENT_SET,
#ifndef GST_DISABLE_LOADSAVE
#ifndef GST_DISABLE_LOADSAVE_REGISTRY
OBJECT_SAVED,
#endif
LAST_SIGNAL
@ -43,6 +43,8 @@ enum {
SO_LAST_SIGNAL
};
GType _gst_object_type = 0;
typedef struct _GstSignalObject GstSignalObject;
typedef struct _GstSignalObjectClass GstSignalObjectClass;
@ -64,9 +66,7 @@ static guint gst_object_signals[LAST_SIGNAL] = { 0 };
GType
gst_object_get_type (void)
{
static GType object_type = 0;
if (!object_type) {
if (!_gst_object_type) {
static const GTypeInfo object_info = {
sizeof (GstObjectClass),
NULL,
@ -79,9 +79,9 @@ gst_object_get_type (void)
(GInstanceInitFunc) gst_object_init,
NULL
};
object_type = g_type_register_static (G_TYPE_OBJECT, "GstObject", &object_info, G_TYPE_FLAG_ABSTRACT);
_gst_object_type = g_type_register_static (G_TYPE_OBJECT, "GstObject", &object_info, G_TYPE_FLAG_ABSTRACT);
}
return object_type;
return _gst_object_type;
}
static void
@ -98,7 +98,7 @@ gst_object_class_init (GstObjectClass *klass)
G_STRUCT_OFFSET (GstObjectClass, parent_set), NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,G_TYPE_NONE,1,
G_TYPE_OBJECT);
#ifndef GST_DISABLE_LOADSAVE
#ifndef GST_DISABLE_LOADSAVE_REGISTRY
gst_object_signals[OBJECT_SAVED] =
g_signal_new("object_saved", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstObjectClass, object_saved), NULL, NULL,
@ -446,7 +446,7 @@ gst_object_check_uniqueness (GList *list, const gchar *name)
}
#ifndef GST_DISABLE_LOADSAVE
#ifndef GST_DISABLE_LOADSAVE_REGISTRY
/**
* gst_object_save_thyself:
* @object: GstObject to save
@ -496,7 +496,7 @@ gst_object_restore_thyself (GstObject *object, xmlNodePtr parent)
if (oclass->restore_thyself)
oclass->restore_thyself (object, parent);
}
#endif // GST_DISABLE_LOADSAVE
#endif /* GST_DISABLE_LOADSAVE_REGISTRY */
/**
* gst_object_get_path_string:
@ -577,9 +577,9 @@ struct _GstSignalObjectClass {
GObjectClass parent_class;
/* signals */
#ifndef GST_DISABLE_LOADSAVE
#ifndef GST_DISABLE_LOADSAVE_REGISTRY
void (*object_loaded) (GstSignalObject *object, GstObject *new, xmlNodePtr self);
#endif /* GST_DISABLE_LOADSAVE */
#endif /* GST_DISABLE_LOADSAVE_REGISTRY */
};
static GType
@ -614,7 +614,7 @@ gst_signal_object_class_init (GstSignalObjectClass *klass)
parent_class = g_type_class_ref (G_TYPE_OBJECT);
#ifndef GST_DISABLE_LOADSAVE
#ifndef GST_DISABLE_LOADSAVE_REGISTRY
gst_signal_object_signals[SO_OBJECT_LOADED] =
g_signal_new("object_loaded", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstObjectClass, parent_set), NULL, NULL,
@ -648,7 +648,7 @@ gst_class_signal_connect (GstObjectClass *klass,
return g_signal_connect (klass->signal_object, name, func, func_data);
}
#ifndef GST_DISABLE_LOADSAVE
#ifndef GST_DISABLE_LOADSAVE_REGISTRY
/**
* gst_class_signal_emit_by_name:
* @object: the object that sends the signal
@ -669,4 +669,4 @@ gst_class_signal_emit_by_name (GstObject *object,
g_signal_emit_by_name (oclass->signal_object, name, object, self);
}
#endif // GST_DISABLE_LOADSAVE
#endif /* GST_DISABLE_LOADSAVE_REGISTRY */

View file

@ -24,10 +24,7 @@
#ifndef __GST_OBJECT_H__
#define __GST_OBJECT_H__
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gstconfig.h>
#ifdef USE_GLIB2
#include <glib-object.h> // note that this gets wrapped in __GST_OBJECT_H__
@ -36,15 +33,13 @@
#include <gst/gobject2gtk.h>
#endif
#include <gst/gsttrace.h>
#include <parser.h>
#include <gst/gsttypes.h>
#ifdef HAVE_ATOMIC_H
#include <asm/atomic.h>
#endif
#include <gst/gsttrace.h>
#include <gst/gsttypes.h>
// FIXME
#include "gstlog.h"
@ -52,17 +47,22 @@
extern "C" {
#endif /* __cplusplus */
extern GType _gst_object_type;
#define GST_TYPE_OBJECT \
(gst_object_get_type())
#define GST_OBJECT(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OBJECT,GstObject))
#define GST_OBJECT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OBJECT,GstObjectClass))
#define GST_IS_OBJECT(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OBJECT))
#define GST_IS_OBJECT_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OBJECT))
#define GST_TYPE_OBJECT (_gst_object_type)
# define GST_IS_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_OBJECT))
# define GST_IS_OBJECT_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_OBJECT))
#define GST_OBJECT_FAST(obj) ((GstObject*)(obj))
#define GST_OBJECT_CLASS_FAST(klass) ((GstObjectClass*)(klass))
#ifdef GST_TYPE_PARANOID
# define GST_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_OBJECT, GstObject))
# define GST_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_OBJECT, GstObjectClass))
#else
# define GST_OBJECT GST_OBJECT_FAST
# define GST_OBJECT_CLASS GST_OBJECT_CLASS_FAST
#endif
//typedef struct _GstObject GstObject;
//typedef struct _GstObjectClass GstObjectClass;
@ -76,40 +76,43 @@ typedef enum
} GstObjectFlags;
struct _GstObject {
GObject object;
GObject object;
gchar *name;
gchar *name;
/* have to have a refcount for the object */
#ifdef HAVE_ATOMIC_H
atomic_t refcount;
atomic_t refcount;
#else
int refcount;
gint refcount;
#endif
/* locking for all sorts of things (like the refcount) */
GMutex *lock;
GMutex *lock;
/* this objects parent */
GstObject *parent;
GstObject *parent;
guint32 flags;
guint32 flags;
};
struct _GstObjectClass {
GObjectClass parent_class;
gchar *path_string_separator;
GObject *signal_object;
gchar *path_string_separator;
GObject *signal_object;
/* signals */
void (*parent_set) (GstObject *object, GstObject *parent);
#ifndef GST_DISABLE_LOADSAVE_REGISTRY
void (*object_saved) (GstObject *object, xmlNodePtr parent);
#endif
/* functions go here */
void (*destroy) (GstObject *object);
#ifndef GST_DISABLE_LOADSAVE_REGISTRY
xmlNodePtr (*save_thyself) (GstObject *object, xmlNodePtr parent);
void (*restore_thyself) (GstObject *object, xmlNodePtr self);
#endif
};
#define GST_FLAGS(obj) (GST_OBJECT (obj)->flags)
@ -144,11 +147,12 @@ void gst_object_unparent (GstObject *object);
gboolean gst_object_check_uniqueness (GList *list, const gchar *name);
#ifndef GST_DISABLE_LOADSAVE
#ifndef GST_DISABLE_LOADSAVE_REGISTRY
xmlNodePtr gst_object_save_thyself (GstObject *object, xmlNodePtr parent);
void gst_object_restore_thyself (GstObject *object, xmlNodePtr parent);
void gst_object_restore_thyself (GstObject *object, xmlNodePtr parent);
#else
#pragma GCC poison gst_object_save_thyself
#pragma GCC poison gst_object_restore_thyself
#endif
/* refcounting */
@ -166,7 +170,7 @@ guint gst_class_signal_connect (GstObjectClass *klass,
gpointer func,
gpointer func_data);
#ifndef GST_DISABLE_LOADSAVE
#ifndef GST_DISABLE_LOADSAVE_REGISTRY
void gst_class_signal_emit_by_name (GstObject *object,
const gchar *name,
xmlNodePtr self);

View file

@ -30,6 +30,7 @@
#include "gstbin.h"
#include "gstscheduler.h"
GType _gst_pad_type = 0;
/***** Start with the base GstPad class *****/
static void gst_pad_class_init (GstPadClass *klass);
@ -42,10 +43,9 @@ static xmlNodePtr gst_pad_save_thyself (GstObject *object, xmlNodePtr parent);
static GstObject *pad_parent_class = NULL;
GType
gst_pad_get_type(void) {
static GType pad_type = 0;
if (!pad_type) {
gst_pad_get_type(void)
{
if (!_gst_pad_type) {
static const GTypeInfo pad_info = {
sizeof(GstPadClass),
NULL,
@ -58,9 +58,9 @@ gst_pad_get_type(void) {
(GInstanceInitFunc)gst_pad_init,
NULL
};
pad_type = g_type_register_static(GST_TYPE_OBJECT, "GstPad", &pad_info, 0);
_gst_pad_type = g_type_register_static(GST_TYPE_OBJECT, "GstPad", &pad_info, 0);
}
return pad_type;
return _gst_pad_type;
}
static void
@ -107,15 +107,14 @@ static void gst_real_pad_dispose (GObject *object);
static void gst_pad_push_func (GstPad *pad, GstBuffer *buf);
GType _gst_real_pad_type = 0;
static GstPad *real_pad_parent_class = NULL;
static guint gst_real_pad_signals[REAL_LAST_SIGNAL] = { 0 };
GType
gst_real_pad_get_type(void) {
static GType pad_type = 0;
if (!pad_type) {
if (!_gst_real_pad_type) {
static const GTypeInfo pad_info = {
sizeof(GstRealPadClass),
NULL,
@ -128,9 +127,9 @@ gst_real_pad_get_type(void) {
(GInstanceInitFunc)gst_real_pad_init,
NULL
};
pad_type = g_type_register_static(GST_TYPE_PAD, "GstRealPad", &pad_info, 0);
_gst_real_pad_type = g_type_register_static(GST_TYPE_PAD, "GstRealPad", &pad_info, 0);
}
return pad_type;
return _gst_real_pad_type;
}
static void
@ -1432,7 +1431,7 @@ gst_pad_ghost_save_thyself (GstPad *pad,
return self;
}
#endif // GST_DISABLE_LOADSAVE
#endif /* GST_DISABLE_LOADSAVE */
#ifndef gst_pad_push
/**
@ -1881,6 +1880,7 @@ gst_pad_get_element_private (GstPad *pad)
/***** ghost pads *****/
GType _gst_ghost_pad_type = 0;
static void gst_ghost_pad_class_init (GstGhostPadClass *klass);
static void gst_ghost_pad_init (GstGhostPad *pad);
@ -1890,9 +1890,7 @@ static GstPad *ghost_pad_parent_class = NULL;
GType
gst_ghost_pad_get_type(void) {
static GType pad_type = 0;
if (!pad_type) {
if (!_gst_ghost_pad_type) {
static const GTypeInfo pad_info = {
sizeof(GstGhostPadClass),
NULL,
@ -1905,9 +1903,9 @@ gst_ghost_pad_get_type(void) {
(GInstanceInitFunc)gst_ghost_pad_init,
NULL
};
pad_type = g_type_register_static(GST_TYPE_PAD, "GstGhostPad", &pad_info, 0);
_gst_ghost_pad_type = g_type_register_static(GST_TYPE_PAD, "GstGhostPad", &pad_info, 0);
}
return pad_type;
return _gst_ghost_pad_type;
}
static void
@ -1985,14 +1983,36 @@ gst_pad_event (GstPad *pad, GstEventType event, gint64 timestamp, guint32 data)
GST_DEBUG(GST_CAT_EVENT, "have event %d on pad %s:%s\n",(gint)event,GST_DEBUG_PAD_NAME(pad));
peer = GST_RPAD_PEER(pad);
if (GST_RPAD_EVENTFUNC(peer))
handled = GST_RPAD_EVENTFUNC(peer) (peer, event, timestamp, data);
if (GST_RPAD_EVENTFUNC(peer)) {
//handled = GST_RPAD_EVENTFUNC(peer) (peer, event, timestamp, data);
}
else {
GST_DEBUG(GST_CAT_EVENT, "there's no event function for peer %s:%s\n",GST_DEBUG_PAD_NAME(peer));
}
if (!handled) {
GST_DEBUG(GST_CAT_EVENT, "would proceed with default behavior here\n");
gst_pad_event_default(peer,event, timestamp, data);
//gst_pad_event_default(peer,event, timestamp, data);
}
}
gboolean
gst_pad_send_event (GstPad *pad, GstEvent *event)
{
gboolean handled = FALSE;
GST_DEBUG (GST_CAT_EVENT, "have event %d on pad %s:%s\n",
GST_EVENT_TYPE (event), GST_DEBUG_PAD_NAME (pad));
if (GST_RPAD_EVENTFUNC (pad))
handled = GST_RPAD_EVENTFUNC (pad) (pad, event);
else {
GST_DEBUG(GST_CAT_EVENT, "there's no event function for pad %s:%s\n", GST_DEBUG_PAD_NAME (pad));
}
if (!handled) {
GST_DEBUG(GST_CAT_EVENT, "would proceed with default behavior here\n");
//gst_pad_event_default (pad, event);
}
}

View file

@ -24,14 +24,7 @@
#ifndef __GST_PAD_H__
#define __GST_PAD_H__
#include <parser.h> // NOTE: This is xml-config's fault
// Include compatability defines: if libxml hasn't already defined these,
// we have an old version 1.x
#ifndef xmlChildrenNode
#define xmlChildrenNode childs
#define xmlRootNode root
#endif
#include <gst/gstconfig.h>
#include <gst/gstobject.h>
#include <gst/gstbuffer.h>
@ -44,25 +37,70 @@
extern "C" {
#endif /* __cplusplus */
extern GType _gst_pad_type;
extern GType _gst_real_pad_type;
extern GType _gst_ghost_pad_type;
#define GST_TYPE_PAD (gst_pad_get_type ())
#define GST_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PAD, GstPad))
#define GST_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PAD, GstPadClass))
//#define GST_TYPE_PARANOID
/*
* Pad base class
*/
#define GST_TYPE_PAD (_gst_pad_type)
#define GST_PAD_FAST(obj) ((GstPad*)(obj))
#define GST_PAD_CLASS_FAST(klass) ((GstPadClass*)(klass))
#define GST_IS_PAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PAD))
#define GST_IS_PAD_FAST(obj) (G_OBJECT_TYPE(obj) == GST_TYPE_REAL_PAD || \
G_OBJECT_TYPE(obj) == GST_TYPE_GHOST_PAD)
#define GST_IS_PAD_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PAD))
#define GST_TYPE_REAL_PAD (gst_real_pad_get_type ())
#define GST_REAL_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_REAL_PAD, GstRealPad))
#define GST_REAL_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_REAL_PAD, GstRealPadClass))
#ifdef GST_TYPE_PARANOID
# define GST_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PAD, GstPad))
# define GST_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PAD, GstPadClass))
#else
# define GST_PAD GST_PAD_FAST
# define GST_PAD_CLASS GST_PAD_CLASS_FAST
#endif
/*
* Real Pads
*/
#define GST_TYPE_REAL_PAD (_gst_real_pad_type)
#define GST_REAL_PAD_FAST(obj) ((GstRealPad*)(obj))
#define GST_REAL_PAD_CLASS_FAST(klass) ((GstRealPadClass*)(klass))
#define GST_IS_REAL_PAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_REAL_PAD))
#define GST_IS_REAL_PAD_FAST(obj) (G_OBJECT_TYPE(obj) == GST_TYPE_REAL_PAD)
#define GST_IS_REAL_PAD_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_REAL_PAD))
#define GST_TYPE_GHOST_PAD (gst_ghost_pad_get_type ())
#define GST_GHOST_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_GHOST_PAD, GstGhostPad))
#define GST_GHOST_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_GHOST_PAD, GstGhostPadClass))
#ifdef GST_TYPE_PARANOID
# define GST_REAL_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_REAL_PAD, GstRealPad))
# define GST_REAL_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_REAL_PAD, GstRealPadClass))
#else
# define GST_REAL_PAD GST_REAL_PAD_FAST
# define GST_REAL_PAD_CLASS GST_REAL_PAD_CLASS_FAST
#endif
/*
* Ghost Pads
*/
#define GST_TYPE_GHOST_PAD (_gst_ghost_pad_type)
#define GST_GHOST_PAD_FAST(obj) ((GstGhostPad*)(obj))
#define GST_GHOST_PAD_CLASS_FAST(klass) ((GstGhostPadClass*)(klass))
#define GST_IS_GHOST_PAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_GHOST_PAD))
#define GST_IS_GHOST_PAD_FAST(obj) (G_OBJECT_TYPE(obj) == GST_TYPE_GHOST_PAD)
#define GST_IS_GHOST_PAD_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_GHOST_PAD))
#ifdef GST_TYPE_PARANOID
# define GST_GHOST_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_GHOST_PAD, GstGhostPad))
# define GST_GHOST_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_GHOST_PAD, GstGhostPadClass))
#else
# define GST_GHOST_PAD GST_GHOST_PAD_FAST
# define GST_GHOST_PAD_CLASS GST_GHOST_PAD_CLASS_FAST
#endif
//typedef struct _GstPad GstPad;
//typedef struct _GstPadClass GstPadClass;
@ -92,7 +130,7 @@ typedef enum {
* buf is the buffer being passed */
typedef void (*GstPadChainFunction) (GstPad *pad,GstBuffer *buf);
typedef GstBuffer* (*GstPadGetFunction) (GstPad *pad);
typedef gboolean (*GstPadEventFunction) (GstPad *pad, GstEventType event, gint64 timestamp, guint32 data);
typedef gboolean (*GstPadEventFunction) (GstPad *pad, GstEvent *event);
typedef GstBuffer* (*GstPadGetRegionFunction) (GstPad *pad, GstRegionType type, guint64 offset, guint64 len);
typedef GstBuffer* (*GstPadPullRegionFunction) (GstPad *pad, GstRegionType type, guint64 offset, guint64 len);
@ -375,12 +413,15 @@ FALSE )
}G_STMT_END
#endif
gboolean gst_pad_send_event (GstPad *pad, GstEvent *event);
GstBuffer* gst_pad_peek (GstPad *pad);
GstPad* gst_pad_select (GList *padlist);
GstPad* gst_pad_selectv (GstPad *pad, ...);
#ifndef GST_DISABLE_LOADSAVE
void gst_pad_load_and_connect (xmlNodePtr self, GstObject *parent);
#endif
/* ghostpads */
@ -397,8 +438,10 @@ GstPadTemplate* gst_padtemplate_new (gchar *name_template,
GstCaps* gst_padtemplate_get_caps (GstPadTemplate *templ);
GstCaps* gst_padtemplate_get_caps_by_name (GstPadTemplate *templ, const gchar *name);
#ifndef GST_DISABLE_LOADSAVE
xmlNodePtr gst_padtemplate_save_thyself (GstPadTemplate *templ, xmlNodePtr parent);
GstPadTemplate* gst_padtemplate_load_thyself (xmlNodePtr parent);
#endif
xmlNodePtr gst_pad_ghost_save_thyself (GstPad *pad,
GstElement *bin,

View file

@ -299,7 +299,11 @@ gst_parse_launch_cmdline(int argc,char *argv[],GstBin *parent,gst_parse_priv *pr
element = gst_elementfactory_make(arg,ptr);
g_free(ptr);
if (!element) {
#ifndef GST_DISABLE_REGISTRY
fprintf(stderr,"Couldn't create a '%s', no such element or need to run gstreamer-register?\n",arg);
#else
fprintf(stderr,"Couldn't create a '%s', no such element or need to load pluginn?\n",arg);
#endif
exit(-1);
}
GST_DEBUG(0,"CREATED element %s\n",GST_ELEMENT_NAME(element));

View file

@ -105,7 +105,7 @@ _gst_plugin_initialize (void)
gst_plugin_load_thyself (doc->xmlRootNode);
xmlFreeDoc (doc);
#endif // GST_DISABLE_REGISTRY
#endif /* GST_DISABLE_REGISTRY */
}
void
@ -845,7 +845,7 @@ gst_plugin_load_thyself (xmlNodePtr parent)
}
GST_INFO (GST_CAT_PLUGIN_LOADING, "added %d features ", featurecount);
}
#endif // GST_DISABLE_REGISTRY
#endif /* GST_DISABLE_REGISTRY */
/**

View file

@ -24,15 +24,9 @@
#ifndef __GST_PLUGIN_H__
#define __GST_PLUGIN_H__
#include <gmodule.h>
#include <parser.h> // NOTE: this is xml-config's fault
#include <gst/gstconfig.h>
// Include compatability defines: if libxml hasn't already defined these,
// we have an old version 1.x
#ifndef xmlChildrenNode
#define xmlChildrenNode childs
#define xmlRootNode root
#endif
#include <gmodule.h>
#include <gst/gstpluginfeature.h>

View file

@ -987,7 +987,7 @@ end:
return compatible;
}
#if (! (defined(GST_DISABLE_LOADSAVE) && defined(GST_DISABLE_REGISTRY)) )
#ifndef GST_DISABLE_LOADSAVE_REGISTRY
static xmlNodePtr
gst_props_save_thyself_func (GstPropsEntry *entry, xmlNodePtr parent)
{
@ -1242,5 +1242,5 @@ gst_props_load_thyself (xmlNodePtr parent)
return props;
}
#endif /* (! (defined(GST_DISABLE_LOADSAVE) && defined(GST_DISABLE_REGISTRY)) ) */
#endif /* GST_DISABLE_LOADSAVE_REGISTRY */

View file

@ -24,16 +24,9 @@
#ifndef __GST_PROPS_H__
#define __GST_PROPS_H__
#include <gst/gstconfig.h>
#include <glib.h>
#include <parser.h> // NOTE: this is xml-config's fault
// Include compatability defines: if libxml hasn't already defined these,
// we have an old version 1.x
#ifndef xmlChildrenNode
#define xmlChildrenNode childs
#define xmlRootNode root
#endif
typedef struct _GstProps GstProps;
@ -95,7 +88,9 @@ gulong gst_props_get_fourcc_int (GstProps *props, const gchar *name);
gboolean gst_props_get_boolean (GstProps *props, const gchar *name);
const gchar* gst_props_get_string (GstProps *props, const gchar *name);
#ifndef GST_DISABLE_LOADSAVE
xmlNodePtr gst_props_save_thyself (GstProps *props, xmlNodePtr parent);
GstProps* gst_props_load_thyself (xmlNodePtr parent);
#endif
#endif /* __GST_PROPS_H__ */

View file

@ -1424,7 +1424,7 @@ GST_DEBUG(GST_CAT_SCHEDULING,"there are %d elements in this chain\n",chain->num_
}
} else {
GST_INFO (GST_CAT_DATAFLOW,"NO ENABLED ELEMENTS IN CHAIN!!");
//eos = TRUE;
eos = TRUE;
}
/*

View file

@ -124,16 +124,16 @@ gst_thread_class_init (GstThreadClass *klass)
gobject_class->dispose = gst_thread_dispose;
#ifndef GST_DISABLE_LOADSAVE
gstobject_class->save_thyself = gst_thread_save_thyself;
gstobject_class->restore_thyself = gst_thread_restore_thyself;
gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_thread_save_thyself);
gstobject_class->restore_thyself = GST_DEBUG_FUNCPTR(gst_thread_restore_thyself);
#endif
gstelement_class->change_state = gst_thread_change_state;
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_thread_change_state);
// gstbin_class->schedule = gst_thread_schedule_dummy;
gobject_class->set_property = gst_thread_set_property;
gobject_class->get_property = gst_thread_get_property;
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_thread_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_thread_get_property);
}

View file

@ -28,4 +28,6 @@
#define GST_VERSION_MINOR @GST_VERSION_MINOR@
#define GST_VERSION_MICRO @GST_VERSION_MICRO@
void gst_version (guint *major, guint *minor, guint *micro);
#endif /* __GST_H__ */

View file

@ -23,17 +23,10 @@
#ifndef __GST_XML_H__
#define __GST_XML_H__
#include <gst/gstconfig.h>
#ifndef GST_DISABLE_LOADSAVE
#include <parser.h>
// Include compatability defines: if libxml hasn't already defined these,
// we have an old version 1.x
#ifndef xmlChildrenNode
#define xmlChildrenNode childs
#define xmlRootNode root
#endif
#include <gst/gstelement.h>
#ifdef __cplusplus

113
gst/utils/gstbytestream.c Normal file
View file

@ -0,0 +1,113 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
*
* gstbytestreams.c: Utility functions: gtk_get_property stuff, etc.
*
* 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.
*/
#include <stdio.h>
#include <string.h>
#include "gstbytestreams.h"
/**
* gst_bytestream_new:
* @pad: the pad to attach the bytstream to
*
* creates a bytestream from the given pad
*
* Returns: a new #GstByteStream object
*/
GstByteStream *
gst_bytestream_new (GstPad * pad)
{
GstByteStream *bs = g_new (GstByteStream, 1);
bs->pad = pad;
bs->data = NULL;
bs->size = 0;
bs->index = 0;
return bs;
}
void
gst_bytestream_destroy (GstByteStream * bs)
{
if (bs->data) {
g_free (bs->data);
}
g_free (bs);
}
static void
gst_bytestream_bytes_fill (GstByteStream * bs, guint64 len)
{
size_t oldlen;
GstBuffer *buf;
while ((bs->index + len) > bs->size) {
buf = gst_pad_pull (bs->pad);
oldlen = bs->size - bs->index;
memmove (bs->data, bs->data + bs->index, oldlen);
bs->size = oldlen + GST_BUFFER_SIZE (buf);
bs->index = 0;
bs->data = realloc (bs->data, bs->size);
if (!bs->data) {
fprintf (stderr, "realloc failed: d:%p s:%d\n", bs->data, bs->size);
}
memcpy (bs->data + oldlen, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
}
g_assert ((bs->index + len) <= bs->size);
}
guint8 *
gst_bytestream_bytes_peek (GstByteStream * bs, guint64 len)
{
g_return_val_if_fail (len > 0, NULL);
gst_bytestream_bytes_fill (bs, len);
return gst_bytestream_pos (bs);
}
guint8 *
gst_bytestream_bytes_read (GstByteStream * bs, guint64 len)
{
guint8 *ptr;
g_return_val_if_fail (len > 0, NULL);
gst_bytestream_bytes_fill (bs, len);
ptr = gst_bytestream_pos (bs);
bs->index += len;
return ptr;
}
gboolean
gst_bytestream_bytes_seek (GstByteStream * bs, guint64 offset)
{
return FALSE;
}
void
gst_bytestream_bytes_flush (GstByteStream * bs, guint64 len)
{
gst_bytestream_bytes_read (bs, len);
}

56
gst/utils/gstbytestream.h Normal file
View file

@ -0,0 +1,56 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
*
* gstbytestream.h: Header for various utility functions
*
* 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_BYTESTREAM_H__
#define __GST_BYTESTREAM_H__
#include <gst/gstpad.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct _GstByteStream GstByteStream;
struct _GstByteStream
{
GstPad *pad;
guint8 *data;
guint64 size;
guint64 index;
};
GstByteStream* gst_bytestream_new (GstPad *pad);
void gst_bytestream_destroy (GstByteStream *bs);
gint gst_bytestream_bytes_peek (GstByteStream *bs, guint8 **buf, guint64 len);
gint gst_bytestream_bytes_read (GstByteStream *bs, guint8 **buf, guint64 len);
gboolean gst_bytestream_bytes_seek (GstByteStream *bs, guint64 offset);
gint gst_bytestream_bytes_flush (GstByteStream *bs, guint64 len);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __GST_BYTESTREAM_H__ */

View file

@ -402,7 +402,7 @@ gst_play_set_uri (GstPlay *play, const guchar *uri)
}
if (priv->src == NULL) {
priv->src = gst_elementfactory_make ("disksrc", "srcelement");
priv->src = gst_elementfactory_make ("filesrc", "srcelement");
}
priv->uri = g_strdup (uri);

View file

@ -25,7 +25,9 @@ main (int argc, char *argv[])
}
}
#ifndef GST_DISABLE_LOADSAVE
xmlSaveFile ("gstmediaplay.gst", gst_xml_write (gst_play_get_pipeline (play->play)));
#endif
gdk_threads_enter();
gst_main();

View file

@ -1,4 +1,3 @@
SUBDIRS = riff getbits putbits idct audio bytestream control
SUBDIRS = riff getbits putbits idct audio control
DIST_SUBDIRS = riff getbits putbits audio idct control
DIST_SUBDIRS = riff getbits putbits audio idct bytestream control

View file

@ -0,0 +1,11 @@
filterdir = $(libdir)/gst
filter_LTLIBRARIES = libgstbytestream.la libgstbstest.la
libgstbytestream_la_SOURCES = gstbytestream.c
libgstbstest_la_SOURCES = gstbstest.c
libgstbytestreamincludedir = $(includedir)/gst/libs/bytestream
libgstbytestreaminclude_HEADERS = gstbytestream.h
# CFLAGS += -O2 $(FOMIT_FRAME_POINTER) -funroll-all-loops -finline-functions -ffast-math

294
libs/bytestream/gstbstest.c Normal file
View file

@ -0,0 +1,294 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
*
* gstidentity.c:
*
* 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.
*/
#include <gst/gst.h>
#include "gstbytestream.h"
#define GST_TYPE_IDENTITY \
(gst_identity_get_type())
#define GST_IDENTITY(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_IDENTITY,GstIdentity))
#define GST_IDENTITY_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_IDENTITY,GstIdentityClass))
#define GST_IS_IDENTITY(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_IDENTITY))
#define GST_IS_IDENTITY_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_IDENTITY))
typedef struct _GstIdentity GstIdentity;
typedef struct _GstIdentityClass GstIdentityClass;
struct _GstIdentity {
GstElement element;
GstPad *sinkpad;
GstPad *srcpad;
GstByteStream *bs;
gint byte_size;
gint count;
};
struct _GstIdentityClass {
GstElementClass parent_class;
};
GType gst_identity_get_type(void);
GstElementDetails gst_identity_details = {
"ByteStreamTest",
"Filter",
"Test for the GstByteStream code",
VERSION,
"Erik Walthinsen <omega@temple-baptist.com>",
"(C) 2001",
};
/* Identity signals and args */
enum {
/* FILL ME */
LAST_SIGNAL
};
enum {
ARG_0,
ARG_BYTE_SIZE,
ARG_COUNT,
};
static void gst_identity_class_init (GstIdentityClass *klass);
static void gst_identity_init (GstIdentity *identity);
static void gst_identity_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
static void gst_identity_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
static void gst_identity_loop (GstElement *element);
static GstElementClass *parent_class = NULL;
// static guint gst_identity_signals[LAST_SIGNAL] = { 0 };
GType
gst_identity_get_type (void)
{
static GType identity_type = 0;
if (!identity_type) {
static const GTypeInfo identity_info = {
sizeof(GstIdentityClass), NULL,
NULL,
(GClassInitFunc)gst_identity_class_init,
NULL,
NULL,
sizeof(GstIdentity),
0,
(GInstanceInitFunc)gst_identity_init,
};
identity_type = g_type_register_static (GST_TYPE_ELEMENT, "GstBSTest", &identity_info, 0);
}
return identity_type;
}
static void
gst_identity_class_init (GstIdentityClass *klass)
{
GObjectClass *gobject_class;
gobject_class = (GObjectClass*)klass;
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BYTE_SIZE,
g_param_spec_uint ("byte_size", "byte_size", "byte_size",
0, G_MAXUINT, 0, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_COUNT,
g_param_spec_uint ("count", "count", "count",
0, G_MAXUINT, 0, G_PARAM_READWRITE));
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_identity_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_identity_get_property);
}
static GstPadNegotiateReturn
gst_identity_negotiate_src (GstPad *pad, GstCaps **caps, gpointer *data)
{
GstIdentity *identity;
identity = GST_IDENTITY (gst_pad_get_parent (pad));
return gst_pad_negotiate_proxy (pad, identity->sinkpad, caps);
}
static GstPadNegotiateReturn
gst_identity_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer *data)
{
GstIdentity *identity;
identity = GST_IDENTITY (gst_pad_get_parent (pad));
return gst_pad_negotiate_proxy (pad, identity->srcpad, caps);
}
static void
gst_identity_init (GstIdentity *identity)
{
identity->sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
gst_element_add_pad (GST_ELEMENT (identity), identity->sinkpad);
gst_pad_set_negotiate_function (identity->sinkpad, gst_identity_negotiate_sink);
identity->srcpad = gst_pad_new ("src", GST_PAD_SRC);
gst_element_add_pad (GST_ELEMENT (identity), identity->srcpad);
gst_pad_set_negotiate_function (identity->srcpad, gst_identity_negotiate_src);
gst_element_set_loop_function (GST_ELEMENT (identity), gst_identity_loop);
identity->byte_size = 384;
identity->count = 5;
identity->bs = gst_bytestream_new(identity->sinkpad);
}
static void
gst_identity_loop (GstElement *element)
{
GstIdentity *identity;
GstBuffer *buf;
int i;
g_return_if_fail (element != NULL);
g_return_if_fail (GST_IS_IDENTITY (element));
identity = GST_IDENTITY (element);
/* THIS IS THE BUFFER BASED ONE
do {
// g_print("\n");
for (i=0;i<identity->count;i++) {
// g_print("bstest: getting a buffer of %d bytes\n",identity->byte_size);
buf = gst_bytestream_read(identity->bs,identity->byte_size);
if (!buf) g_print("BUFFER IS BOGUS\n");
// g_print("pushing the buffer, %d bytes at %d\n",GST_BUFFER_SIZE(buf),GST_BUFFER_OFFSET(buf));
gst_pad_push(identity->srcpad,buf);
// g_print("\n");
gst_bytestream_print_status(identity->bs);
// g_print("\n\n");
}
exit(1);
} while (!GST_ELEMENT_IS_COTHREAD_STOPPING(element));
*/
/* THIS IS THE BYTE BASED ONE*/
do {
for (i=0;i<identity->count;i++) {
buf = gst_buffer_new();
// note that this is dangerous, as it does *NOT* refcount the data, it can go away!!!
GST_BUFFER_DATA(buf) = gst_bytestream_peek_bytes(identity->bs,identity->byte_size);
GST_BUFFER_SIZE(buf) = identity->byte_size;
GST_BUFFER_FLAG_SET(buf,GST_BUFFER_DONTFREE);
gst_pad_push(identity->srcpad,buf);
gst_bytestream_flush(identity->bs,identity->byte_size);
}
exit(1);
} while (!GST_ELEMENT_IS_COTHREAD_STOPPING(element));
/**/
}
static void
gst_identity_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
GstIdentity *identity;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_IDENTITY (object));
identity = GST_IDENTITY (object);
switch (prop_id) {
case ARG_BYTE_SIZE:
identity->byte_size = g_value_get_uint (value);
break;
case ARG_COUNT:
identity->count = g_value_get_uint (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void gst_identity_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) {
GstIdentity *identity;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_IDENTITY (object));
identity = GST_IDENTITY (object);
switch (prop_id) {
case ARG_BYTE_SIZE:
g_value_set_uint (value, identity->byte_size);
break;
case ARG_COUNT:
g_value_set_uint (value, identity->count);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
plugin_init (GModule *module, GstPlugin *plugin)
{
GstElementFactory *factory;
// we need gstbytestream
if (!gst_library_load ("gstbytestream")) {
g_print("can't load bytestream\n");
return FALSE;
}
/* We need to create an ElementFactory for each element we provide.
* This consists of the name of the element, the GType identifier,
* and a pointer to the details structure at the top of the file.
*/
factory = gst_elementfactory_new("gstbstest", GST_TYPE_IDENTITY, &gst_identity_details);
g_return_val_if_fail(factory != NULL, FALSE);
/* The very last thing is to register the elementfactory with the plugin. */
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
return TRUE;
}
GstPluginDesc plugin_desc = {
GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"gstbstest",
plugin_init
};

View file

@ -0,0 +1,394 @@
/* GStreamer
* Copyright (C) 2001 Erik Walthinsen <omega@temple-baptist.com>
*
* gstbytestream.c: adds a convenient bytestream based API to a pad.
*
* 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.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <gst/gstinfo.h>
#include "gstbytestream.h"
//#define BS_DEBUG
#ifdef BS_DEBUG
# define bs_print(format,args...) GST_DEBUG (GST_CAT_BUFFER, format, ## args)
# define bs_status(bs) gst_bytestream_print_status(bs)
#else
# define bs_print(format,args...)
# define bs_status(bs)
#endif
guint8 *gst_bytestream_assemble (GstByteStream * bs, guint32 len);
/**
* gst_bytestream_new:
* @pad: the pad to attach the bytestream to
*
* creates a bytestream from the given pad
*
* Returns: a new #GstByteStream object
*/
GstByteStream *
gst_bytestream_new (GstPad * pad)
{
GstByteStream *bs = g_new (GstByteStream, 1);
bs->pad = pad;
bs->buflist = NULL;
bs->headbufavail = 0;
bs->listavail = 0;
bs->assembled = NULL;
return bs;
}
void
gst_bytestream_destroy (GstByteStream * bs)
{
GSList *walk;
walk = bs->buflist;
while (walk) {
gst_buffer_unref (GST_BUFFER (walk->data));
walk = g_slist_next (walk);
}
g_slist_free (bs->buflist);
if (bs->assembled)
g_free (bs->assembled);
g_free (bs);
}
// HOW THIS WORKS:
//
// The fundamental structure is a singly-linked list of buffers. The
// buffer on the front is the oldest, and thus the first to read data
// from. The number of bytes left to be read in this buffer is stored
// in bs->headbufavail. The number of bytes available in the entire
// list (including the head buffer) is in bs->listavail.
//
// When a request is made for data (peek), _fill_bytes is called with
// the number of bytes needed, but only if the listavail indicates
// that there aren't already enough. This calls _get_next_buf until
// the listavail is sufficient to satisfy the demand.
//
// _get_next_buf pulls a buffer from the pad the bytestream is attached
// to, and shoves it in the list. There are actually two things it can
// do. If there's already a buffer in the list, and the _is_span_fast()
// test returns true, it will merge it with that last buffer. Otherwise
// it will simply tack it onto the end of the list.
//
// The _peek itself first checks the simple case of the request fitting
// within the head buffer, and if so creates a subbuffer and returns.
// Otherwise, it creates a new buffer and allocates space for the request
// and calls _assemble to fill it. We know we have to copy because this
// case only happens when the _merge wasn't feasible during _get_next_buf.
//
// The _flush method repeatedly inspects the head buffer and flushes as
// much data from it as it needs to, up to the size of the buffer. If
// the flush decimates the buffer, it's stripped, unref'd, and removed.
// get the next buffer
// if the buffer can be merged with the head buffer, do so
// else add it onto the head of the
static gboolean
gst_bytestream_get_next_buf (GstByteStream * bs)
{
GstBuffer *nextbuf, *lastbuf;
GSList *end;
bs_print ("get_next_buf: pulling buffer\n");
nextbuf = gst_pad_pull (bs->pad);
bs_print ("get_next_buf: got buffer of %d bytes\n", GST_BUFFER_SIZE (nextbuf));
// first see if there are any buffers in the list at all
if (bs->buflist) {
bs_print ("gst_next_buf: there is at least one buffer in the list\n");
// now find the end of the list
end = g_slist_last (bs->buflist);
// get the buffer that's there
lastbuf = GST_BUFFER (end->data);
// see if we can marge cheaply
if (gst_buffer_is_span_fast (lastbuf, nextbuf)) {
bs_print ("get_next_buf: merging new buffer with last buf on list\n");
// it is, let's merge them (this is really an append, but...)
end->data = gst_buffer_merge (lastbuf, nextbuf);
// add to the length of the list
bs->listavail += GST_BUFFER_SIZE (nextbuf);
// have to check to see if we merged with the head buffer
if (end == bs->buflist) {
bs->headbufavail += GST_BUFFER_SIZE (nextbuf);
}
gst_buffer_unref (lastbuf);
gst_buffer_unref (nextbuf);
// if we can't, we just append this buffer
}
else {
bs_print ("get_next_buf: adding new buffer to the end of the list\n");
end = g_slist_append (end, nextbuf);
// also need to increment length of list and buffer count
bs->listavail += GST_BUFFER_SIZE (nextbuf);
}
// if there are no buffers in the list
}
else {
bs_print ("get_next_buf: buflist is empty, adding new buffer to list\n");
// put this on the end of the list
bs->buflist = g_slist_append (bs->buflist, nextbuf);
// and increment the number of bytes in the list
bs->listavail = GST_BUFFER_SIZE (nextbuf);
// set the head buffer avail to the size
bs->headbufavail = GST_BUFFER_SIZE (nextbuf);
}
return TRUE;
}
static gboolean
gst_bytestream_fill_bytes (GstByteStream * bs, guint32 len)
{
// as long as we don't have enough, we get more buffers
while (bs->listavail < len) {
bs_print ("fill_bytes: there are %d bytes in the list, we need %d\n", bs->listavail, len);
gst_bytestream_get_next_buf (bs);
}
return TRUE;
}
GstBuffer *
gst_bytestream_peek (GstByteStream * bs, guint32 len)
{
GstBuffer *headbuf, *retbuf = NULL;
g_return_val_if_fail (bs != NULL, NULL);
g_return_val_if_fail (len > 0, NULL);
bs_print ("peek: asking for %d bytes\n", len);
// make sure we have enough
bs_print ("peek: there are %d bytes in the list\n", bs->listavail);
if (len > bs->listavail) {
gst_bytestream_fill_bytes (bs, len);
bs_print ("peek: there are now %d bytes in the list\n", bs->listavail);
}
bs_status (bs);
// extract the head buffer
headbuf = GST_BUFFER (bs->buflist->data);
// if the requested bytes are in the current buffer
bs_print ("peek: headbufavail is %d\n", bs->headbufavail);
if (len <= bs->headbufavail) {
bs_print ("peek: there are enough bytes in headbuf (need %d, have %d)\n", len, bs->headbufavail);
// create a sub-buffer of the headbuf
retbuf = gst_buffer_create_sub (headbuf, GST_BUFFER_SIZE (headbuf) - bs->headbufavail, len);
// otherwise we need to figure out how to assemble one
}
else {
bs_print ("peek: current buffer is not big enough for len %d\n", len);
retbuf = gst_buffer_new ();
GST_BUFFER_SIZE (retbuf) = len;
GST_BUFFER_DATA (retbuf) = gst_bytestream_assemble (bs, len);
if (GST_BUFFER_OFFSET (headbuf) != -1)
GST_BUFFER_OFFSET (retbuf) = GST_BUFFER_OFFSET (headbuf) + (GST_BUFFER_SIZE (headbuf) - bs->headbufavail);
}
return retbuf;
}
guint8 *
gst_bytestream_peek_bytes (GstByteStream * bs, guint32 len)
{
GstBuffer *headbuf;
guint8 *data = NULL;
g_return_val_if_fail (bs != NULL, NULL);
g_return_val_if_fail (len > 0, NULL);
bs_print ("peek_bytes: asking for %d bytes\n", len);
if (bs->assembled) {
g_free (bs->assembled);
bs->assembled = NULL;
}
// make sure we have enough
bs_print ("peek_bytes: there are %d bytes in the list\n", bs->listavail);
if (len > bs->listavail) {
gst_bytestream_fill_bytes (bs, len);
bs_print ("peek_bytes: there are now %d bytes in the list\n", bs->listavail);
}
bs_status (bs);
// extract the head buffer
headbuf = GST_BUFFER (bs->buflist->data);
// if the requested bytes are in the current buffer
bs_print ("peek_bytes: headbufavail is %d\n", bs->headbufavail);
if (len <= bs->headbufavail) {
bs_print ("peek_bytes: there are enough bytes in headbuf (need %d, have %d)\n", len, bs->headbufavail);
// create a sub-buffer of the headbuf
data = GST_BUFFER_DATA (headbuf) + (GST_BUFFER_SIZE (headbuf) - bs->headbufavail);
// otherwise we need to figure out how to assemble one
}
else {
bs_print ("peek_bytes: current buffer is not big enough for len %d\n", len);
data = gst_bytestream_assemble (bs, len);
bs->assembled = data;
bs->assembled_len = len;
}
return data;
}
guint8 *
gst_bytestream_assemble (GstByteStream * bs, guint32 len)
{
guint8 *data = g_malloc (len);
GSList *walk;
guint32 copied = 0;
GstBuffer *buf;
// copy the data from the curbuf
buf = GST_BUFFER (bs->buflist->data);
bs_print ("assemble: copying %d bytes from curbuf at %d to *data\n", bs->headbufavail,
GST_BUFFER_SIZE (buf) - bs->headbufavail);
memcpy (data, GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf) - bs->headbufavail, bs->headbufavail);
copied += bs->headbufavail;
// asumption is made that the buffers all exist in the list
walk = g_slist_next (bs->buflist);
while (copied < len) {
buf = GST_BUFFER (walk->data);
if (GST_BUFFER_SIZE (buf) < (len - copied)) {
bs_print ("assemble: copying %d bytes from buf to output offset %d\n", GST_BUFFER_SIZE (buf), copied);
memcpy (data + copied, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
copied += GST_BUFFER_SIZE (buf);
}
else {
bs_print ("assemble: copying %d bytes from buf to output offset %d\n", len - copied, copied);
memcpy (data + copied, GST_BUFFER_DATA (buf), len - copied);
copied = len;
}
walk = g_slist_next (walk);
}
return data;
}
gboolean
gst_bytestream_flush (GstByteStream * bs, guint32 len)
{
GstBuffer *headbuf;
bs_print ("flush: flushing %d bytes\n", len);
if (bs->assembled) {
g_free (bs->assembled);
bs->assembled = NULL;
}
// make sure we have enough
bs_print ("flush: there are %d bytes in the list\n", bs->listavail);
if (len > bs->listavail) {
gst_bytestream_fill_bytes (bs, len);
bs_print ("flush: there are now %d bytes in the list\n", bs->listavail);
}
// repeat until we've flushed enough data
while (len > 0) {
headbuf = GST_BUFFER (bs->buflist->data);
bs_print ("flush: analyzing buffer that's %d bytes long, offset %d\n", GST_BUFFER_SIZE (headbuf),
GST_BUFFER_OFFSET (headbuf));
// if there's enough to complete the flush
if (bs->headbufavail > len) {
// just trim it off
bs_print ("flush: trimming %d bytes off end of headbuf\n", len);
bs->headbufavail -= len;
bs->listavail -= len;
len = 0;
// otherwise we have to trim the whole buffer
}
else {
bs_print ("flush: removing head buffer completely\n");
// remove it from the list
bs->buflist = g_slist_delete_link (bs->buflist, bs->buflist);
// trim it from the avail size
bs->listavail -= bs->headbufavail;
// record that we've trimmed this many bytes
len -= bs->headbufavail;
// unref it
gst_buffer_unref (headbuf);
// record the new headbufavail
if (bs->buflist) {
bs->headbufavail = GST_BUFFER_SIZE (GST_BUFFER (bs->buflist->data));
bs_print ("flush: next headbuf is %d bytes\n", bs->headbufavail);
}
else {
bs_print ("flush: no more bytes at all\n");
}
}
bs_print ("flush: bottom of while(), len is now %d\n", len);
}
return TRUE;
}
GstBuffer *
gst_bytestream_read (GstByteStream * bs, guint32 len)
{
GstBuffer *buf = gst_bytestream_peek (bs, len);
gst_bytestream_flush (bs, len);
return buf;
}
void
gst_bytestream_print_status (GstByteStream * bs)
{
GSList *walk;
GstBuffer *buf;
bs_print ("STATUS: head buffer has %d bytes available\n", bs->headbufavail);
bs_print ("STATUS: list has %d bytes available\n", bs->listavail);
walk = bs->buflist;
while (walk) {
buf = GST_BUFFER (walk->data);
walk = g_slist_next (walk);
bs_print ("STATUS: buffer starts at %d and is %d bytes long\n", GST_BUFFER_OFFSET (buf), GST_BUFFER_SIZE (buf));
}
}

View file

@ -0,0 +1,53 @@
/* GStreamer
* Copyright (C) 2001 Erik Walthinsen <omega@temple-baptist.com>
*
* 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_BYTESTREAM_H__
#define __GST_BYTESTREAM_H__
#include <gst/gstpad.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct _GstByteStream GstByteStream;
struct _GstByteStream {
GstPad *pad;
GSList *buflist;
guint32 headbufavail;
guint32 listavail;
// we keep state of assembled pieces
guint8 *assembled;
guint32 assembled_len;
};
GstByteStream* gst_bytestream_new (GstPad *pad);
void gst_bytestream_destroy (GstByteStream *bs);
GstBuffer* gst_bytestream_read (GstByteStream *bs, guint32 len);
GstBuffer* gst_bytestream_peek (GstByteStream *bs, guint32 len);
guint8* gst_bytestream_peek_bytes (GstByteStream *bs, guint32 len);
gboolean gst_bytestream_flush (GstByteStream *bs, guint32 len);
void gst_bytestream_print_status (GstByteStream *bs);
#endif /* __GST_BYTESTREAM_H__ */

View file

@ -8,6 +8,8 @@ else
GSTHTTPSRC=
endif
#CFLAGS += -O2 -Wall -finstrument-functions -DGST_ENABLE_FUNC_INSTRUMENTATION
libgstelements_la_DEPENDENCIES = ../libgst.la
libgstelements_la_SOURCES = \
gstelements.c \
@ -37,8 +39,10 @@ noinst_HEADERS = \
gstfdsink.h \
gstpipefilter.h \
gsttee.h \
gstaggregator.h
CFLAGS += -O2 -Wall
gstaggregator.h \
gstsinesrc.h
CFLAGS += -O2 -Wall
LDFLAGS += -lm
libgstelements_la_LIBADD = $(GHTTP_LIBS)

View file

@ -76,7 +76,8 @@ gst_aggregator_sched_get_type (void)
static void gst_aggregator_class_init (GstAggregatorClass *klass);
static void gst_aggregator_init (GstAggregator *aggregator);
static GstPad* gst_aggregator_request_new_pad (GstElement *element, GstPadTemplate *temp);
static GstPad* gst_aggregator_request_new_pad (GstElement *element, GstPadTemplate *temp, const
gchar *unused);
static void gst_aggregator_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec);
@ -150,7 +151,7 @@ gst_aggregator_init (GstAggregator *aggregator)
}
static GstPad*
gst_aggregator_request_new_pad (GstElement *element, GstPadTemplate *templ)
gst_aggregator_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *unused)
{
gchar *name;
GstPad *sinkpad;

View file

@ -64,8 +64,8 @@ static void gst_disksrc_set_property (GObject *object, guint prop_id,
static void gst_disksrc_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec);
static GstBuffer * gst_disksrc_get (GstPad *pad);
static GstBuffer * gst_disksrc_get_region (GstPad *pad,GstRegionType type,guint64 offset,guint64 len);
static GstBuffer* gst_disksrc_get (GstPad *pad);
static GstBufferPool* gst_disksrc_get_bufferpool (GstPad *pad);
static GstElementStateReturn
gst_disksrc_change_state (GstElement *element);
@ -73,7 +73,7 @@ static GstElementStateReturn
static gboolean gst_disksrc_open_file (GstDiskSrc *src);
static void gst_disksrc_close_file (GstDiskSrc *src);
static GstElementClass *parent_class = NULL;
static GstElementClass* parent_class = NULL;
//static guint gst_disksrc_signals[LAST_SIGNAL] = { 0 };
GType
@ -133,8 +133,8 @@ gst_disksrc_init (GstDiskSrc *disksrc)
// GST_FLAG_SET (disksrc, GST_SRC_);
disksrc->srcpad = gst_pad_new ("src", GST_PAD_SRC);
gst_pad_set_get_function (disksrc->srcpad,gst_disksrc_get);
gst_pad_set_getregion_function (disksrc->srcpad,gst_disksrc_get_region);
gst_pad_set_get_function (disksrc->srcpad, gst_disksrc_get);
gst_pad_set_bufferpool_function (disksrc->srcpad, gst_disksrc_get_bufferpool);
gst_element_add_pad (GST_ELEMENT (disksrc), disksrc->srcpad);
disksrc->filename = NULL;
@ -220,6 +220,56 @@ gst_disksrc_get_property (GObject *object, guint prop_id, GValue *value, GParamS
}
}
static GstBuffer*
gst_disksrc_buffer_new (GstBufferPool *pool, gint64 location, gint size, gpointer user_data)
{
GstDiskSrc *src;
GstBuffer *buf;
src = GST_DISKSRC (user_data);
buf = gst_buffer_new ();
g_return_val_if_fail (buf != NULL, NULL);
/* simply set the buffer to point to the correct region of the file */
GST_BUFFER_DATA (buf) = src->map + location;
GST_BUFFER_OFFSET (buf) = location;
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_DONTFREE);
if ((location + size) > src->size)
GST_BUFFER_SIZE (buf) = src->size - location;
else
GST_BUFFER_SIZE (buf) = size;
GST_DEBUG (0,"map %p, offset %ld (%p), size %d\n", src->map, src->curoffset,
src->map + src->curoffset, GST_BUFFER_SIZE (buf));
return buf;
}
static void
gst_disksrc_buffer_free (GstBuffer *buf)
{
// FIXME do something here
}
static GstBufferPool*
gst_disksrc_get_bufferpool (GstPad *pad)
{
GstDiskSrc *src;
src = GST_DISKSRC (gst_pad_get_parent (pad));
if (!src->bufferpool) {
src->bufferpool = gst_buffer_pool_new ();
gst_buffer_pool_set_buffer_new_function (src->bufferpool, gst_disksrc_buffer_new);
gst_buffer_pool_set_buffer_free_function (src->bufferpool, gst_disksrc_buffer_free);
gst_buffer_pool_set_user_data (src->bufferpool, src);
}
return src->bufferpool;
}
/**
* gst_disksrc_get:
* @pad: #GstPad to push a buffer from
@ -246,28 +296,10 @@ gst_disksrc_get (GstPad *pad)
return buf;
}
/* create the buffer */
// FIXME: should eventually use a bufferpool for this
buf = gst_buffer_new ();
g_return_val_if_fail (buf != NULL, NULL);
/* simply set the buffer to point to the correct region of the file */
GST_BUFFER_DATA (buf) = src->map + src->curoffset;
GST_BUFFER_OFFSET (buf) = src->curoffset;
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_DONTFREE);
if ((src->curoffset + src->bytes_per_read) > src->size) {
GST_BUFFER_SIZE (buf) = src->size - src->curoffset;
// FIXME: set the buffer's EOF bit here
} else
GST_BUFFER_SIZE (buf) = src->bytes_per_read;
GST_DEBUG (0,"map %p, offset %ld (%p), size %d\n", src->map, src->curoffset,
src->map + src->curoffset, GST_BUFFER_SIZE (buf));
// FIXME use a bufferpool
buf = gst_disksrc_buffer_new (NULL, src->curoffset, src->bytes_per_read, src);
//gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
src->curoffset += GST_BUFFER_SIZE (buf);
if (src->new_seek) {
@ -280,61 +312,6 @@ gst_disksrc_get (GstPad *pad)
return buf;
}
/**
* gst_disksrc_get_region:
* @src: #GstSrc to push a buffer from
* @offset: offset in file
* @size: number of bytes
*
* Push a new buffer from the disksrc of given size at given offset.
*/
static GstBuffer *
gst_disksrc_get_region (GstPad *pad, GstRegionType type,guint64 offset,guint64 len)
{
GstDiskSrc *src;
GstBuffer *buf;
g_return_val_if_fail (pad != NULL, NULL);
g_return_val_if_fail (type == GST_REGION_OFFSET_LEN, NULL);
src = GST_DISKSRC (gst_pad_get_parent (pad));
g_return_val_if_fail (GST_IS_DISKSRC (src), NULL);
g_return_val_if_fail (GST_FLAG_IS_SET (src, GST_DISKSRC_OPEN), NULL);
/* deal with EOF state */
if (offset >= src->size) {
gst_pad_event (pad, GST_EVENT_EOS, 0LL, 0);
GST_DEBUG (0,"map offset %lld >= size %ld --> eos\n", offset, src->size);
//FIXME
buf = gst_buffer_new();
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_EOS);
return buf;
}
/* create the buffer */
// FIXME: should eventually use a bufferpool for this
buf = gst_buffer_new ();
g_return_val_if_fail (buf != NULL, NULL);
/* simply set the buffer to point to the correct region of the file */
GST_BUFFER_DATA (buf) = src->map + offset;
GST_BUFFER_OFFSET (buf) = offset;
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_DONTFREE);
if ((offset + len) > src->size) {
GST_BUFFER_SIZE (buf) = src->size - offset;
// FIXME: set the buffer's EOF bit here
} else
GST_BUFFER_SIZE (buf) = len;
GST_DEBUG (0,"map %p, offset %lld, size %d\n", src->map, offset, GST_BUFFER_SIZE (buf));
/* we're done, return the buffer off now */
return buf;
}
/* open the file and mmap it, necessary to go to READY state */
static gboolean
gst_disksrc_open_file (GstDiskSrc *src)

View file

@ -64,6 +64,7 @@ struct _GstDiskSrc {
gchar *filename;
/* fd */
gint fd;
GstBufferPool *bufferpool;
/* mapping parameters */
gulong size; /* how long is the file? */

View file

@ -45,6 +45,7 @@ enum {
ARG_0,
ARG_NUM_SINKS,
ARG_SILENT,
ARG_DUMP,
};
GST_PADTEMPLATE_FACTORY (fakesink_sink_factory,
@ -58,7 +59,8 @@ GST_PADTEMPLATE_FACTORY (fakesink_sink_factory,
static void gst_fakesink_class_init (GstFakeSinkClass *klass);
static void gst_fakesink_init (GstFakeSink *fakesink);
static GstPad* gst_fakesink_request_new_pad (GstElement *element, GstPadTemplate *templ);
static GstPad* gst_fakesink_request_new_pad (GstElement *element, GstPadTemplate *templ, const
gchar *unused);
static void gst_fakesink_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec);
@ -66,7 +68,6 @@ static void gst_fakesink_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec);
static void gst_fakesink_chain (GstPad *pad, GstBuffer *buf);
static gboolean gst_fakesink_event (GstPad *pad, GstEventType event, guint64 timestamp, guint32 data);
static GstElementClass *parent_class = NULL;
static guint gst_fakesink_signals[LAST_SIGNAL] = { 0 };
@ -109,6 +110,9 @@ gst_fakesink_class_init (GstFakeSinkClass *klass)
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
g_param_spec_boolean ("silent", "silent", "silent",
FALSE, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DUMP,
g_param_spec_boolean ("dump", "dump", "dump",
FALSE, G_PARAM_READWRITE));
gst_fakesink_signals[SIGNAL_HANDOFF] =
g_signal_new ("handoff", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
@ -129,15 +133,15 @@ gst_fakesink_init (GstFakeSink *fakesink)
pad = gst_pad_new ("sink", GST_PAD_SINK);
gst_element_add_pad (GST_ELEMENT (fakesink), pad);
gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_fakesink_chain));
gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_fakesink_event));
fakesink->sinkpads = g_slist_prepend (NULL, pad);
fakesink->numsinkpads = 1;
fakesink->silent = FALSE;
fakesink->dump = FALSE;
}
static GstPad*
gst_fakesink_request_new_pad (GstElement *element, GstPadTemplate *templ)
gst_fakesink_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *unused)
{
gchar *name;
GstPad *sinkpad;
@ -175,6 +179,9 @@ gst_fakesink_set_property (GObject *object, guint prop_id, const GValue *value,
case ARG_SILENT:
sink->silent = g_value_get_boolean (value);
break;
case ARG_DUMP:
sink->dump = g_value_get_boolean (value);
break;
default:
break;
}
@ -197,6 +204,9 @@ gst_fakesink_get_property (GObject *object, guint prop_id, GValue *value, GParam
case ARG_SILENT:
g_value_set_boolean (value, sink->silent);
break;
case ARG_DUMP:
g_value_set_boolean (value, sink->dump);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -206,9 +216,9 @@ gst_fakesink_get_property (GObject *object, guint prop_id, GValue *value, GParam
/**
* gst_fakesink_chain:
* @pad: the pad this faksink is connected to
* @buf: the buffer that has to be absorbed
* @buffer: the buffer or event that has to be absorbed
*
* take the buffer from the pad and unref it without doing
* Take the buffer or event from the pad and unref it without doing
* anything with it.
*/
static void
@ -221,12 +231,33 @@ gst_fakesink_chain (GstPad *pad, GstBuffer *buf)
g_return_if_fail (buf != NULL);
fakesink = GST_FAKESINK (gst_pad_get_parent (pad));
if (GST_IS_EVENT(buf)) {
GstEvent *event = GST_EVENT (buf);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_EOS:
g_print("fakesink: have EOS event!\n");
gst_element_set_state (GST_ELEMENT (fakesink), GST_STATE_PAUSED);
break;
default:
g_print("fakesink: have unhandled event!\n");
break;
}
gst_event_free (event);
return;
}
if (!fakesink->silent)
g_print("fakesink: chain ******* (%s:%s)< (%d bytes, %lld) \n",
GST_DEBUG_PAD_NAME (pad), GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf));
g_signal_emit (G_OBJECT (fakesink), gst_fakesink_signals[SIGNAL_HANDOFF], 0,
buf);
g_print("fakesink: chain ******* (%s:%s)< (%d bytes, %lld) %p\n",
GST_DEBUG_PAD_NAME (pad), GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf), buf);
g_signal_emit (G_OBJECT (fakesink), gst_fakesink_signals[SIGNAL_HANDOFF], 0, buf, pad);
if (fakesink->dump)
{
gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
}
gst_buffer_unref (buf);
}
@ -238,14 +269,3 @@ gst_fakesink_factory_init (GstElementFactory *factory)
return TRUE;
}
static gboolean
gst_fakesink_event (GstPad *pad, GstEventType event, guint64 timestamp, guint32 data)
{
GST_DEBUG (GST_CAT_EVENT, "fakesink has event %d on pad %s:%s\n",event,GST_DEBUG_PAD_NAME(pad));
if (event == GST_EVENT_EOS) {
GST_DEBUG(GST_CAT_EVENT, "have EOS\n");
}
}

View file

@ -57,6 +57,7 @@ struct _GstFakeSink {
GSList *sinkpads;
gint numsinkpads;
gboolean silent;
gboolean dump;
};
struct _GstFakeSinkClass {

View file

@ -21,6 +21,9 @@
*/
#include <stdlib.h>
#include <string.h>
#include <gstfakesrc.h>
@ -47,10 +50,17 @@ enum {
ARG_NUM_SOURCES,
ARG_LOOP_BASED,
ARG_OUTPUT,
ARG_DATA,
ARG_SIZETYPE,
ARG_SIZEMIN,
ARG_SIZEMAX,
ARG_FILLTYPE,
ARG_PATTERN,
ARG_NUM_BUFFERS,
ARG_EOS,
ARG_SILENT
ARG_SILENT,
ARG_DUMP,
ARG_PARENTSIZE
};
GST_PADTEMPLATE_FACTORY (fakesrc_src_factory,
@ -82,12 +92,69 @@ gst_fakesrc_output_get_type (void)
return fakesrc_output_type;
}
#define GST_TYPE_FAKESRC_DATA (gst_fakesrc_data_get_type())
static GType
gst_fakesrc_data_get_type (void)
{
static GType fakesrc_data_type = 0;
static GEnumValue fakesrc_data[] = {
{ FAKESRC_DATA_ALLOCATE, "2", "Allocate data"},
{ FAKESRC_DATA_SUBBUFFER, "3", "Subbuffer data"},
{0, NULL, NULL},
};
if (!fakesrc_data_type) {
fakesrc_data_type = g_enum_register_static ("GstFakeSrcData", fakesrc_data);
}
return fakesrc_data_type;
}
#define GST_TYPE_FAKESRC_SIZETYPE (gst_fakesrc_sizetype_get_type())
static GType
gst_fakesrc_sizetype_get_type (void)
{
static GType fakesrc_sizetype_type = 0;
static GEnumValue fakesrc_sizetype[] = {
{ FAKESRC_SIZETYPE_NULL, "1", "Send empty buffers"},
{ FAKESRC_SIZETYPE_FIXED, "2", "Fixed size buffers (sizemax sized)"},
{ FAKESRC_SIZETYPE_RANDOM, "3", "Random sized buffers (sizemin <= size <= sizemax)"},
{0, NULL, NULL},
};
if (!fakesrc_sizetype_type) {
fakesrc_sizetype_type = g_enum_register_static ("GstFakeSrcSizeType", fakesrc_sizetype);
}
return fakesrc_sizetype_type;
}
#define GST_TYPE_FAKESRC_FILLTYPE (gst_fakesrc_filltype_get_type())
static GType
gst_fakesrc_filltype_get_type (void)
{
static GType fakesrc_filltype_type = 0;
static GEnumValue fakesrc_filltype[] = {
{ FAKESRC_FILLTYPE_NOTHING, "1", "Leave data as malloced"},
{ FAKESRC_FILLTYPE_NULL, "2", "Fill buffers with zeros"},
{ FAKESRC_FILLTYPE_RANDOM, "3", "Fill buffers with random crap"},
{ FAKESRC_FILLTYPE_PATTERN, "4", "Fill buffers with pattern 0x00 -> 0xff"},
{ FAKESRC_FILLTYPE_PATTERN_CONT, "5", "Fill buffers with pattern 0x00 -> 0xff that spans buffers"},
{0, NULL, NULL},
};
if (!fakesrc_filltype_type) {
fakesrc_filltype_type = g_enum_register_static ("GstFakeSrcFillType", fakesrc_filltype);
}
return fakesrc_filltype_type;
}
static void gst_fakesrc_class_init (GstFakeSrcClass *klass);
static void gst_fakesrc_init (GstFakeSrc *fakesrc);
static GstPad* gst_fakesrc_request_new_pad (GstElement *element, GstPadTemplate *templ);
static void gst_fakesrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
static void gst_fakesrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
static void gst_fakesrc_update_functions (GstFakeSrc *src);
static void gst_fakesrc_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec);
static void gst_fakesrc_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec);
static GstElementStateReturn gst_fakesrc_change_state (GstElement *element);
static GstBuffer* gst_fakesrc_get (GstPad *pad);
static void gst_fakesrc_loop (GstElement *element);
@ -137,6 +204,24 @@ gst_fakesrc_class_init (GstFakeSrcClass *klass)
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_OUTPUT,
g_param_spec_enum("output","output","output",
GST_TYPE_FAKESRC_OUTPUT,FAKESRC_FIRST_LAST_LOOP,G_PARAM_READWRITE)); // CHECKME!
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DATA,
g_param_spec_enum ("data", "data", "data",
GST_TYPE_FAKESRC_DATA, FAKESRC_DATA_ALLOCATE, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIZETYPE,
g_param_spec_enum ("sizetype", "sizetype", "sizetype",
GST_TYPE_FAKESRC_SIZETYPE, FAKESRC_SIZETYPE_NULL, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIZEMIN,
g_param_spec_int ("sizemin","sizemin","sizemin",
0, G_MAXINT, 0, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIZEMAX,
g_param_spec_int ("sizemax","sizemax","sizemax",
0, G_MAXINT, 4096, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PARENTSIZE,
g_param_spec_int ("parentsize","parentsize","parentsize",
0, G_MAXINT, 4096 * 10, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FILLTYPE,
g_param_spec_enum ("filltype", "filltype", "filltype",
GST_TYPE_FAKESRC_FILLTYPE, FAKESRC_FILLTYPE_NULL, G_PARAM_READWRITE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_PATTERN,
g_param_spec_string("pattern","pattern","pattern",
NULL, G_PARAM_READWRITE)); // CHECKME
@ -149,6 +234,9 @@ gst_fakesrc_class_init (GstFakeSrcClass *klass)
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SILENT,
g_param_spec_boolean("silent","silent","silent",
FALSE, G_PARAM_READWRITE)); // CHECKME
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DUMP,
g_param_spec_boolean ("dump","dump","dump",
FALSE, G_PARAM_READWRITE));
gst_fakesrc_signals[SIGNAL_HANDOFF] =
g_signal_new ("handoff", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
@ -159,7 +247,8 @@ gst_fakesrc_class_init (GstFakeSrcClass *klass)
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesrc_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesrc_get_property);
gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR (gst_fakesrc_request_new_pad);
gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR (gst_fakesrc_request_new_pad);
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_fakesrc_change_state);
}
static void
@ -176,17 +265,21 @@ gst_fakesrc_init (GstFakeSrc *fakesrc)
fakesrc->srcpads = g_slist_append (NULL, pad);
fakesrc->loop_based = FALSE;
if (fakesrc->loop_based)
gst_element_set_loop_function (GST_ELEMENT (fakesrc), GST_DEBUG_FUNCPTR (gst_fakesrc_loop));
else
gst_pad_set_get_function (pad, GST_DEBUG_FUNCPTR (gst_fakesrc_get));
gst_fakesrc_update_functions (fakesrc);
fakesrc->num_buffers = -1;
fakesrc->buffer_count = 0;
fakesrc->silent = FALSE;
// we're ready right away, since we don't have any args...
// gst_element_set_state(GST_ELEMENT(fakesrc),GST_STATE_READY);
fakesrc->dump = FALSE;
fakesrc->pattern_byte = 0x00;
fakesrc->need_flush = FALSE;
fakesrc->data = FAKESRC_DATA_ALLOCATE;
fakesrc->sizetype = FAKESRC_SIZETYPE_NULL;
fakesrc->filltype = FAKESRC_FILLTYPE_NOTHING;
fakesrc->sizemin = 0;
fakesrc->sizemax = 4096;
fakesrc->parent = NULL;
fakesrc->parentsize = 4096 * 10;
}
static GstPad*
@ -216,6 +309,34 @@ gst_fakesrc_request_new_pad (GstElement *element, GstPadTemplate *templ)
return srcpad;
}
static gboolean
gst_fakesrc_event_handler (GstPad *pad, GstEvent *event)
{
GstFakeSrc *src;
src = GST_FAKESRC (gst_pad_get_parent (pad));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK:
g_print("fakesrc: have seek event\n");
src->buffer_count = GST_EVENT_SEEK_OFFSET (event);
if (!GST_EVENT_SEEK_FLUSH (event)) {
gst_event_free (event);
break;
}
// else we do a flush too
case GST_EVENT_FLUSH:
g_print("fakesrc: have flush event\n");
src->need_flush = TRUE;
break;
default:
g_print("fakesrc: have unhandled event\n");
break;
}
return TRUE;
}
static void
gst_fakesrc_update_functions (GstFakeSrc *src)
{
@ -238,10 +359,25 @@ gst_fakesrc_update_functions (GstFakeSrc *src)
else {
gst_pad_set_get_function (pad, GST_DEBUG_FUNCPTR (gst_fakesrc_get));
}
gst_pad_set_event_function (pad, gst_fakesrc_event_handler);
pads = g_slist_next (pads);
}
}
static void
gst_fakesrc_alloc_parent (GstFakeSrc *src)
{
GstBuffer *buf;
buf = gst_buffer_new ();
GST_BUFFER_DATA (buf) = g_malloc (src->parentsize);
GST_BUFFER_SIZE (buf) = src->parentsize;
src->parent = buf;
src->parentoffset = 0;
}
static void
gst_fakesrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
@ -257,6 +393,37 @@ gst_fakesrc_set_property (GObject *object, guint prop_id, const GValue *value, G
break;
case ARG_OUTPUT:
break;
case ARG_DATA:
src->data = g_value_get_int (value);
switch (src->data) {
case FAKESRC_DATA_ALLOCATE:
if (src->parent) {
gst_buffer_unref (src->parent);
src->parent = NULL;
}
break;
case FAKESRC_DATA_SUBBUFFER:
if (!src->parent)
gst_fakesrc_alloc_parent (src);
default:
break;
}
break;
case ARG_SIZETYPE:
src->sizetype = g_value_get_int (value);
break;
case ARG_SIZEMIN:
src->sizemin = g_value_get_int (value);
break;
case ARG_SIZEMAX:
src->sizemax = g_value_get_int (value);
break;
case ARG_PARENTSIZE:
src->parentsize = g_value_get_int (value);
break;
case ARG_FILLTYPE:
src->filltype = g_value_get_int (value);
break;
case ARG_PATTERN:
break;
case ARG_NUM_BUFFERS:
@ -269,6 +436,9 @@ GST_INFO (0, "will EOS on next buffer");
case ARG_SILENT:
src->silent = g_value_get_boolean (value);
break;
case ARG_DUMP:
src->dump = g_value_get_boolean (value);
break;
default:
break;
}
@ -294,6 +464,24 @@ gst_fakesrc_get_property (GObject *object, guint prop_id, GValue *value, GParamS
case ARG_OUTPUT:
g_value_set_int (value, src->output);
break;
case ARG_DATA:
g_value_set_int (value, src->data);
break;
case ARG_SIZETYPE:
g_value_set_int (value, src->sizetype);
break;
case ARG_SIZEMIN:
g_value_set_int (value, src->sizemin);
break;
case ARG_SIZEMAX:
g_value_set_int (value, src->sizemax);
break;
case ARG_PARENTSIZE:
g_value_set_int (value, src->parentsize);
break;
case ARG_FILLTYPE:
g_value_set_int (value, src->filltype);
break;
case ARG_PATTERN:
g_value_set_string (value, src->pattern);
break;
@ -306,21 +494,150 @@ gst_fakesrc_get_property (GObject *object, guint prop_id, GValue *value, GParamS
case ARG_SILENT:
g_value_set_boolean (value, src->silent);
break;
case ARG_DUMP:
g_value_set_boolean (value, src->dump);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_fakesrc_prepare_buffer (GstFakeSrc *src, GstBuffer *buf)
{
if (GST_BUFFER_SIZE (buf) == 0)
return;
switch (src->filltype) {
case FAKESRC_FILLTYPE_NULL:
memset (GST_BUFFER_DATA (buf), 0, GST_BUFFER_SIZE (buf));
break;
case FAKESRC_FILLTYPE_RANDOM:
{
gint i;
guint8 *ptr = GST_BUFFER_DATA (buf);
for (i = GST_BUFFER_SIZE (buf); i; i--) {
*ptr++ = (gint8)((255.0)*rand()/(RAND_MAX));
}
break;
}
case FAKESRC_FILLTYPE_PATTERN:
src->pattern_byte = 0x00;
case FAKESRC_FILLTYPE_PATTERN_CONT:
{
gint i;
guint8 *ptr = GST_BUFFER_DATA (buf);
for (i = GST_BUFFER_SIZE (buf); i; i--) {
*ptr++ = src->pattern_byte++;
}
break;
}
case FAKESRC_FILLTYPE_NOTHING:
default:
break;
}
}
static GstBuffer*
gst_fakesrc_alloc_buffer (GstFakeSrc *src, guint size)
{
GstBuffer *buf;
buf = gst_buffer_new ();
GST_BUFFER_SIZE(buf) = size;
if (size != 0) {
switch (src->filltype) {
case FAKESRC_FILLTYPE_NOTHING:
GST_BUFFER_DATA(buf) = g_malloc (size);
break;
case FAKESRC_FILLTYPE_NULL:
GST_BUFFER_DATA(buf) = g_malloc0 (size);
break;
case FAKESRC_FILLTYPE_RANDOM:
case FAKESRC_FILLTYPE_PATTERN:
case FAKESRC_FILLTYPE_PATTERN_CONT:
default:
GST_BUFFER_DATA(buf) = g_malloc (size);
gst_fakesrc_prepare_buffer (src, buf);
break;
}
}
return buf;
}
static guint
gst_fakesrc_get_size (GstFakeSrc *src)
{
guint size;
switch (src->sizetype) {
case FAKESRC_SIZETYPE_FIXED:
size = src->sizemax;
break;
case FAKESRC_SIZETYPE_RANDOM:
size = src->sizemin + (guint8)(((gfloat)src->sizemax)*rand()/(RAND_MAX + (gfloat)src->sizemin));
break;
case FAKESRC_SIZETYPE_NULL:
default:
size = 0;
break;
}
return size;
}
static GstBuffer *
gst_fakesrc_create_buffer (GstFakeSrc *src)
{
GstBuffer *buf;
guint size;
gboolean dump = src->dump;
size = gst_fakesrc_get_size (src);
if (size == 0)
return gst_buffer_new();
switch (src->data) {
case FAKESRC_DATA_ALLOCATE:
buf = gst_fakesrc_alloc_buffer (src, size);
break;
case FAKESRC_DATA_SUBBUFFER:
// see if we have a parent to subbuffer
if (!src->parent) {
gst_fakesrc_alloc_parent (src);
g_assert (src->parent);
}
// see if it's large enough
if ((GST_BUFFER_SIZE (src->parent) - src->parentoffset) >= size) {
buf = gst_buffer_create_sub (src->parent, src->parentoffset, size);
src->parentoffset += size;
}
else {
// the parent is useless now
gst_buffer_unref (src->parent);
src->parent = NULL;
// try again (this will allocate a new parent)
return gst_fakesrc_create_buffer (src);
}
gst_fakesrc_prepare_buffer (src, buf);
break;
default:
g_warning ("fakesrc: dunno how to allocate buffers !");
buf = gst_buffer_new();
break;
}
if (dump) {
gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
}
return buf;
}
/**
* gst_fakesrc_get:
* @src: the faksesrc to get
*
* generate an empty buffer and return it
*
* Returns: a new empty buffer
*/
static GstBuffer *
gst_fakesrc_get(GstPad *pad)
{
@ -333,9 +650,16 @@ gst_fakesrc_get(GstPad *pad)
g_return_val_if_fail (GST_IS_FAKESRC (src), NULL);
if (src->need_flush) {
src->need_flush = FALSE;
g_print("fakesrc: sending FLUSH\n");
return GST_BUFFER(gst_event_new (GST_EVENT_FLUSH));
}
if (src->num_buffers == 0) {
gst_pad_event (pad, GST_EVENT_EOS, 0LL, 0);
return NULL;
g_print("fakesrc: sending EOS\n");
gst_element_set_state (GST_ELEMENT (src), GST_STATE_PAUSED);
return GST_BUFFER(gst_event_new (GST_EVENT_EOS));
}
else {
if (src->num_buffers > 0)
@ -344,11 +668,11 @@ gst_fakesrc_get(GstPad *pad)
if (src->eos) {
GST_INFO (0, "fakesrc is setting eos on pad");
gst_pad_event (pad, GST_EVENT_EOS, 0LL, 0);
return NULL;
g_print("fakesrc: sending EOS\n");
return GST_BUFFER(gst_event_new (GST_EVENT_EOS));
}
buf = gst_buffer_new();
buf = gst_fakesrc_create_buffer (src);
GST_BUFFER_TIMESTAMP (buf) = src->buffer_count++;
if (!src->silent)
@ -356,7 +680,7 @@ gst_fakesrc_get(GstPad *pad)
GST_DEBUG_PAD_NAME (pad), GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf));
g_signal_emit (G_OBJECT (src), gst_fakesrc_signals[SIGNAL_HANDOFF], 0,
buf);
buf, pad);
return buf;
}
@ -387,21 +711,20 @@ gst_fakesrc_loop(GstElement *element)
GstBuffer *buf;
if (src->num_buffers == 0) {
gst_pad_event (pad, GST_EVENT_EOS, 0LL, 0);
return;
src->eos = TRUE;
}
else {
if (src->num_buffers > 0)
src->num_buffers--;
if (src->num_buffers > 0)
src->num_buffers--;
}
if (src->eos) {
GST_INFO (0, "fakesrc is setting eos on pad");
gst_pad_event (pad, GST_EVENT_EOS, 0LL, 0);
return;
gst_pad_push(pad, GST_BUFFER(gst_event_new (GST_EVENT_EOS)));
return;
}
buf = gst_buffer_new();
buf = gst_fakesrc_create_buffer (src);
GST_BUFFER_TIMESTAMP (buf) = src->buffer_count++;
if (!src->silent)
@ -409,7 +732,7 @@ gst_fakesrc_loop(GstElement *element)
GST_DEBUG_PAD_NAME (pad), GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf));
g_signal_emit (G_OBJECT (src), gst_fakesrc_signals[SIGNAL_HANDOFF], 0,
buf);
buf, pad);
gst_pad_push (pad, buf);
pads = g_slist_next (pads);
@ -417,6 +740,31 @@ gst_fakesrc_loop(GstElement *element)
} while (!GST_ELEMENT_IS_COTHREAD_STOPPING (element));
}
static GstElementStateReturn
gst_fakesrc_change_state (GstElement *element)
{
GstFakeSrc *fakesrc;
g_return_val_if_fail (GST_IS_FAKESRC (element), GST_STATE_FAILURE);
fakesrc = GST_FAKESRC (element);
if (GST_STATE_PENDING (element) == GST_STATE_READY) {
fakesrc->buffer_count = 0;
fakesrc->pattern_byte = 0x00;
fakesrc->need_flush = FALSE;
if (fakesrc->parent) {
gst_buffer_unref (fakesrc->parent);
fakesrc->parent = NULL;
}
}
if (GST_ELEMENT_CLASS (parent_class)->change_state)
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
return GST_STATE_SUCCESS;
}
gboolean
gst_fakesrc_factory_init (GstElementFactory *factory)
{

View file

@ -47,6 +47,25 @@ typedef enum {
FAKESRC_GET_ALWAYS_SUCEEDS,
} GstFakeSrcOutputType;
typedef enum {
FAKESRC_DATA_ALLOCATE = 1,
FAKESRC_DATA_SUBBUFFER,
} GstFakeSrcDataType;
typedef enum {
FAKESRC_SIZETYPE_NULL = 1,
FAKESRC_SIZETYPE_FIXED,
FAKESRC_SIZETYPE_RANDOM
} GstFakeSrcSizeType;
typedef enum {
FAKESRC_FILLTYPE_NOTHING = 1,
FAKESRC_FILLTYPE_NULL,
FAKESRC_FILLTYPE_RANDOM,
FAKESRC_FILLTYPE_PATTERN,
FAKESRC_FILLTYPE_PATTERN_CONT
} GstFakeSrcFillType;
#define GST_TYPE_FAKESRC \
(gst_fakesrc_get_type())
#define GST_FAKESRC(obj) \
@ -64,16 +83,29 @@ typedef struct _GstFakeSrcClass GstFakeSrcClass;
struct _GstFakeSrc {
GstElement element;
gboolean loop_based;
gboolean eos;
gint numsrcpads;
GSList *srcpads;
gboolean loop_based;
gboolean eos;
gint numsrcpads;
GSList *srcpads;
GstFakeSrcOutputType output;
gchar *pattern;
GList *patternlist;
gint num_buffers;
guint64 buffer_count;
gboolean silent;
GstFakeSrcDataType data;
GstFakeSrcSizeType sizetype;
GstFakeSrcFillType filltype;
guint sizemin;
guint sizemax;
GstBuffer *parent;
guint parentsize;
guint parentoffset;
guint8 pattern_byte;
gchar *pattern;
GList *patternlist;
gint num_buffers;
guint64 buffer_count;
gboolean silent;
gboolean dump;
gboolean need_flush;
};
struct _GstFakeSrcClass {

View file

@ -27,6 +27,7 @@
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
/**********************************************************************
@ -74,6 +75,9 @@ GstElementDetails gst_filesrc_details = {
"(C) 1999",
};
//#define fs_print(format,args...) g_print(format, ## args)
#define fs_print(format,args...)
#define GST_TYPE_FILESRC \
(gst_filesrc_get_type())
@ -110,10 +114,12 @@ struct _GstFileSrc {
gboolean touch; // whether to touch every page
GstBuffer *mapbuf;
off_t mapsize;
size_t mapsize;
GTree *map_regions;
GMutex *map_regions_lock;
gboolean seek_happened;
};
struct _GstFileSrcClass {
@ -135,6 +141,7 @@ enum {
ARG_BLOCKSIZE,
ARG_OFFSET,
ARG_MAPSIZE,
ARG_TOUCH,
};
@ -203,6 +210,9 @@ gst_filesrc_class_init (GstFileSrcClass *klass)
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MAPSIZE,
g_param_spec_ulong("mmapsize","mmap() Block Size","Size in bytes of mmap()d regions",
0,G_MAXULONG,4*1048576,G_PARAM_READWRITE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_TOUCH,
g_param_spec_boolean("touch","Touch read data","Touch data to force disk read before push()",
TRUE,G_PARAM_READWRITE));
gobject_class->set_property = gst_filesrc_set_property;
gobject_class->get_property = gst_filesrc_get_property;
@ -246,6 +256,8 @@ gst_filesrc_init (GstFileSrc *src)
src->map_regions = g_tree_new(gst_filesrc_bufcmp);
src->map_regions_lock = g_mutex_new();
src->seek_happened = FALSE;
}
@ -286,6 +298,9 @@ gst_filesrc_set_property (GObject *object, guint prop_id, const GValue *value, G
else
GST_INFO(0, "invalid mapsize, must a multiple of pagesize, which is %d\n",src->pagesize);
break;
case ARG_TOUCH:
src->touch = g_value_get_boolean (value);
break;
default:
break;
}
@ -320,6 +335,9 @@ gst_filesrc_get_property (GObject *object, guint prop_id, GValue *value, GParamS
case ARG_MAPSIZE:
g_value_set_ulong (value, src->mapsize);
break;
case ARG_TOUCH:
g_value_set_boolean (value, src->touch);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -331,7 +349,7 @@ gst_filesrc_free_parent_mmap (GstBuffer *buf)
{
GstFileSrc *src = GST_FILESRC(GST_BUFFER_POOL_PRIVATE(buf));
// fprintf(stderr,"freeing mmap()d buffer at %d+%d\n",GST_BUFFER_OFFSET(buf),GST_BUFFER_SIZE(buf));
fs_print ("freeing mmap()d buffer at %d+%d\n",GST_BUFFER_OFFSET(buf),GST_BUFFER_SIZE(buf));
// remove the buffer from the list of available mmap'd regions
g_mutex_lock(src->map_regions_lock);
@ -347,21 +365,24 @@ gst_filesrc_free_parent_mmap (GstBuffer *buf)
}
static GstBuffer *
gst_filesrc_map_region (GstFileSrc *src, off_t offset, off_t size)
gst_filesrc_map_region (GstFileSrc *src, off_t offset, size_t size)
{
GstBuffer *buf;
gint retval;
// fprintf(stderr,"mapping region %d+%d from file into memory\n",offset,size);
g_return_val_if_fail (offset >= 0, NULL);
fs_print ("mapping region %08lx+%08lx from file into memory\n",offset,size);
// time to allocate a new mapbuf
buf = gst_buffer_new();
// mmap() the data into this new buffer
GST_BUFFER_DATA(buf) = mmap (NULL, size, PROT_READ, MAP_SHARED, src->fd, offset);
if (GST_BUFFER_DATA(buf) == NULL) {
fprintf(stderr, "ERROR: gstfilesrc couldn't map file!\n");
} else if (GST_BUFFER_DATA(buf) == (void *)-1) {
perror("gstfilesrc:mmap()");
fprintf (stderr, "ERROR: gstfilesrc couldn't map file!\n");
} else if (GST_BUFFER_DATA(buf) == MAP_FAILED) {
g_error ("gstfilesrc mmap(0x%x, %d, 0x%llx) : %s",
size, src->fd, offset, sys_errlist[errno]);
}
// madvise to tell the kernel what to do with it
retval = madvise(GST_BUFFER_DATA(buf),GST_BUFFER_SIZE(buf),MADV_SEQUENTIAL);
@ -382,20 +403,27 @@ gst_filesrc_map_region (GstFileSrc *src, off_t offset, off_t size)
}
static GstBuffer *
gst_filesrc_map_small_region (GstFileSrc *src, off_t offset, off_t size)
gst_filesrc_map_small_region (GstFileSrc *src, off_t offset, size_t size)
{
int mod, mapbase, mapsize;
size_t mapsize;
off_t mod, mapbase;
GstBuffer *map;
// printf("attempting to map a small buffer at %d+%d\n",offset,size);
// if the offset starts at a non-page boundary, we have to special case
if ((mod = offset % src->pagesize)) {
GstBuffer *ret;
mapbase = offset - mod;
mapsize = ((size + mod + src->pagesize - 1) / src->pagesize) * src->pagesize;
// printf("not on page boundaries, resizing map to %d+%d\n",mapbase,mapsize);
map = gst_filesrc_map_region(src, mapbase, mapsize);
return gst_buffer_create_sub (map, offset - mapbase, size);
ret = gst_buffer_create_sub (map, offset - mapbase, size);
gst_buffer_unref (map);
return ret;
}
return gst_filesrc_map_region(src,offset,size);
@ -431,8 +459,8 @@ gst_filesrc_get (GstPad *pad)
{
GstFileSrc *src;
GstBuffer *buf = NULL, *map;
off_t readend,readsize,mapstart,mapend;
gboolean eof = FALSE;
size_t readsize;
off_t readend,mapstart,mapend;
GstFileSrcRegion region;
int i;
@ -440,6 +468,18 @@ gst_filesrc_get (GstPad *pad)
src = GST_FILESRC (gst_pad_get_parent (pad));
g_return_val_if_fail (GST_FLAG_IS_SET (src, GST_FILESRC_OPEN), NULL);
// check for seek
if (src->seek_happened) {
src->seek_happened = FALSE;
return gst_event_new(GST_EVENT_DISCONTINUOUS);
}
// check for EOF
if (src->curoffset == src->filelen) {
gst_element_set_state(src,GST_STATE_PAUSED);
return gst_event_new(GST_EVENT_EOS);
}
// calculate end pointers so we don't have to do so repeatedly later
readsize = src->block_size;
readend = src->curoffset + src->block_size; // note this is the byte *after* the read
@ -450,7 +490,6 @@ gst_filesrc_get (GstPad *pad)
if (readend > src->filelen) {
readsize = src->filelen - src->curoffset;
readend = src->curoffset;
eof = TRUE;
}
// if the start is past the mapstart
@ -458,15 +497,15 @@ gst_filesrc_get (GstPad *pad)
// 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)
if (readend <= mapend) {
// printf("read buf %d+%d lives in current mapbuf %d+%d, creating subbuffer of mapbuf\n",
// src->curoffset,readsize,GST_BUFFER_OFFSET(src->mapbuf),GST_BUFFER_SIZE(src->mapbuf));
fs_print ("read buf %d+%d lives in current mapbuf %d+%d, creating subbuffer of mapbuf\n",
src->curoffset,readsize,GST_BUFFER_OFFSET(src->mapbuf),GST_BUFFER_SIZE(src->mapbuf));
buf = gst_buffer_create_sub (src->mapbuf, src->curoffset - GST_BUFFER_OFFSET(src->mapbuf),
readsize);
// if the start actually is within the current mmap region, map an overlap buffer
} else if (src->curoffset < mapend) {
// printf("read buf %d+%d starts in mapbuf %d+%d but ends outside, creating new mmap\n",
// src->curoffset,readsize,GST_BUFFER_OFFSET(src->mapbuf),GST_BUFFER_SIZE(src->mapbuf));
fs_print ("read buf %d+%d starts in mapbuf %d+%d but ends outside, creating new mmap\n",
src->curoffset,readsize,GST_BUFFER_OFFSET(src->mapbuf),GST_BUFFER_SIZE(src->mapbuf));
buf = gst_filesrc_map_small_region (src, src->curoffset, readsize);
}
@ -478,37 +517,39 @@ gst_filesrc_get (GstPad *pad)
// either the read buffer overlaps the start of the 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
// printf("read buf %d+%d starts before mapbuf %d+%d, but overlaps it\n",
// src->curoffset,readsize,GST_BUFFER_OFFSET(src->mapbuf),GST_BUFFER_SIZE(src->mapbuf));
fs_print ("read buf %d+%d starts before mapbuf %d+%d, but overlaps it\n",
src->curoffset,readsize,GST_BUFFER_OFFSET(src->mapbuf),GST_BUFFER_SIZE(src->mapbuf));
buf = gst_filesrc_map_small_region (src, src->curoffset, readsize);
}
// then deal with the case where the read buffer is totally outside
if (buf == NULL) {
// first check to see if there's a map that covers the right region already
// printf("searching for mapbuf to cover %d+%d\n",src->curoffset,readsize);
fs_print ("searching for mapbuf to cover %d+%d\n",src->curoffset,readsize);
region.offset = src->curoffset;
region.size = readsize;
map = g_tree_search(src->map_regions,gst_filesrc_search_region_match,&region);
map = g_tree_search (src->map_regions,
(GCompareFunc) gst_filesrc_search_region_match,
&region);
// if we found an exact match, subbuffer it
if (map != NULL) {
// printf("found mapbuf at %d+%d, creating subbuffer\n",GST_BUFFER_OFFSET(map),GST_BUFFER_SIZE(map));
fs_print ("found mapbuf at %d+%d, creating subbuffer\n",GST_BUFFER_OFFSET(map),GST_BUFFER_SIZE(map));
buf = gst_buffer_create_sub (map, src->curoffset - GST_BUFFER_OFFSET(map), readsize);
// otherwise we need to create something out of thin air
} else {
// if the read buffer crosses a mmap region boundary, create a one-off region
if ((src->curoffset / src->mapsize) != (readend / src->mapsize)) {
// printf("read buf %d+%d crosses a %d-byte boundary, creating a one-off\n",
// src->curoffset,readsize,src->mapsize);
fs_print ("read buf %d+%d crosses a %d-byte boundary, creating a one-off\n",
src->curoffset,readsize,src->mapsize);
buf = gst_filesrc_map_small_region (src, src->curoffset, readsize);
// otherwise we will create a new mmap region and set it to the default
} else {
off_t nextmap = src->curoffset - (src->curoffset % src->mapsize);
// printf("read buf %d+%d in new mapbuf at %d+%d, mapping and subbuffering\n",
// src->curoffset,readsize,nextmap,src->mapsize);
fs_print ("read buf %d+%d in new mapbuf at %d+%d, mapping and subbuffering\n",
src->curoffset,readsize,nextmap,src->mapsize);
// first, we're done with the old mapbuf
gst_buffer_unref(src->mapbuf);
// create a new one
@ -525,8 +566,6 @@ gst_filesrc_get (GstPad *pad)
*(GST_BUFFER_DATA(buf)+i) = *(GST_BUFFER_DATA(buf)+i);
}
// if we hit EOF,
/* we're done, return the buffer */
src->curoffset += GST_BUFFER_SIZE(buf);
return buf;
@ -567,6 +606,7 @@ gst_filesrc_close_file (GstFileSrc *src)
{
g_return_if_fail (GST_FLAG_IS_SET (src, GST_FILESRC_OPEN));
g_print ("close\n");
/* close the file */
close (src->fd);
@ -613,6 +653,7 @@ gst_filesrc_srcpad_event(GstPad *pad, GstEventType event, gint64 location, guint
} else if (data == SEEK_END) {
src->curoffset = src->filelen - (guint64)location;
}
src->seek_happened = TRUE;
// push a discontinuous event?
return TRUE;
}

View file

@ -0,0 +1,452 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* 2001 Steve Baker <stevebaker_org@yahoo.co.uk>
*
* gstsinesrc.c:
*
* 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.
*/
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <gstsinesrc.h>
GstElementDetails gst_sinesrc_details = {
"Sine-wave src",
"Source/Audio",
"Create a sine wave of a given frequency and volume",
VERSION,
"Erik Walthinsen <omega@cse.ogi.edu>",
"(C) 1999",
};
/* SineSrc signals and args */
enum {
/* FILL ME */
LAST_SIGNAL
};
enum {
ARG_0,
ARG_VOLUME,
ARG_FORMAT,
ARG_SAMPLERATE,
ARG_FREQ,
ARG_TABLESIZE,
ARG_BUFFER_SIZE,
};
// FIXME: this is not core business...
GST_PADTEMPLATE_FACTORY (sinesrc_src_factory,
"src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_CAPS_NEW (
"sinesrc_src",
"audio/raw",
"format", GST_PROPS_STRING ("int"),
"law", GST_PROPS_INT (0),
"endianness", GST_PROPS_INT (G_BYTE_ORDER),
"signed", GST_PROPS_BOOLEAN (TRUE),
"width", GST_PROPS_INT (16),
"depth", GST_PROPS_INT (16),
"rate", GST_PROPS_INT_RANGE (8000, 48000),
"channels", GST_PROPS_INT (1)
)
);
static void gst_sinesrc_class_init (GstSineSrcClass *klass);
static void gst_sinesrc_init (GstSineSrc *src);
static GstPadNegotiateReturn gst_sinesrc_negotiate (GstPad *pad, GstCaps **caps, gpointer *data);
static void gst_sinesrc_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec);
static void gst_sinesrc_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec);
//static gboolean gst_sinesrc_change_state(GstElement *element,
// GstElementState state);
//static void gst_sinesrc_close_audio(GstSineSrc *src);
//static gboolean gst_sinesrc_open_audio(GstSineSrc *src);
static void gst_sinesrc_update_volume(GValue *value, gpointer data);
static void gst_sinesrc_update_freq(GValue *value, gpointer data);
static void gst_sinesrc_populate_sinetable (GstSineSrc *src);
static inline void gst_sinesrc_update_table_inc (GstSineSrc *src);
static inline void gst_sinesrc_update_vol_scale (GstSineSrc *src);
static void gst_sinesrc_force_caps (GstSineSrc *src);
static GstBuffer* gst_sinesrc_get (GstPad *pad);
static GstElementClass *parent_class = NULL;
//static guint gst_sinesrc_signals[LAST_SIGNAL] = { 0 };
GType
gst_sinesrc_get_type (void)
{
static GType sinesrc_type = 0;
if (!sinesrc_type) {
static const GTypeInfo sinesrc_info = {
sizeof(GstSineSrcClass),
NULL,
NULL,
(GClassInitFunc)gst_sinesrc_class_init,
NULL,
NULL,
sizeof(GstSineSrc),
0,
(GInstanceInitFunc)gst_sinesrc_init,
};
sinesrc_type = g_type_register_static (GST_TYPE_ELEMENT, "GstSineSrc", &sinesrc_info, 0);
}
return sinesrc_type;
}
static void
gst_sinesrc_class_init (GstSineSrcClass *klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass*)klass;
gstelement_class = (GstElementClass*)klass;
parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_VOLUME,
g_param_spec_double("volume","volume","volume",
0.0, 1.0, 0.0,G_PARAM_READWRITE)); // CHECKME
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FORMAT,
g_param_spec_int("format","format","format",
G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SAMPLERATE,
g_param_spec_int("samplerate","samplerate","samplerate",
G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_TABLESIZE,
g_param_spec_int("tablesize","tablesize","tablesize",
G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FREQ,
g_param_spec_double("freq","freq","freq",
0.0,G_MAXDOUBLE, 440.0,G_PARAM_READWRITE)); // CHECKME
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BUFFER_SIZE,
g_param_spec_int("buffersize","buffersize","buffersize",
0, G_MAXINT, 1024, G_PARAM_READWRITE));
gobject_class->set_property = gst_sinesrc_set_property;
gobject_class->get_property = gst_sinesrc_get_property;
// gstelement_class->change_state = gst_sinesrc_change_state;
}
static void
gst_sinesrc_init (GstSineSrc *src)
{
GstElement *element = GST_ELEMENT(src);
GstDParamManager *dpman;
src->srcpad = gst_pad_new_from_template (
GST_PADTEMPLATE_GET (sinesrc_src_factory), "src");
gst_element_add_pad(GST_ELEMENT(src), src->srcpad);
gst_pad_set_negotiate_function (src->srcpad, gst_sinesrc_negotiate);
gst_pad_set_get_function(src->srcpad, gst_sinesrc_get);
src->format = 16;
src->samplerate = 44100;
src->newcaps = TRUE;
src->table_pos = 0.0;
src->table_size = 1024;
src->buffer_size=1024;
src->seq = 0;
dpman = gst_dpman_new ("sinesrc_dpman", GST_ELEMENT(src));
gst_dpman_add_required_dparam (dpman, "volume", G_TYPE_FLOAT, gst_sinesrc_update_volume, src);
gst_dpman_add_required_dparam (dpman, "freq", G_TYPE_FLOAT, gst_sinesrc_update_freq, src);
gst_dpman_set_rate_change_pad(dpman, src->srcpad);
GST_ELEMENT_DPARAM_MANAGER(element) = dpman;
gst_sinesrc_update_vol_scale(src);
gst_sinesrc_populate_sinetable(src);
gst_sinesrc_update_table_inc(src);
}
static GstPadNegotiateReturn
gst_sinesrc_negotiate (GstPad *pad, GstCaps **caps, gpointer *data)
{
GstSineSrc *src;
if (*caps) {
g_return_val_if_fail (pad != NULL, GST_PAD_NEGOTIATE_FAIL);
src = GST_SINESRC(gst_pad_get_parent (pad));
src->samplerate = gst_caps_get_int (*caps, "rate");
gst_sinesrc_update_table_inc(src);
return GST_PAD_NEGOTIATE_AGREE;
}
return GST_PAD_NEGOTIATE_FAIL;
}
static GstBuffer *
gst_sinesrc_get(GstPad *pad)
{
GstSineSrc *src;
GstBuffer *buf;
GstDParamManager *dpman;
gint16 *samples;
gint i=0, frame_countdown;
g_return_val_if_fail (pad != NULL, NULL);
src = GST_SINESRC(gst_pad_get_parent (pad));
buf = gst_buffer_new();
g_return_val_if_fail (buf, NULL);
samples = g_new(gint16, src->buffer_size);
GST_BUFFER_DATA(buf) = (gpointer) samples;
GST_BUFFER_SIZE(buf) = 2 * src->buffer_size;
dpman = GST_ELEMENT_DPARAM_MANAGER(GST_ELEMENT(src));
frame_countdown = GST_DPMAN_FIRST_COUNTDOWN(dpman, src->buffer_size, 0LL);
while(GST_DPMAN_COUNTDOWN(dpman, frame_countdown, i)) {
src->table_lookup = (gint)(src->table_pos);
src->table_lookup_next = src->table_lookup + 1;
src->table_interp = src->table_pos - src->table_lookup;
// wrap the array lookups if we're out of bounds
if (src->table_lookup_next >= src->table_size){
src->table_lookup_next -= src->table_size;
if (src->table_lookup >= src->table_size){
src->table_lookup -= src->table_size;
src->table_pos -= src->table_size;
}
}
src->table_pos += src->table_inc;
//no interpolation
//samples[i] = src->table_data[src->table_lookup]
// * src->vol_scale;
//linear interpolation
samples[i++] = ((src->table_interp
*(src->table_data[src->table_lookup_next]
-src->table_data[src->table_lookup]
)
)+src->table_data[src->table_lookup]
)* src->vol_scale;
}
if (src->newcaps) {
gst_sinesrc_force_caps(src);
}
return buf;
}
static void
gst_sinesrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
GstSineSrc *src;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail(GST_IS_SINESRC(object));
src = GST_SINESRC(object);
switch (prop_id) {
case ARG_VOLUME:
src->volume = (gfloat)g_value_get_double (value);
gst_sinesrc_update_vol_scale(src);
break;
case ARG_FORMAT:
src->format = g_value_get_int (value);
src->newcaps=TRUE;
break;
case ARG_SAMPLERATE:
src->samplerate = g_value_get_int (value);
src->newcaps=TRUE;
gst_sinesrc_update_table_inc(src);
break;
case ARG_FREQ: {
if (g_value_get_double (value) <= 0.0 || g_value_get_double (value) > src->samplerate/2)
break;
src->freq = (gfloat)g_value_get_double (value);
gst_sinesrc_update_table_inc(src);
break;
case ARG_TABLESIZE:
src->table_size = g_value_get_int (value);
gst_sinesrc_populate_sinetable(src);
gst_sinesrc_update_table_inc(src);
break;
case ARG_BUFFER_SIZE:
src->buffer_size = g_value_get_int (value);
break;
}
default:
break;
}
}
static void
gst_sinesrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
GstSineSrc *src;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail(GST_IS_SINESRC(object));
src = GST_SINESRC(object);
switch (prop_id) {
case ARG_VOLUME:
g_value_set_double (value, (gdouble)(src->volume));
break;
case ARG_FORMAT:
g_value_set_int (value, src->format);
break;
case ARG_SAMPLERATE:
g_value_set_int (value, src->samplerate);
break;
case ARG_FREQ:
g_value_set_double (value, (gdouble)(src->freq));
break;
case ARG_TABLESIZE:
g_value_set_int (value, src->table_size);
break;
case ARG_BUFFER_SIZE:
g_value_set_int (value, src->buffer_size);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/*
static gboolean gst_sinesrc_change_state(GstElement *element,
GstElementState state) {
g_return_if_fail(GST_IS_SINESRC(element));
switch (state) {
case GST_STATE_RUNNING:
if (!gst_sinesrc_open_audio(GST_SINESRC(element)))
return FALSE;
break;
case ~GST_STATE_RUNNING:
gst_sinesrc_close_audio(GST_SINESRC(element));
break;
default:
break;
}
if (GST_ELEMENT_CLASS(parent_class)->change_state)
return GST_ELEMENT_CLASS(parent_class)->change_state(element,state);
return TRUE;
}
*/
static void
gst_sinesrc_populate_sinetable (GstSineSrc *src)
{
gint i;
gdouble pi2scaled = M_PI * 2 / src->table_size;
gfloat *table = g_new(gfloat, src->table_size);
for(i=0 ; i < src->table_size ; i++){
table[i] = (gfloat)sin(i * pi2scaled);
}
g_free(src->table_data);
src->table_data = table;
}
static void
gst_sinesrc_update_volume(GValue *value, gpointer data)
{
GstSineSrc *src = (GstSineSrc*)data;
g_return_if_fail(GST_IS_SINESRC(src));
src->volume = g_value_get_float(value);
src->vol_scale = 32767.0 * src->volume;
}
static void
gst_sinesrc_update_freq(GValue *value, gpointer data)
{
GstSineSrc *src = (GstSineSrc*)data;
g_return_if_fail(GST_IS_SINESRC(src));
src->freq = g_value_get_float(value);
src->table_inc = src->table_size * src->freq / src->samplerate;
}
static inline void
gst_sinesrc_update_table_inc (GstSineSrc *src)
{
src->table_inc = src->table_size * src->freq / src->samplerate;
}
static inline void
gst_sinesrc_update_vol_scale (GstSineSrc *src)
{
src->vol_scale = 32767.0 * src->volume;
}
static void
gst_sinesrc_force_caps(GstSineSrc *src) {
GstCaps *caps;
if (!src->newcaps)
return;
src->newcaps=FALSE;
caps = gst_caps_new (
"sinesrc_src_caps",
"audio/raw",
gst_props_new (
"format", GST_PROPS_STRING ("int"),
"law", GST_PROPS_INT (0),
"endianness", GST_PROPS_INT (G_BYTE_ORDER),
"signed", GST_PROPS_BOOLEAN (TRUE),
"width", GST_PROPS_INT (16),
"depth", GST_PROPS_INT (16),
"rate", GST_PROPS_INT (src->samplerate),
"channels", GST_PROPS_INT (1),
NULL
)
);
gst_pad_set_caps (src->srcpad, caps);
}
gboolean
gst_sinesrc_factory_init (GstElementFactory *factory)
{
gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (sinesrc_src_factory));
return TRUE;
}

View file

@ -0,0 +1,96 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
*
* gstsinesrc.h:
*
* 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_SINESRC_H__
#define __GST_SINESRC_H__
#include <config.h>
#include <gst/gst.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
GstElementDetails gst_sinesrc_details;
#define GST_TYPE_SINESRC \
(gst_sinesrc_get_type())
#define GST_SINESRC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SINESRC,GstSineSrc))
#define GST_SINESRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SINESRC,GstSineSrcClass))
#define GST_IS_SINESRC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SINESRC))
#define GST_IS_SINESRC_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SINESRC))
typedef struct _GstSineSrc GstSineSrc;
typedef struct _GstSineSrcClass GstSineSrcClass;
struct _GstSineSrc {
GstElement element;
/* pads */
GstPad *srcpad;
/* parameters */
gfloat volume;
gfloat freq;
gfloat vol_scale;
/* lookup table data */
gfloat *table_data;
gdouble table_pos;
gdouble table_inc;
gint table_size;
gdouble table_interp;
gint table_lookup;
gint table_lookup_next;
/* audio parameters */
gint format;
gint samplerate;
gint buffer_size;
gulong seq;
gboolean newcaps;
};
struct _GstSineSrcClass {
GstElementClass parent_class;
};
GType gst_sinesrc_get_type(void);
gboolean gst_sinesrc_factory_init (GstElementFactory *factory);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __GST_SINESRC_H__ */

View file

@ -56,7 +56,7 @@ GST_PADTEMPLATE_FACTORY (tee_src_factory,
static void gst_tee_class_init (GstTeeClass *klass);
static void gst_tee_init (GstTee *tee);
static GstPad* gst_tee_request_new_pad (GstElement *element, GstPadTemplate *temp);
static GstPad* gst_tee_request_new_pad (GstElement *element, GstPadTemplate *temp, const gchar *unused);
static void gst_tee_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec);
@ -127,7 +127,7 @@ gst_tee_init (GstTee *tee)
}
static GstPad*
gst_tee_request_new_pad (GstElement *element, GstPadTemplate *templ)
gst_tee_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *unused)
{
gchar *name;
GstPad *srcpad;

View file

@ -55,7 +55,9 @@ int main(int argc,char *argv[]) {
gst_pad_connect(gst_element_get_pad(queue,"src"),
gst_element_get_pad(play,"sink"));
#ifndef GST_DISABLE_LOADSAVE
xmlSaveFile("ac3play.gst", gst_xml_write(GST_ELEMENT(pipeline)));
#endif
// set thread start state
g_object_set(G_OBJECT(decodethread),"create_thread",TRUE,NULL);

View file

@ -128,7 +128,9 @@ int main(int argc,char *argv[]) {
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_READY);
gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PLAYING);
#ifndef GST_DISABLE_LOADSAVE
xmlSaveFile("aviparse.xml",gst_xml_write(GST_ELEMENT(pipeline)));
#endif
g_print("about to enter loop\n");

10
test/bufspeed/.gitignore vendored Normal file
View file

@ -0,0 +1,10 @@
Makefile
Makefile.in
*.o
*.lo
*.la
.deps
.libs
*.xml
test1
test2

View file

@ -0,0 +1,6 @@
noinst_PROGRAMS = test1 test2
test1_SOURCES = test1.c gstbuffer.c gstmempool.c
#LIBS += $(GST_LIBS)
CFLAGS += $(GST_CFLAGS)

6
test/bufspeed/README Normal file
View file

@ -0,0 +1,6 @@
benchmark of 5000000 gst_buffer_new/free on 0.2.1 code
------------------------------------------------------
gstmemchunk, no lock: real 0m1.309s user 0m1.220s sys 0m0.070s
gmemchunk, no lock: real 0m3.872s user 0m3.740s sys 0m0.090s
gstmemchunk, lock: real 0m5.306s user 0m5.160s sys 0m0.100s
gmemchunk, lock: real 0m8.001s user 0m7.890s sys 0m0.080s

495
test/bufspeed/gstbuffer.c Normal file
View file

@ -0,0 +1,495 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
*
* gstbuffer.c: Buffer operations
*
* 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.
*/
/* this file makes too much noise for most debugging sessions */
#define GST_DEBUG_FORCE_DISABLE
#include "gst/gst_private.h"
#include "gstbuffer.h"
#include "gstmempool.h"
GType _gst_buffer_type;
static GstMemPool *_gst_buffer_pool;
static void
gst_buffer_alloc_func (GstMemPool *pool, gpointer data)
{
GstBuffer *buffer = GST_BUFFER (data);
GST_DATA_TYPE(buffer) = _gst_buffer_type;
buffer->lock = g_mutex_new ();
}
static void
gst_buffer_free_func (GstMemPool *pool, gpointer data)
{
GstBuffer *buffer = GST_BUFFER (data);
g_mutex_free (buffer->lock);
}
void
_gst_buffer_initialize (void)
{
int buffersize = sizeof(GstBuffer);
static const GTypeInfo buffer_info = {
0, // sizeof(class),
NULL,
NULL,
NULL,
NULL,
NULL,
0, // sizeof(object),
0,
NULL,
};
// round up to the nearest 32 bytes for cache-line and other efficiencies
buffersize = (((buffersize-1) / 32) + 1) * 32;
_gst_buffer_pool = gst_mem_pool_new ("GstBuffer", buffersize,
buffersize * 32, G_ALLOC_AND_FREE, gst_buffer_alloc_func, gst_buffer_free_func);
_gst_buffer_type = g_type_register_static (G_TYPE_INT, "GstBuffer", &buffer_info, 0);
}
/**
* gst_buffer_new:
*
* Create a new buffer.
*
* Returns: new buffer
*/
GstBuffer*
gst_buffer_new (void)
{
GstBuffer *buffer;
buffer = gst_mem_pool_alloc (_gst_buffer_pool);
GST_INFO (GST_CAT_BUFFER,"creating new buffer %p",buffer);
#ifdef HAVE_ATOMIC_H
atomic_set (&buffer->refcount, 1);
#else
buffer->refcount = 1;
#endif
buffer->offset = -1;
buffer->flags = 0;
buffer->data = NULL;
buffer->size = 0;
buffer->maxsize = 0;
buffer->timestamp = 0;
buffer->parent = NULL;
buffer->pool = NULL;
buffer->pool_private = NULL;
buffer->free = NULL;
buffer->copy = NULL;
return buffer;
}
/**
* gst_buffer_new_from_pool:
* @pool: the buffer pool to use
*
* Create a new buffer using the specified bufferpool.
*
* Returns: new buffer
*/
GstBuffer*
gst_buffer_new_from_pool (GstBufferPool *pool, guint32 offset, guint32 size)
{
GstBuffer *buffer;
g_return_val_if_fail (pool != NULL, NULL);
g_return_val_if_fail (pool->buffer_new != NULL, NULL);
buffer = pool->buffer_new (pool, offset, size, pool->user_data);
buffer->pool = pool;
buffer->free = pool->buffer_free;
buffer->copy = pool->buffer_copy;
GST_INFO (GST_CAT_BUFFER,"creating new buffer %p from pool %p (size %x, offset %x)",
buffer, pool, size, offset);
return buffer;
}
/**
* gst_buffer_create_sub:
* @parent: parent buffer
* @offset: offset into parent buffer
* @size: size of new subbuffer
*
* Creates a sub-buffer from the parent at a given offset.
*
* Returns: new buffer
*/
GstBuffer*
gst_buffer_create_sub (GstBuffer *parent,
guint32 offset,
guint32 size)
{
GstBuffer *buffer;
g_return_val_if_fail (parent != NULL, NULL);
g_return_val_if_fail (GST_BUFFER_REFCOUNT(parent) > 0, NULL);
g_return_val_if_fail (size > 0, NULL);
g_return_val_if_fail ((offset+size) <= parent->size, NULL);
buffer = gst_mem_pool_alloc (_gst_buffer_pool);
GST_DATA_TYPE(buffer) = _gst_buffer_type;
GST_INFO (GST_CAT_BUFFER,"creating new subbuffer %p from parent %p (size %u, offset %u)",
buffer, parent, size, offset);
#ifdef HAVE_ATOMIC_H
atomic_set (&buffer->refcount, 1);
#else
buffer->refcount = 1;
#endif
// copy flags and type from parent, for lack of better
buffer->flags = parent->flags;
// set the data pointer, size, offset, and maxsize
buffer->data = parent->data + offset;
buffer->size = size;
buffer->maxsize = parent->size - offset;
// deal with bogus/unknown offsets
if (parent->offset != -1)
buffer->offset = parent->offset + offset;
else
buffer->offset = -1;
// again, for lack of better, copy parent's timestamp
buffer->timestamp = parent->timestamp;
buffer->maxage = parent->maxage;
// if the parent buffer is a subbuffer itself, use its parent, a real buffer
if (parent->parent != NULL)
parent = parent->parent;
// set parentage and reference the parent
buffer->parent = parent;
gst_buffer_ref (parent);
buffer->pool = NULL;
return buffer;
}
// FIXME FIXME: how does this overlap with the newly-added gst_buffer_span() ???
/**
* gst_buffer_append:
* @buffer: a buffer
* @append: the buffer to append
*
* Creates a new buffer by appending the data of append to the
* existing data of buffer.
*
* Returns: new buffer
*/
GstBuffer*
gst_buffer_append (GstBuffer *buffer,
GstBuffer *append)
{
guint size;
GstBuffer *newbuf;
g_return_val_if_fail (buffer != NULL, NULL);
g_return_val_if_fail (append != NULL, NULL);
g_return_val_if_fail (buffer->pool == NULL, NULL);
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buffer) > 0, NULL);
g_return_val_if_fail (GST_BUFFER_REFCOUNT(append) > 0, NULL);
GST_INFO (GST_CAT_BUFFER,"appending buffers %p and %p",buffer,append);
GST_BUFFER_LOCK (buffer);
// the buffer is not used by anyone else
if (GST_BUFFER_REFCOUNT (buffer) == 1 && buffer->parent == NULL
&& !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_DONTFREE)) {
// save the old size
size = buffer->size;
buffer->size += append->size;
buffer->data = g_realloc (buffer->data, buffer->size);
memcpy(buffer->data + size, append->data, append->size);
GST_BUFFER_UNLOCK (buffer);
}
// the buffer is used, create a new one
else {
newbuf = gst_buffer_new ();
newbuf->size = buffer->size+append->size;
newbuf->data = g_malloc (newbuf->size);
memcpy (newbuf->data, buffer->data, buffer->size);
memcpy (newbuf->data+buffer->size, append->data, append->size);
GST_BUFFER_UNLOCK (buffer);
gst_buffer_unref (buffer);
buffer = newbuf;
}
return buffer;
}
/**
* gst_buffer_destroy:
* @buffer: the GstBuffer to destroy
*
* destroy the buffer
*/
void
gst_buffer_destroy (GstBuffer *buffer)
{
g_return_if_fail (buffer != NULL);
GST_INFO (GST_CAT_BUFFER, "freeing %sbuffer %p",
(buffer->parent?"sub":""),
buffer);
// free the data only if there is some, DONTFREE isn't set, and not sub
if (GST_BUFFER_DATA (buffer) &&
!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_DONTFREE) &&
(buffer->parent == NULL)) {
// if there's a free function, use it
if (buffer->free != NULL) {
(buffer->free)(buffer);
} else {
g_free (GST_BUFFER_DATA (buffer));
}
}
// unreference the parent if there is one
if (buffer->parent != NULL)
gst_buffer_unref (buffer->parent);
// remove it entirely from memory
gst_mem_pool_free (_gst_buffer_pool,buffer);
}
/**
* gst_buffer_ref:
* @buffer: the GstBuffer to reference
*
* Increment the refcount of this buffer.
*/
void
gst_buffer_ref (GstBuffer *buffer)
{
g_return_if_fail (buffer != NULL);
g_return_if_fail (GST_BUFFER_REFCOUNT(buffer) > 0);
GST_INFO (GST_CAT_BUFFER, "ref buffer %p\n", buffer);
#ifdef HAVE_ATOMIC_H
atomic_inc (&(buffer->refcount));
#else
GST_BUFFER_LOCK (buffer);
buffer->refcount++;
GST_BUFFER_UNLOCK (buffer);
#endif
}
/**
* gst_buffer_unref:
* @buffer: the GstBuffer to unref
*
* Decrement the refcount of this buffer. If the refcount is
* zero, the buffer will be destroyed.
*/
void
gst_buffer_unref (GstBuffer *buffer)
{
gint zero;
g_return_if_fail (buffer != NULL);
g_return_if_fail (GST_BUFFER_REFCOUNT(buffer) > 0);
GST_INFO (GST_CAT_BUFFER, "unref buffer %p\n", buffer);
#ifdef HAVE_ATOMIC_H
zero = atomic_dec_and_test (&(buffer->refcount));
#else
GST_BUFFER_LOCK (buffer);
buffer->refcount--;
zero = (buffer->refcount == 0);
GST_BUFFER_UNLOCK (buffer);
#endif
/* if we ended up with the refcount at zero, destroy the buffer */
if (zero) {
gst_buffer_destroy (buffer);
}
}
/**
* gst_buffer_copy:
* @buffer: the orignal GstBuffer to make a copy of
*
* Make a full copy of the give buffer, data and all.
*
* Returns: new buffer
*/
GstBuffer *
gst_buffer_copy (GstBuffer *buffer)
{
GstBuffer *newbuf;
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buffer) > 0, NULL);
// if a copy function exists, use it, else copy the bytes
if (buffer->copy != NULL) {
newbuf = (buffer->copy)(buffer);
} else {
// allocate a new buffer
newbuf = gst_buffer_new();
// copy the absolute size
newbuf->size = buffer->size;
// allocate space for the copy
newbuf->data = (guchar *)g_malloc (buffer->size);
// copy the data straight across
memcpy(newbuf->data,buffer->data,buffer->size);
// the new maxsize is the same as the size, since we just malloc'd it
newbuf->maxsize = newbuf->size;
}
newbuf->offset = buffer->offset;
newbuf->timestamp = buffer->timestamp;
newbuf->maxage = buffer->maxage;
// since we just created a new buffer, so we have no ties to old stuff
newbuf->parent = NULL;
newbuf->pool = NULL;
return newbuf;
}
/*
* gst_buffer_is_span_fast
* @buf1: first source buffer
* @buf2: second source buffer
*
* Determines whether a gst_buffer_span is free, or requires a memcpy.
*
* Returns: TRUE if the buffers are contiguous, FALSE if a copy would be required.
*/
gboolean
gst_buffer_is_span_fast (GstBuffer *buf1, GstBuffer *buf2)
{
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf1) > 0, FALSE);
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf2) > 0, FALSE);
return (buf1->parent && buf2->parent &&
(buf1->parent == buf2->parent) &&
((buf1->data + buf1->size) == buf2->data));
}
/**
* gst_buffer_span:
* @buf1: first source buffer to merge
* @offset: offset in first buffer to start new buffer
* @buf2: second source buffer to merge
* @len: length of new buffer
*
* Create a new buffer that consists of part of buf1 and buf2.
* Logically, buf1 and buf2 are concatenated into a single larger
* buffer, and a new buffer is created at the given offset inside
* this space, with a given length.
*
* If the two source buffers are children of the same larger buffer,
* and are contiguous, the new buffer will be a child of the shared
* parent, and thus no copying is necessary.
*
* Returns: new buffer that spans the two source buffers
*/
// FIXME need to think about CoW and such...
GstBuffer *
gst_buffer_span (GstBuffer *buf1, guint32 offset, GstBuffer *buf2, guint32 len)
{
GstBuffer *newbuf;
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf1) > 0, NULL);
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf2) > 0, NULL);
// make sure buf1 has a lower address than buf2
if (buf1->data > buf2->data) {
GstBuffer *tmp = buf1;
g_print ("swapping buffers\n");
buf1 = buf2;
buf2 = tmp;
}
// if the two buffers have the same parent and are adjacent
if (gst_buffer_is_span_fast(buf1,buf2)) {
// we simply create a subbuffer of the common parent
newbuf = gst_buffer_create_sub (buf1->parent, buf1->data - (buf1->parent->data) + offset, len);
}
else {
g_print ("slow path taken in buffer_span\n");
// otherwise we simply have to brute-force copy the buffers
newbuf = gst_buffer_new ();
// put in new size
newbuf->size = len;
// allocate space for the copy
newbuf->data = (guchar *)g_malloc(len);
// copy the first buffer's data across
memcpy(newbuf->data, buf1->data + offset, buf1->size - offset);
// copy the second buffer's data across
memcpy(newbuf->data + (buf1->size - offset), buf2->data, len - (buf1->size - offset));
if (newbuf->offset != -1)
newbuf->offset = buf1->offset + offset;
newbuf->timestamp = buf1->timestamp;
if (buf2->maxage > buf1->maxage) newbuf->maxage = buf2->maxage;
else newbuf->maxage = buf1->maxage;
}
return newbuf;
}
/**
* gst_buffer_merge:
* @buf1: first source buffer to merge
* @buf2: second source buffer to merge
*
* Create a new buffer that is the concatenation of the two source
* buffers. The original source buffers will not be modified or
* unref'd.
*
* Internally is nothing more than a specialized gst_buffer_span,
* so the same optimizations can occur.
*
* Returns: new buffer that's the concatenation of the source buffers
*/
GstBuffer *
gst_buffer_merge (GstBuffer *buf1, GstBuffer *buf2)
{
// we're just a specific case of the more general gst_buffer_span()
return gst_buffer_span (buf1, 0, buf2, buf1->size + buf2->size);
}

174
test/bufspeed/gstbuffer.h Normal file
View file

@ -0,0 +1,174 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
*
* gstbuffer.h: Header for GstBuffer object
*
* 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_H__
#define __GST_BUFFER_H__
//
// Define this to add file:line info to each GstBuffer showing
// the location in the source code where the buffer was created.
//
// #define GST_BUFFER_WHERE
//
// Then in gdb, you can `call gst_buffer_print_live()' to get a list
// of allocated GstBuffers and also the file:line where they were
// allocated.
//
#include <gst/gstdata.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_ATOMIC_H
#include <asm/atomic.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
extern GType _gst_buffer_type;
#define GST_TYPE_BUFFER (_gst_buffer_type)
#define GST_BUFFER(buf) ((GstBuffer *)(buf))
#define GST_IS_BUFFER(buf) (GST_DATA_TYPE(buf) == GST_TYPE_BUFFER)
#define GST_BUFFER_FLAGS(buf) (GST_BUFFER(buf)->flags)
#define GST_BUFFER_FLAG_IS_SET(buf,flag) (GST_BUFFER_FLAGS(buf) & (1<<(flag)))
#define GST_BUFFER_FLAG_SET(buf,flag) G_STMT_START{ (GST_BUFFER_FLAGS(buf) |= (1<<(flag))); }G_STMT_END
#define GST_BUFFER_FLAG_UNSET(buf,flag) G_STMT_START{ (GST_BUFFER_FLAGS(buf) &= ~(1<<(flag))); }G_STMT_END
#define GST_BUFFER_DATA(buf) (GST_BUFFER(buf)->data)
#define GST_BUFFER_SIZE(buf) (GST_BUFFER(buf)->size)
#define GST_BUFFER_OFFSET(buf) (GST_BUFFER(buf)->offset)
#define GST_BUFFER_MAXSIZE(buf) (GST_BUFFER(buf)->maxsize)
#define GST_BUFFER_TIMESTAMP(buf) (GST_BUFFER(buf)->timestamp)
#define GST_BUFFER_MAXAGE(buf) (GST_BUFFER(buf)->maxage)
#define GST_BUFFER_BUFFERPOOL(buf) (GST_BUFFER(buf)->pool)
#define GST_BUFFER_PARENT(buf) (GST_BUFFER(buf)->parent)
#define GST_BUFFER_POOL_PRIVATE(buf) (GST_BUFFER(buf)->pool_private)
#define GST_BUFFER_COPY_FUNC(buf) (GST_BUFFER(buf)->copy)
#define GST_BUFFER_FREE_FUNC(buf) (GST_BUFFER(buf)->free)
#define GST_BUFFER_LOCK(buf) (g_mutex_lock(GST_BUFFER(buf)->lock))
#define GST_BUFFER_TRYLOCK(buf) (g_mutex_trylock(GST_BUFFER(buf)->lock))
#define GST_BUFFER_UNLOCK(buf) (g_mutex_unlock(GST_BUFFER(buf)->lock))
typedef enum {
GST_BUFFER_READONLY,
GST_BUFFER_ORIGINAL,
GST_BUFFER_DONTFREE,
GST_BUFFER_FLUSH,
GST_BUFFER_EOS,
GST_BUFFER_DISCONTINUOUS,
} GstBufferFlags;
typedef struct _GstBuffer GstBuffer;
typedef void (*GstBufferFreeFunc) (GstBuffer *buf);
typedef GstBuffer *(*GstBufferCopyFunc) (GstBuffer *srcbuf);
#include <gst/gstbufferpool.h>
struct _GstBuffer {
GstData data_type;
/* locking */
GMutex *lock;
/* refcounting */
#ifdef HAVE_ATOMIC_H
atomic_t refcount;
#define GST_BUFFER_REFCOUNT(buf) (atomic_read(&(GST_BUFFER((buf))->refcount)))
#else
int refcount;
#define GST_BUFFER_REFCOUNT(buf) (GST_BUFFER(buf)->refcount)
#endif
/* flags */
guint16 flags;
/* pointer to data, its size, and offset in original source if known */
guchar *data;
guint32 size;
guint32 maxsize;
guint32 offset;
/* timestamp */
gint64 timestamp;
gint64 maxage;
/* subbuffer support, who's my parent? */
GstBuffer *parent;
/* this is a pointer to the buffer pool (if any) */
GstBufferPool *pool;
gpointer pool_private;
/* utility function pointers */
GstBufferFreeFunc free; // free the data associated with the buffer
GstBufferCopyFunc copy; // copy the data from one buffer to another
};
/* initialisation */
void _gst_buffer_initialize (void);
/* creating a new buffer from scratch */
GstBuffer* gst_buffer_new (void);
GstBuffer* gst_buffer_new_from_pool (GstBufferPool *pool, guint32 offset, guint32 size);
/* creating a subbuffer */
GstBuffer* gst_buffer_create_sub (GstBuffer *parent, guint32 offset, guint32 size);
/* refcounting */
void gst_buffer_ref (GstBuffer *buffer);
void gst_buffer_unref (GstBuffer *buffer);
/* destroying the buffer */
void gst_buffer_destroy (GstBuffer *buffer);
/* copy buffer */
GstBuffer* gst_buffer_copy (GstBuffer *buffer);
/* merge, span, or append two buffers, intelligently */
GstBuffer* gst_buffer_merge (GstBuffer *buf1, GstBuffer *buf2);
GstBuffer* gst_buffer_span (GstBuffer *buf1,guint32 offset,GstBuffer *buf2,guint32 len);
GstBuffer* gst_buffer_append (GstBuffer *buf, GstBuffer *buf2);
gboolean gst_buffer_is_span_fast (GstBuffer *buf1, GstBuffer *buf2);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __GST_BUFFER_H__ */

191
test/bufspeed/gstmempool.c Normal file
View file

@ -0,0 +1,191 @@
#include "gstmempool.h"
#ifdef __SMP__
#define POOL_LOCK "lock ; "
#else
#define POOL_LOCK ""
#endif
#define GST_MEM_POOL_AREA(pool) (((GstMemPoolElement*)(pool))->area)
#define GST_MEM_POOL_DATA(pool) ((gpointer)(((GstMemPoolElement*)(pool)) + 1))
#define GST_MEM_POOL_LINK(mem) ((GstMemPoolElement*)((guint8*)(mem) - sizeof (GstMemPoolElement)))
#define USE_ASM
/*******************************************************
* area size
* +-----------------------------------------+
* pool size
* +------------+
*
* !next!data... !next!data.... !next!data...
* ! ^ ! ^ !
* +-------------+ +------------+ +---> NULL
*
*/
static gboolean
populate (GstMemPool *mem_pool)
{
guint8 *area;
gint i;
if (mem_pool->cleanup)
return FALSE;
area = (guint8 *) g_malloc (mem_pool->area_size);
for (i=0; i < mem_pool->area_size; i += mem_pool->pool_size) {
guint8 *areap = area + i;
GST_MEM_POOL_AREA (areap) = (GstMemPoolElement *)area;
if (mem_pool->alloc_func) {
mem_pool->alloc_func (mem_pool, GST_MEM_POOL_DATA (areap));
}
gst_mem_pool_free (mem_pool, GST_MEM_POOL_DATA (areap));
}
return TRUE;
}
GstMemPool*
gst_mem_pool_new (gchar* name, gint atom_size, gulong area_size, gint type,
GstMemPoolAllocFunc alloc_func,
GstMemPoolFreeFunc free_func)
{
GstMemPool *mem_pool;
g_return_val_if_fail (atom_size > 0, NULL);
g_return_val_if_fail (area_size >= atom_size, NULL);
mem_pool = g_malloc (sizeof (GstMemPool));
mem_pool->pool_size = atom_size + sizeof (GstMemPoolElement);
area_size = (area_size/atom_size) * mem_pool->pool_size;
mem_pool->name = g_strdup (name);
mem_pool->free = NULL;
mem_pool->cnt = 0;
mem_pool->atom_size = atom_size;
mem_pool->area_size = area_size;
mem_pool->cleanup = FALSE;
mem_pool->alloc_func = alloc_func;
mem_pool->free_func = free_func;
mem_pool->chunk_lock = g_mutex_new ();
populate (mem_pool);
return mem_pool;
}
static gboolean
free_area (gpointer key, gpointer value, gpointer user_data)
{
g_print ("free %p\n", key);
g_free (key);
return TRUE;
}
void
gst_mem_pool_destroy (GstMemPool *mem_pool)
{
GHashTable *elements = g_hash_table_new (NULL, NULL);
gpointer data;
mem_pool->cleanup = TRUE;
data = gst_mem_pool_alloc (mem_pool);
while (data) {
GstMemPoolElement *elem = GST_MEM_POOL_LINK (data);
g_hash_table_insert (elements, GST_MEM_POOL_AREA (elem), NULL);
data = gst_mem_pool_alloc (mem_pool);
}
g_hash_table_foreach_remove (elements, free_area, NULL);
g_hash_table_destroy (elements);
g_free (mem_pool->name);
g_free (mem_pool);
}
gpointer
gst_mem_pool_alloc (GstMemPool *mem_pool)
{
GstMemPoolElement *pool = NULL;
g_return_val_if_fail (mem_pool != NULL, NULL);
again:
#ifdef USE_ASM
__asm__ __volatile__ (" testl %%eax, %%eax \n\t"
" jz 20f \n"
"10: \t"
" movl (%%eax), %%ebx \n\t"
" movl %%edx, %%ecx \n\t"
" incl %%ecx \n\t"
POOL_LOCK "cmpxchg8b %1 \n\t"
" jz 20f \n\t"
" testl %%eax, %%eax \n\t"
" jnz 10b \n"
"20:\t"
:"=a" (pool)
:"m" (*mem_pool), "a" (mem_pool->free), "d" (mem_pool->cnt)
:"ecx", "ebx");
#else
g_mutex_lock (mem_pool->chunk_lock);
if (mem_pool->free) {
pool = mem_pool->free;
mem_pool->free = pool->link;
}
g_mutex_unlock (mem_pool->chunk_lock);
#endif
if (!pool) {
//g_print ("extending\n");
if (populate (mem_pool))
goto again;
else
return NULL;
}
return GST_MEM_POOL_DATA (pool);
}
gpointer
gst_mem_pool_alloc0 (GstMemPool *mem_pool)
{
gpointer mem = gst_mem_pool_alloc (mem_pool);
if (mem)
memset (mem, 0, mem_pool->atom_size);
return mem;
}
void
gst_mem_pool_free (GstMemPool *mem_pool, gpointer mem)
{
GstMemPoolElement *pool;
g_return_if_fail (mem_pool != NULL);
g_return_if_fail (mem != NULL);
pool = GST_MEM_POOL_LINK (mem);
#ifdef USE_ASM
__asm__ __volatile__ ( "1: \t"
" movl %2, (%1) \n"
POOL_LOCK "cmpxchg %1, %0 \n\t"
" jnz 1b \n\t"
:
:"m" (*mem_pool), "r" (pool), "a" (mem_pool->free));
#else
g_mutex_lock (mem_pool->chunk_lock);
pool->link = mem_pool->free;
mem_pool->free = pool;
g_mutex_unlock (mem_pool->chunk_lock);
#endif
}

Some files were not shown because too many files have changed in this diff Show more