From d574ab8126f0ede0e32d9e4028e30d32888d2f22 Mon Sep 17 00:00:00 2001 From: Erik Walthinsen Date: Wed, 17 Oct 2001 10:21:27 +0000 Subject: [PATCH] merge from EVENTS1 on 20011016 Original commit message from CVS: merge from EVENTS1 on 20011016 --- autogen.sh | 10 +- configure.base | 30 +- docs/gst/tmpl/gstautoplug.sgml | 21 +- docs/gst/tmpl/gstbuffer.sgml | 8 +- docs/gst/tmpl/gstbufferpool.sgml | 69 +- docs/gst/tmpl/gstdisksrc.sgml | 4 +- docs/gst/tmpl/gstelement.sgml | 37 +- docs/gst/tmpl/gstfakesink.sgml | 2 +- docs/gst/tmpl/gstfakesrc.sgml | 6 +- docs/gst/tmpl/gstidentity.sgml | 4 +- docs/gst/tmpl/gstobject.sgml | 8 - docs/gst/tmpl/gstpad.sgml | 130 +- docs/gst/tmpl/gstplugin.sgml | 88 +- docs/gst/tmpl/gstqueue.sgml | 2 +- docs/gst/tmpl/gstreamer-unused.sgml | 5722 +++++++++++--------- docs/gst/tmpl/gsttee.sgml | 2 +- docs/gst/tmpl/gstthread.sgml | 2 +- docs/gst/tmpl/gsttype.sgml | 22 +- docs/random/wtay/events | 244 +- docs/random/wtay/events2 | 140 + editor/gsteditorproject.c | 7 +- examples/Makefile.am | 10 +- examples/autoplug/autoplug.c | 2 + examples/mixer/mixer.c | 4 + gst/Makefile.am | 6 + gst/autoplug/gstautoplugger.c | 2 +- gst/elements/Makefile.am | 8 +- gst/elements/gstaggregator.c | 5 +- gst/elements/gstdisksrc.c | 137 +- gst/elements/gstdisksrc.h | 1 + gst/elements/gstfakesink.c | 64 +- gst/elements/gstfakesink.h | 1 + gst/elements/gstfakesrc.c | 414 +- gst/elements/gstfakesrc.h | 50 +- gst/elements/gstfilesrc.c | 97 +- gst/elements/gstsinesrc.c | 452 ++ gst/elements/gstsinesrc.h | 96 + gst/elements/gsttee.c | 4 +- gst/gobject2gtk.c | 19 +- gst/gobject2gtk.h | 60 +- gst/gst.c | 101 +- gst/gst.h | 1 + gst/gstautoplug.c | 9 + gst/gstbin.c | 15 +- gst/gstbuffer.c | 134 +- gst/gstbuffer.h | 67 +- gst/gstbufferpool.c | 9 +- gst/gstcaps.c | 4 +- gst/gstcaps.h | 11 +- gst/gstconfig.h | 32 + gst/gstdata.h | 46 + gst/gstelement.c | 63 +- gst/gstelement.h | 95 +- gst/gstelementfactory.c | 4 +- gst/gstevent.c | 96 + gst/gstevent.h | 46 +- gst/gstinfo.c | 49 +- gst/gstinfo.h | 2 + gst/gstobject.c | 28 +- gst/gstobject.h | 68 +- gst/gstpad.c | 60 +- gst/gstpad.h | 79 +- gst/gstparse.c | 4 + gst/gstplugin.c | 4 +- gst/gstplugin.h | 10 +- gst/gstprops.c | 4 +- gst/gstprops.h | 13 +- gst/gstscheduler.c | 2 +- gst/gstthread.c | 10 +- gst/gstversion.h.in | 2 + gst/gstxml.h | 11 +- gst/utils/gstbytestream.c | 113 + gst/utils/gstbytestream.h | 56 + gstplay/gstplay.c | 2 +- gstplay/main.c | 2 + libs/Makefile.am | 5 +- libs/bytestream/Makefile.am | 11 + libs/bytestream/gstbstest.c | 294 + libs/bytestream/gstbytestream.c | 394 ++ libs/bytestream/gstbytestream.h | 53 + plugins/elements/Makefile.am | 8 +- plugins/elements/gstaggregator.c | 5 +- plugins/elements/gstdisksrc.c | 137 +- plugins/elements/gstdisksrc.h | 1 + plugins/elements/gstfakesink.c | 64 +- plugins/elements/gstfakesink.h | 1 + plugins/elements/gstfakesrc.c | 414 +- plugins/elements/gstfakesrc.h | 50 +- plugins/elements/gstfilesrc.c | 97 +- plugins/elements/gstsinesrc.c | 452 ++ plugins/elements/gstsinesrc.h | 96 + plugins/elements/gsttee.c | 4 +- test/ac3play.c | 2 + test/aviparse.c | 2 + test/bufspeed/.gitignore | 10 + test/bufspeed/Makefile.am | 6 + test/bufspeed/README | 6 + test/bufspeed/gstbuffer.c | 495 ++ test/bufspeed/gstbuffer.h | 174 + test/bufspeed/gstmempool.c | 191 + test/bufspeed/gstmempool.h | 43 + test/bufspeed/test1.c | 19 + test/bufspeed/test2.c | 19 + test/dvshow.c | 2 + test/events/Makefile.am | 4 + test/events/seek.c | 68 + test/main.c | 2 + test/memchunk/Makefile.am | 7 + test/memchunk/gmemchunktest.c | 78 + test/memchunk/gstmemchunk.c | 162 + test/memchunk/gstmemchunk.h | 34 + test/memchunk/gstmemchunktest.c | 79 + test/mpeg2parse2.c | 2 +- tests/Makefile.am | 13 +- tests/old/examples/Makefile.am | 10 +- tests/old/examples/autoplug/autoplug.c | 2 + tests/old/examples/mixer/mixer.c | 4 + tests/old/testsuite/bytestream/.gitignore | 8 + tests/old/testsuite/bytestream/Makefile.am | 13 + tests/old/testsuite/bytestream/gstbstest.c | 407 ++ tests/old/testsuite/bytestream/mem.c | 23 + tests/old/testsuite/bytestream/mem.h | 1 + tests/old/testsuite/bytestream/test1.c | 230 + tests/old/testsuite/bytestream/testfile1 | 93 + tests/sched/Makefile.am | 4 + testsuite/bytestream/.gitignore | 8 + testsuite/bytestream/Makefile.am | 13 + testsuite/bytestream/gstbstest.c | 407 ++ testsuite/bytestream/mem.c | 23 + testsuite/bytestream/mem.h | 1 + testsuite/bytestream/test1.c | 230 + testsuite/bytestream/testfile1 | 93 + tools/Makefile.am | 12 +- tools/gstreamer-inspect.c | 2 + tools/gstreamer-launch.c | 8 +- 135 files changed, 10416 insertions(+), 3922 deletions(-) create mode 100644 docs/random/wtay/events2 create mode 100644 gst/elements/gstsinesrc.c create mode 100644 gst/elements/gstsinesrc.h create mode 100644 gst/gstconfig.h create mode 100644 gst/gstdata.h create mode 100644 gst/gstevent.c create mode 100644 gst/utils/gstbytestream.c create mode 100644 gst/utils/gstbytestream.h create mode 100644 libs/bytestream/Makefile.am create mode 100644 libs/bytestream/gstbstest.c create mode 100644 libs/bytestream/gstbytestream.c create mode 100644 libs/bytestream/gstbytestream.h create mode 100644 plugins/elements/gstsinesrc.c create mode 100644 plugins/elements/gstsinesrc.h create mode 100644 test/bufspeed/.gitignore create mode 100644 test/bufspeed/Makefile.am create mode 100644 test/bufspeed/README create mode 100644 test/bufspeed/gstbuffer.c create mode 100644 test/bufspeed/gstbuffer.h create mode 100644 test/bufspeed/gstmempool.c create mode 100644 test/bufspeed/gstmempool.h create mode 100644 test/bufspeed/test1.c create mode 100644 test/bufspeed/test2.c create mode 100644 test/events/Makefile.am create mode 100644 test/events/seek.c create mode 100644 test/memchunk/Makefile.am create mode 100644 test/memchunk/gmemchunktest.c create mode 100644 test/memchunk/gstmemchunk.c create mode 100644 test/memchunk/gstmemchunk.h create mode 100644 test/memchunk/gstmemchunktest.c create mode 100644 tests/old/testsuite/bytestream/.gitignore create mode 100644 tests/old/testsuite/bytestream/Makefile.am create mode 100644 tests/old/testsuite/bytestream/gstbstest.c create mode 100644 tests/old/testsuite/bytestream/mem.c create mode 100644 tests/old/testsuite/bytestream/mem.h create mode 100644 tests/old/testsuite/bytestream/test1.c create mode 100644 tests/old/testsuite/bytestream/testfile1 create mode 100644 testsuite/bytestream/.gitignore create mode 100644 testsuite/bytestream/Makefile.am create mode 100644 testsuite/bytestream/gstbstest.c create mode 100644 testsuite/bytestream/mem.c create mode 100644 testsuite/bytestream/mem.h create mode 100644 testsuite/bytestream/test1.c create mode 100644 testsuite/bytestream/testfile1 diff --git a/autogen.sh b/autogen.sh index 42a3281be4..8a4d60b2c2 100755 --- a/autogen.sh +++ b/autogen.sh @@ -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 diff --git a/configure.base b/configure.base index de9b8151ac..7597efb68b 100644 --- a/configure.base +++ b/configure.base @@ -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 diff --git a/docs/gst/tmpl/gstautoplug.sgml b/docs/gst/tmpl/gstautoplug.sgml index ff407eac19..050429cf92 100644 --- a/docs/gst/tmpl/gstautoplug.sgml +++ b/docs/gst/tmpl/gstautoplug.sgml @@ -116,7 +116,7 @@ The type of the autoplugger. -@name: +@feature: @longdesc: @type: @@ -207,22 +207,3 @@ The type of the autoplugger. @Returns: - - - - - -@factory: -@parent: -@Returns: - - - - - - - -@parent: -@Returns: - - diff --git a/docs/gst/tmpl/gstbuffer.sgml b/docs/gst/tmpl/gstbuffer.sgml index 9214caa7c5..94ccbc2a9e 100644 --- a/docs/gst/tmpl/gstbuffer.sgml +++ b/docs/gst/tmpl/gstbuffer.sgml @@ -239,6 +239,7 @@ used when data in a stream has been skipped +@data_type: @lock: @data: @size: @@ -265,6 +266,8 @@ used when data in a stream has been skipped @pool: +@location: +@size: @Returns: @@ -293,9 +296,12 @@ used when data in a stream has been skipped +@buf: +@buf2: +@Returns: + @buffer: @append: -@Returns: diff --git a/docs/gst/tmpl/gstbufferpool.sgml b/docs/gst/tmpl/gstbufferpool.sgml index ddcf3dadf2..874a6501d6 100644 --- a/docs/gst/tmpl/gstbufferpool.sgml +++ b/docs/gst/tmpl/gstbufferpool.sgml @@ -52,30 +52,10 @@ A bufferpool can be requested from a pad with the gst_pad_get_bufferpool() funct @lock: -@new_user_data: -@destroy_user_data: -@destroy_buffer: - - - -The function called when a buffer has to be created for this pool. - - -@pool: the pool from which to create the buffer -@user_data: any user data -@Returns: a new buffer from the pool - - - - -This function will be called when the given buffer has to be returned to -the pool. - - -@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: @@ -85,24 +65,6 @@ the pool. @Returns: - - - - - -@pool: -@Returns: - - - - - - - -@pool: -@buffer: - - @@ -130,26 +92,6 @@ the pool. @pool: - - - - - -@pool: -@create: -@user_data: - - - - - - - -@pool: -@destroy: -@user_data: - - @@ -163,9 +105,10 @@ the pool. -@oldpool: @buffer_size: @pool_size: @Returns: + +@oldpool: diff --git a/docs/gst/tmpl/gstdisksrc.sgml b/docs/gst/tmpl/gstdisksrc.sgml index a7d80b5896..1dae1ec21f 100644 --- a/docs/gst/tmpl/gstdisksrc.sgml +++ b/docs/gst/tmpl/gstdisksrc.sgml @@ -47,8 +47,8 @@ Specify how many bytes to read at a time. Get/set the current offset in the file. - + -Get the size of the file. + diff --git a/docs/gst/tmpl/gstelement.sgml b/docs/gst/tmpl/gstelement.sgml index 8136a4d3cb..496724a3a7 100644 --- a/docs/gst/tmpl/gstelement.sgml +++ b/docs/gst/tmpl/gstelement.sgml @@ -225,7 +225,7 @@ of the element, the GtkType value for it, as well as a pointer to the GstElementDetails struct for the element. -@name: +@feature: @type: @details: @padtemplates: @@ -241,14 +241,6 @@ circumstances. @element: The element in question. - - - - - -@Returns: - - @@ -503,14 +495,6 @@ circumstances. @Returns: - - - - - -@elementfactory: - - @@ -580,25 +564,6 @@ circumstances. @Returns: - - - - - -@factory: -@parent: -@Returns: - - - - - - - -@parent: -@Returns: - - Is trigered whenever the state of an element changes diff --git a/docs/gst/tmpl/gstfakesink.sgml b/docs/gst/tmpl/gstfakesink.sgml index 81869b93ee..1aac92d45a 100644 --- a/docs/gst/tmpl/gstfakesink.sgml +++ b/docs/gst/tmpl/gstfakesink.sgml @@ -24,7 +24,7 @@ with the buffer. (fakesink) @gstfakesink: the object which received the signal. @arg1: - + diff --git a/docs/gst/tmpl/gstfakesrc.sgml b/docs/gst/tmpl/gstfakesrc.sgml index 9da569925b..323cb0b00d 100644 --- a/docs/gst/tmpl/gstfakesrc.sgml +++ b/docs/gst/tmpl/gstfakesrc.sgml @@ -22,12 +22,12 @@ The GstFakeSrc generates empty buffers. (fakesrc) @gstfakesrc: the object which received the signal. @arg1: - + - + @@ -42,7 +42,7 @@ The GstFakeSrc generates empty buffers. (fakesrc) - + diff --git a/docs/gst/tmpl/gstidentity.sgml b/docs/gst/tmpl/gstidentity.sgml index c2309bb31e..70e5009b06 100644 --- a/docs/gst/tmpl/gstidentity.sgml +++ b/docs/gst/tmpl/gstidentity.sgml @@ -22,12 +22,12 @@ Pass data without modification. @gstidentity: the object which received the signal. @arg1: - + - + diff --git a/docs/gst/tmpl/gstobject.sgml b/docs/gst/tmpl/gstobject.sgml index 0698426108..6de54c918e 100644 --- a/docs/gst/tmpl/gstobject.sgml +++ b/docs/gst/tmpl/gstobject.sgml @@ -141,14 +141,6 @@ Check if the object has been destroyed. @obj: The Object to check - - - - - -@Returns: - - diff --git a/docs/gst/tmpl/gstpad.sgml b/docs/gst/tmpl/gstpad.sgml index 85814e86ea..3c62b9afbb 100644 --- a/docs/gst/tmpl/gstpad.sgml +++ b/docs/gst/tmpl/gstpad.sgml @@ -189,24 +189,6 @@ a start/stop timecode pair. @size: the size of the region to get - - -The function that will be called when a QoS message is sent. - - -@pad: the pad that sent the QoS message -@qos_message: the message - - - - -The function that will be called in an EOS case. - - -@pad: the pad that needs to be set to EOS state -@Returns: TRUE if EOS was successful, FALSE otherwise - - 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 - - - -The function that will be called when pushing a buffers. - - -@pad: the pad to push -@buf: a GstBuffer to push - - - - -The function that will be called when pulling buffers. - - -@pad: the pad to pull -@Returns: a GstBuffer - - the region types for #gst_pad_pullregion. @@ -383,24 +346,6 @@ Destroy the pad. @nego: - - - - - -@pad: -@qos: - - - - - - - -@pad: -@eos: - - @@ -627,32 +572,6 @@ Destroy the pad. @Returns: - - - - - -@pad: -@Returns: - - - - - - - -@pad: -@qos_message: - - - - -Call the EOS function of the pad - - -@pad: the pad to call the eos function of. - - @@ -706,15 +625,6 @@ Call the EOS function of the pad @Returns: - - - - - -@pad: -@Returns: - - @@ -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. - - -Get the pushfunction of the real pad. - - -@pad: the real pad to query. - - - - -Get the pullfunction of the real pad. - - -@pad: the real pad to query. - - 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. - - -Get the QoS function of the real pad. - - -@pad: the real pad to query. - - - - -Get the EOS function of the real pad. - - -@pad: the real pad to query. - - Get the negotiate function from the real pad. diff --git a/docs/gst/tmpl/gstplugin.sgml b/docs/gst/tmpl/gstplugin.sgml index 6d5d7bab6c..0668663d52 100644 --- a/docs/gst/tmpl/gstplugin.sgml +++ b/docs/gst/tmpl/gstplugin.sgml @@ -63,11 +63,9 @@ to bring it into memory. @name: @longname: @filename: -@types: -@numtypes: -@elements: -@numelements: -@numautopluggers: +@features: +@numfeatures: +@module: @@ -198,33 +196,6 @@ loaded will use this variable to initialize the plugin. @Returns: - - - - - -@plugin: -@factory: - - - - - - - -@plugin: -@factory: - - - - - - - -@plugin: -@factory: - - @@ -242,59 +213,6 @@ loaded will use this variable to initialize the plugin. @Returns: - - - - - -@plugin: -@Returns: - - - - - - - -@plugin: -@Returns: - - - - - - - -@plugin: -@Returns: - - - - - - - -@name: -@Returns: - - - - - - - -@mime: - - - - - - - -@name: -@Returns: - - diff --git a/docs/gst/tmpl/gstqueue.sgml b/docs/gst/tmpl/gstqueue.sgml index 923850a29b..afac6898d3 100644 --- a/docs/gst/tmpl/gstqueue.sgml +++ b/docs/gst/tmpl/gstqueue.sgml @@ -35,7 +35,7 @@ The queue blocks by default. Get the number of buffers in the queue. - + Specify the maximum number of buffers in the queue before the queue blocks. diff --git a/docs/gst/tmpl/gstreamer-unused.sgml b/docs/gst/tmpl/gstreamer-unused.sgml index 21d14bc6f9..55f641d0eb 100644 --- a/docs/gst/tmpl/gstreamer-unused.sgml +++ b/docs/gst/tmpl/gstreamer-unused.sgml @@ -1,232 +1,26 @@ - - - - - -@pad: -@buf: - - - -Query the element for the current mime type - - - - + - + - + + + + + +GstElement + + + - - - -@Returns: - - - - - - -@obj: - - - - - - -@meta: - - - - - - -@fromcaps: -@tocaps: -@Returns: - - - - - - -@obj: - - - - - - - - - - - - -@pad: -@parent: - - - - - - -@pad: -@buf: - - - - - - -@pad: -@buf: - - - - - - -@Returns: - - - - - - -@pad: -@buf: - - - - - - -@klass: - - - - - - -@elementfactory: -@id: - - - - - - - - - -The number of channels. - - - - - -Use this macro to show debugging info. This is only usefull when developing new -plugin elements. -If you #define DEBUG_ENABLED before including gst/gst.h, this macro will produce -g_print messages. - - -@format: the format specification as in g_print -@args...: arguments - - -GstEsdSink - - - - - - - - - - - - - -@type: -@parent: -@Returns: - - - - - - -@src: - - - - - - -@obj: - - - - - - - - - - - - -@obj: - - - -An eos signal is triggered whenever the GstSrc has reached the end of -the stream. - - - -@gstsrc: the object which received the signal. -@arg1: the object which received the signal - - - - - - - - - - - - -@Returns: - - - - - - -@obj: - - -Provide context for buffers - - - - - +Information about audio buffers. @@ -236,204 +30,36 @@ Provide context for buffers - - + +Information about audio buffers. + + +audioraw + + + + +Reads data from a file. You can seek to a specific location by setting +the offset. -@name_template: -@direction: -@presence: -@caps: -@Returns: - - - - - -@obj: - - + - + +GstAsyncDiskSrc + + + -@obj: - - - - - - -@name: -@Returns: - - - - - - -@klass: - - - - - - - - - - - - -@klass: - - - - - - -@pad: -@parent: -@Returns: - - - - - - -@obj: - - - - - - - - - -The filename to write to. - - - - - - - - -@obj: - - - -Specify how many bytes to read at a time. - - - - - - - - -@name: -@Returns: - - - - - - - - - - -@Returns: - - - - - - -@connection: - - - -subclass use this to start their flag enumeration - - - - - - - - -@audiosink: -@channels: - - -Generic connection between elements. - - - - - - - - - - - - - - - - - - - -@obj: - - - - - - -@bin: - - - - - - -@element: -@format: -@args...: - - - - - - -@meta: -@format: -@visual: -@width: -@height: -@overlay_info: -@dga_info: - - - - - - -@meta: @@ -441,942 +67,33 @@ Generic connection between elements. - - - - - -@obj: - - - - - - - - - - - - -@esdsink: -@channels: - - - - - - -@autoplug: -@srcpad: -@sinkpad: -@Varargs: -@Returns: -@srccaps: -@sinkcaps: - - - - - - -@obj: - - - -Specify wether the queue blocks or not. - - - - - - - - -@pad: -@offset: -@size: -@Returns: - - - - - - -@name: -@fd: -@Returns: - - - - - - -@obj: - - - - - - - - - - - - - - - - - - - - - - - - -@obj: - - - - - - -@pad: -@pull: - - - - - - - - - - - - -@Returns: - - - - - - -@obj: - - - - - - - - - - - - - - - - - - -@pad: -@caps: - - - -Create a fourcc property out of an integer value. - - -@a: the integer value - - - - - - - - - - - - -@format: -@args...: - - - - - - -@obj: - - - - - - -@Returns: - - - -Specify the current offset in the file. - - - - - - - - - - - - - - - - - - - - - - - - - - -@klass: - - - - - - -@nextpad: -@Varargs: -@Returns: - - - - - - -@Returns: - - - - - - - - - - - - - - - - - - -@meta: - - - - - - - - - - - - -@base: -@swidth: -@sheight: -@bytes_per_line: - - -spectrum - - - - - - - - - - - - - - - - - - - -@obj: - - - - - - -@klass: - - - - - - - - - - - - -@name: -@Returns: - - - - - - - - - - - - - - - - - - -@src: - - - - - - -@id: -@sink: - - - - - - -@obj: - - -GstGetbits - - - -audioraw - - - - - - - -@klass: - - - - - - -@name: -@Returns: - - - - - - -@element: -@parent: -@Returns: - - - - - - -@obj: - - - - - - -@sinkid: -@srcid: -@Returns: - - - - - - - - - - - - - - - - - - -@obj: - - - - - - -@id: -@Returns: - - - - - - -@esdsink: -@frequency: - - - - - - - - - - - - - - - - -@obj: - - - - - - -@obj: - - - - - - -@cat: -@format: -@args...: - - - - - - -@obj: - - - -The audio format as defined in soundcard.h - - - - - - - - -@obj: - - -GstAsyncDiskSrc - - - ->>>>>>> 1.23.2.3 - - - - - - - - - - -@elementfactory: -@id: - - - - - - -@bin: - - - - - - -@obj: - - - - - - - - - -The fequency. - - - - - - - - -@Returns: - - - - - - -@name: -@Returns: - - - - - - - - - - - - -@obj: - - - - - - - - - -The buffer is sent to the sound card. - - -@gstaudiosink: the object which received the signal. -@arg1: the audiosink. - - - - - - -@obj: - - - - - - -@obj: - - - - - - -@pad: -@buf: - - - - - - -@buffer: -@meta: - - - - - - -@factory: -@caps: -@Returns: - - - - - - -@pad: -@buf: - - - - - - - - - - - - -@buffer: -@meta: - - - - - - -@factory: -@counter: -@Returns: -@count: - - - - - - - - - - - - - - - - - - -@obj: - - - - - - -@obj: - - - - - - -@cat: -@element: -@format: -@args...: - - - - - - -@klass: - - - - - - - - - - - - -@id: -@src: - - - - - - - - - - - - -@obj: - - - - - - - - - - - - -@obj: - - - - - - -@klass: - - - - - - -@esdsink: - - - - - - -@connection: - - - -Is emited after the buffer has been written to the disk. - - -@gstdisksink: the object which received the signal. - - - - - - -@name: -@Returns: - - - - - - -@element: -@manager: - - - - - - -@obj: - - - - - - - - -GstFilter - - - - - - - -@obj: - - - - - - -@obj: - - - - - - -@Returns: - - - - - - -@pad: -@Returns: - - - - - - -@thread: - - - - - - -@x1: -@x2: -@y1: -@y2: - - - -Flags for the GstSrc element - - -@GST_SRC_ASYNC: Indicates that this src is asynchronous -@GST_SRC_FLAG_LAST: subclasses can use this to number their flags - - -GstColorSpace + +GstAudioSink - - -Defines an entry for a padfactory. - - - - - - - - - -GST_ASYNCDISKSRC_OPEN -the asyncdisksrc is open for reading - - - - - - -@GST_ASYNCDISKSRC_OPEN: -@GST_ASYNCDISKSRC_FLAG_LAST: - - + - - - - - -@element: -@state: -@Returns: - - - - - - -@pad: -@Returns: - - + - - - - - -@obj: - - - -subclasses can use this value to start the enumeration of their flags - + - -Frequencies of a spectrum analysis. + +GstAudioSrc - - - - - -@Returns: - - - - - - -@klass: - - - -Indicates a sinkpad for the padfactory. - - - - - - - - -@klass: @@ -1384,117 +101,24 @@ Indicates a sinkpad for the padfactory. - - - - - -@parent: -@Returns: - - - - - - -@pad: -@Returns: - - + - - - - - -@name: -@Returns: - - - -Retrieve the flags of the given meta information. - - -@meta: the meta information - - - - - - -@element: -@templ: -@Returns: -@temp: - - - - - - -@obj: - - -The end point of a filter graph - - - - - - - -@meta: -@format: -@channels: -@frequency: -@bps: - - - -The number of channels (mono, stereo, ...) - - - - - - - - - - - -This macro checks to see if the given state is set. - - -@obj: Element to check for state. -@flag: State to check for, must be a single bit in guint32. - - - - - - -@lock: for locking purposes -@flags: the flags of the meta data -@data: the meta data -@size: the size of the meta data - - - - - - -@buffer: -@size: -@root: -@Returns: - - + + + + + +GstColorSpace + + + +A connection is a bas class for a generic connection between +elements. A connection is typically a bas class for queues. @@ -1505,347 +129,76 @@ This macro checks to see if the given state is set. - - - - - -@name: -@Returns: - - - - - - -@obj: - - -GstAudioSink + +Generic connection between elements. - - + +GstConnection - -@obj: - - - -This macro sets the given flags. - - -@src: -@flag: Flag to set, can by any number of bits in guint32. -@obj: GstSrc to set flag in. - - - -Retrieves the type id of the data in the buffer. - - -@buf: GstBuffer - - - - - - -@a: - - + - - - - - -@Returns: - - - - - - -@name: -@Returns: - - + - -GstSink + - + + +GstEsdSink + + + -A flag indicating that MMX instructions are supported. +Filters take data in and spit data out. They are the main Element in a filter graph. +Filters have zero or more inputs and zero or more outputs. Filters are connected +together to form filter graphs. A GstFilter is the base class and is not very usefull +on its own. - - - - - -@Returns: - - + - - - - - -@factory: -@caps: -@Returns: - - - -This macro usets the given flags. - - -@src: -@flag: Flag to set, must be a single bit in guint32. -@obj: GstSrc to unset flag in. - - - -The frequency. - + +Take data in and spit data out - - -Indicates a srcpad for the padfactory. - + +GstFilter - + - - - - - -@buffer: -@Returns: - - - - - - -@obj: - - - - - - -@obj: - - + - - + - - - + +GstGetbits - - - - - - - - - - - - - - -@pad: -@name: -@Returns: - - - - - - - - - - - - -@esdsink: -@format: - - - - - - -@cat: -@format: -@args...: - - - - - - - - - - - - -@obj: - - - - - - - - - - - - -@Returns: - - - - - - -@obj: - - - - - - -@obj: - - - -The maximum number of cothreads we are going to support. - - - - - - - - -@name: -@Returns: - - - -Starts the declaration of a the capabilities for this padtemplate. - - -@a...: a capability factory - - -GstSrc - - - - - - - -@pad: -@Returns: - - - - - - -@pad: -@buf: - - - - - - -@name: -@mime: -@props: -@Returns: - - - -The Element is going from the READY state to the PLAYING state. - - - - - - - - - - - - - - - - - - - - - - - - - - -@obj: - - - - - - -@arg: @@ -1946,95 +299,18 @@ it, is there? - -GstConnection - - - + - - - - + +Provide context for buffers - - - - - - - - - - - - - - - - - - - - - - - - - - - -@obj: - - -GstElement - - - - - - - -@id: -@Returns: - - - - - - -@buf: - - - - - - - - - -Clear a flag in the meta data. - - -@meta: the meta data -@flag: the flag to clear - - - - - - -@obj: - - - - - + +GstMeta @@ -2045,41 +321,149 @@ or a video card. - - - - - -@obj: - - - - - - -@Returns: - - + - + +The end point of a filter graph + + + +GstSink + + + + +A GstSrc is the start of a filter graph. It typically is a file or an +audio source. It provides data for the next element in the graph. + + + + + - + +The start point of a filter graph + + + +GstSrc + + + -Query whether this object has multiple input pads. -@obj: Element to query for multiple input pads. - + + + + + + + + + + + +plugin + + + + +Frequencies of a spectrum analysis. + + + + + + + + + + + +Frequencies of a spectrum analysis. + + + +spectrum + + + + +Information about video buffers. + + + + + + + + + + +Information about video buffers. + + + +videoraw + + + + +The maximum number of cothreads we are going to support. + + + + + +The default stack size of a cothread. + + + + + +Use this macro to show debugging info. This is only usefull when developing new +plugin elements. +If you #define DEBUG_ENABLED before including gst/gst.h, this macro will produce +g_print messages. + + +@format: the format specification as in g_print +@args...: arguments + + + + + + +@format: +@args...: + + + + + + + + + + + + +@format: +@args...: + + @@ -2093,97 +477,111 @@ Query whether this object has multiple input pads. @format: @args...: - + +@format: +@args...: - + - - - - - - -@factory: -@Returns: - - - - - - - - - - - - -@self: -@parent: -@Returns: -@elements: - - - - - - -@src: - - - - - - - - - - - - - - - -Information about video buffers. - - - - - - - - -@bin: @element: +@format: +@args...: - + -@name: -@Returns: +@element: +@object: +@format: +@args...: - + + + + + +@obj: + + @klass: - + +@obj: - + + + + + +@klass: + + + + + + +@obj: + + + + + + +@klass: + + + + + + +@obj: + + + + + + +@klass: + + + + + + +@buf: + + + + + + +@buf: + + + +Retrieves the type id of the data in the buffer. + + +@buf: GstBuffer + + @@ -2197,100 +595,17 @@ Information about video buffers. @klass: - + - +A flag indicating that MMX instructions are supported. - + - +A flag indicating that SSE instructions are supported. -@name: -@Returns: - - - - - - -@obj: - - - - - - -@klass: - - - - - - - - - - - - - - - - -@Returns: - - - - - - - - - - - - -@obj: - - - -Filters take data in and spit data out. They are the main Element in a filter graph. -Filters have zero or more inputs and zero or more outputs. Filters are connected -together to form filter graphs. A GstFilter is the base class and is not very usefull -on its own. - - - - - - - - -@tee: -@Returns: - - - - - - -@obj: - - - -The Element is going from the PLAYING state to the READY state. - - - - - - - - -@obj: @@ -2298,7 +613,90 @@ Combine #GST_DEBUG_ENTER and #GST_DEBUG_SET_STRING. - + + + + + + + + + + + +@cat: +@format: +@args...: + + + + + + +@cat: +@format: +@args...: + + + +Set the debug string for the current function, typically containing the arguments +to the current function, i.e. "('element')" + + +@format: printf-style format string +@args...: printf arguments + + + + + + +@obj: + + + + + + +@klass: + + + + + + +@obj: + + + + + + +@klass: + + + +Query whether this object has multiple input pads. + + + +@obj: Element to query for multiple input pads. + + + + + + +@obj: + + + + + + +@klass: <<<<<<< gstreamer-unused.sgml + + @@ -2312,19 +710,264 @@ Combine #GST_DEBUG_ENTER and #GST_DEBUG_SET_STRING. @klass: - + +@obj: - + + + + + +@klass: + + + + + + +@obj: + + + + + + +@klass: + + + + + + +@obj: + + + + + + +@klass: + + + + + + +@obj: + + + + + + +@klass: + + + +subclass use this to start their flag enumeration + + +>>>>>>> 1.23.2.3 + - -videoraw + +@obj: + + + + + + +@klass: + + + + + + +@obj: + + + + + + +@klass: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: @@ -2333,6 +976,1348 @@ videoraw @obj: + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@obj: + + + + + + +@meta: + + + +Retrieve the flags of the given meta information. + + +@meta: the meta information + + + +Check if a given flag is set. + + +@meta: the meta data to test +@flag: the flag to test + + + +Set a flag in the meta data. + + +@meta: the meta data +@flag: the flag to set + + + +Clear a flag in the meta data. + + +@meta: the meta data +@flag: the flag to clear + + + + + + +@obj: + + + + + + +@klass: + + + +subclasses can use this value to start the enumeration of their flags + + + + + + + + +@obj: + + + + + + +@klass: + + + +Indicate that this pad will always be available. +Use this in the factory definition. + + + + + +Starts the declaration of a the capabilities for this padtemplate. + + +@a...: a capability factory + + + +Indicates that this pad will be available on request. Use +this in the factory definition. + + + + + +Indicates a sinkpad for the padfactory. + + + + + +Indicate that this pad will become available depending +on the media type. Use this in the factory definition. + + + + + +Indicates a srcpad for the padfactory. + + + + + + + + +@obj: + + + + + + +@klass: + + + + + + + + + + + + +@a: +@b: + + + + + + +@a: + + + + + + + + + +Create a fourcc property out of an integer value. + + +@a: the integer value + + + + + + + + + + + + + + + + + + + + + + + + +@obj: + + + + + + +@klass: + + + +Get the EOS function of the real pad. + + +@pad: the real pad to query. + + + +Get the pullfunction of the real pad. + + +@pad: the real pad to query. + + + +Get the pushfunction of the real pad. + + +@pad: the real pad to query. + + + +Get the QoS function of the real pad. + + +@pad: the real pad to query. + + + + + + +@obj: + + + + + + +@klass: + + + + + + +@obj: + + + + + + +@klass: + + + + + + + + + + + + +@obj: + + + +This macro checks to see if the GST_SRC_ASYNC flag is set. + + +@obj: GstSrc to check for flag in. + + + + + + +@klass: + + + +This macro returns the entire set of flags for the object. + + +@obj: GstSrc to return flags for. + + + +Query a GstSrc for the ASYNC flag + + +@obj: The GstSrc to query + + + +This macro sets the given flags. + + +@src: +@flag: Flag to set, can by any number of bits in guint32. +@obj: GstSrc to set flag in. + + + +This macro usets the given flags. + + +@src: +@flag: Flag to set, must be a single bit in guint32. +@obj: GstSrc to unset flag in. + + + +This macro checks to see if the given state is set. + + +@obj: Element to check for state. +@flag: State to check for, must be a single bit in guint32. + + + +The Element is going from the PLAYING state to the READY state. + + + + + +The Element is going from the READY state to the PLAYING state. + + + + + +This macro sets the given state on the element. + + +@obj: Element to set state of. +@flag: State to set, can be any number of bits in guint32. + + + +This macro unsets the given state on the element. + + +@obj: Element to unset state of. +@flag: State to unset, can be any number of bits in guint32. + + + + + + +@obj: + + + + + + +@klass: + + + + + + +@obj: + + + + + + +@klass: + + +>>>>>>> 1.23.2.3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Specify how many bytes to read at a time. + + + + + +Get the size of the current file. + + + + + +Specify the location of the file to read. + + + + + +Specify the current offset in the file. + + + + + + + + + + + + + + + + + + + + + +GST_ASYNCDISKSRC_OPEN +the asyncdisksrc is open for reading + + + + + + +@GST_ASYNCDISKSRC_OPEN: +@GST_ASYNCDISKSRC_FLAG_LAST: + + + + + + + + + +The buffer is sent to the sound card. + + +@gstaudiosink: the object which received the signal. +@arg1: the audiosink. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +The number of bytes per read. + + + + + +The number of channels (mono, stereo, ...) + + + + + +Get the current number of bytes read. + + + + + +The audio format as defined in soundcard.h + + + + + +The frequency. + + + + + + + + + + + + + + + + + +The function called when a buffer has to be created for this pool. + + +@pool: the pool from which to create the buffer +@user_data: any user data +@Returns: a new buffer from the pool + + + +This function will be called when the given buffer has to be returned to +the pool. + + +@pool: the pool to return the buffer to +@buffer: the buffer to return +@user_data: any user data + + + + + + +@GST_CAPS_ALWAYS: +@GST_CAPS_MAYBE: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Is emited after the buffer has been written to the disk. + + +@gstdisksink: the object which received the signal. + + + + + + + + + +The filename to write to. + + + + + + + + + + + +Get the size of the file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +@lock: for locking purposes +@flags: the flags of the meta data +@data: the meta data +@size: the size of the meta data + + + +Flags indicating properties about the meta data. + + +@GST_META_FREEABLE: the meta data can be freed + + + + + + + + + +Indicates this pad is active + + + + + + + + + +<<<<<<< gstreamer-unused.sgml + + + + +The function that will be called in an EOS case. + + +@pad: the pad that needs to be set to EOS state +@Returns: TRUE if EOS was successful, FALSE otherwise + + + +Defines an entry for a padfactory. + + + + + +The padfactory. + + + + + +The function that will be called when pulling buffers. + + +@pad: the pad to pull +@Returns: a GstBuffer + + + + +The function that will be called when pushing a buffers. + + +@pad: the pad to push +@buf: a GstBuffer to push + + + +The function that will be called when a QoS message is sent. + + +@pad: the pad that sent the QoS message +@qos_message: the message + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +@GST_PROPS_END_ID_NUM: +@GST_PROPS_LIST_ID_NUM: +@GST_PROPS_INT_ID_NUM: +@GST_PROPS_INT_RANGE_ID_NUM: +@GST_PROPS_FOURCC_ID_NUM: +@GST_PROPS_BOOL_ID_NUM: + + + + + + + + + + + + + + + +Specify wether the queue blocks or not. + + + + + + + + + + + + + + + + + + + + + + + +The number of channels. + + + + + +The fequency. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +An eos signal is triggered whenever the GstSrc has reached the end of +the stream. + + + +@gstsrc: the object which received the signal. +@arg1: the object which received the signal + + + + + + + + + +Flags for the GstSrc element + + +@GST_SRC_ASYNC: Indicates that this src is asynchronous +@GST_SRC_FLAG_LAST: subclasses can use this to number their flags + + + + + + + + + + + + + + + + + + + + + +Query the element for the current mime type + + + + + +Is trigered whenever the state of an element changes + + +@gstelement: the object which received the signal. +@arg1: the new state of the object + + + + + + +@cat: +@format: +@args...: + + + + + + +@cat: +@element: +@format: +@args...: + + + + + + +@meta: +@format: +@channels: +@frequency: +@bps: + + + + + + +@meta: +@bands: +@channels: +@interleaved: +@lowfreq: +@highfreq: +@steps: + + + + + + +@base: +@swidth: +@sheight: +@bytes_per_line: + @@ -2348,13 +2333,58 @@ videoraw @did_overlay: @fully_obscured: - + + + + + +@meta: +@format: +@visual: +@width: +@height: +@overlay_info: +@dga_info: + + + + + + +@x1: +@x2: +@y1: +@y2: + + - + + + + + +@Returns: + + + + + + +@pad: +@buf: + + + + + + +@Returns: + + @@ -2362,247 +2392,21 @@ videoraw @name: @Returns: - - - - - -@obj: - - - - - - - - - - - - -@obj: - - - - - - -@klass: - - - - - - - - - - - - -@obj: - - - -This macro returns the entire set of flags for the object. - - -@obj: GstSrc to return flags for. - - - - - - - - - -Get the size of the current file. - - - - - - - - -The start point of a filter graph - - - - - - - -@src: - - - - - - -@obj: - - - - - - -@src: - - - - - - -@bin: - - - - - - -@factory: -@counter: -@Returns: - - - - - - - - - - - - -@a: -@b: - - - - - - -@klass: - - - - - - - - - -The default stack size of a cothread. - - - - - - - - - - - - - - - - - - - - - - - - - - -@Returns: - - - - - - -@Returns: - - - - - - -@klass: - - - - - - -@klass: <<<<<<< gstreamer-unused.sgml - - - -Indicates that this pad will be available on request. Use -this in the factory definition. - - - - + @audiosink: +@channels: - + -@obj: - - - -This macro unsets the given state on the element. - - -@obj: Element to unset state of. -@flag: State to unset, can be any number of bits in guint32. - - - - - - -@klass: - - - - - - -@pad: -@id: - - - -Indicate that this pad will always be available. -Use this in the factory definition. - - - - - - - - -@pad: -@parent: +@audiosink: +@format: @@ -2612,232 +2416,21 @@ Use this in the factory definition. @audiosink: @frequency: - + +@audiosink: - - - - - -@elementfactory: - - - -The number of bytes per read. - - - - - - - -@argc: -@argv: -@Returns: - - - - - - -@obj: - - - - - - -@size: -@Returns: - - - - - - -@element: -@object: -@format: -@args...: - - + @Returns: - - - - - -@obj: - - - - - - -@obj: - - - - - - - - - - - - -@obj: - - - - - - - - - - - - -@Returns: - - - - - - -@klass: - - - -A connection is a bas class for a generic connection between -elements. A connection is typically a bas class for queues. - - - - - - - - - -@buf: - - - -Query a GstSrc for the ASYNC flag - - -@obj: The GstSrc to query - - - - - - -@obj: - - - -This macro sets the given state on the element. - - -@obj: Element to set state of. -@flag: State to set, can be any number of bits in guint32. - - - - - - -@Returns: - - - - - - - - - -Flags indicating properties about the meta data. - - -@GST_META_FREEABLE: the meta data can be freed - - - - - - - - - - - - -@obj: - - -Information about video buffers. - - - - - - - -@Returns: - - - - - - -@src: -@offset: -@size: - - - - - - - - - - - - -@format: -@args...: - - - -Is trigered whenever the state of an element changes - - -@gstelement: the object which received the signal. -@arg1: the new state of the object - - - - - - -@klass: - - + @@ -2845,112 +2438,59 @@ Is trigered whenever the state of an element changes @name: @Returns: - + +@src: + + + + + + +@autoplug: +@srcpad: +@sinkpad: +@Varargs: +@Returns: +@srccaps: +@sinkcaps: + + + + + + +@parent: @Returns: - -Information about audio buffers. - - - + - - -Take data in and spit data out - - - - -The padfactory. - - - - - -This macro checks to see if the GST_SRC_ASYNC flag is set. - - -@obj: GstSrc to check for flag in. - - - - - - - - - - - - - - -GstMeta - - - - - - - - - - - - - - - - -A flag indicating that SSE instructions are supported. - - - - - - - - -@obj: - - - - - - -@object: -@argname: +@factory: +@parent: @Returns: - + +@bin: +@element: - + +@bin: - - -Set the debug string for the current function, typically containing the arguments -to the current function, i.e. "('element')" - - -@format: printf-style format string -@args...: printf arguments - - + @@ -2965,196 +2505,44 @@ to the current function, i.e. "('element')" @bin: @element: - + +@bin: - - -Set a flag in the meta data. - - -@meta: the meta data -@flag: the flag to set - - + -@obj: +@bin: - - -Information about audio buffers. - - - - + -@GST_PROPS_END_ID_NUM: -@GST_PROPS_LIST_ID_NUM: -@GST_PROPS_INT_ID_NUM: -@GST_PROPS_INT_RANGE_ID_NUM: -@GST_PROPS_FOURCC_ID_NUM: -@GST_PROPS_BOOL_ID_NUM: +@element: +@manager: - + -@GST_CAPS_ALWAYS: -@GST_CAPS_MAYBE: +@buffer: +@meta: - - -Check if a given flag is set. - - -@meta: the meta data to test -@flag: the flag to test - - + - -<<<<<<< gstreamer-unused.sgml - - - - - - - - - ->>>>>>> 1.23.2.3 - - - - -@obj: - - - - - - - - - -Create new meta data. - - -@type: the type of the meta data to create - - - - - - - - - - - - -@factory: +@buffer: @Returns: - - -Specify the location of the file to read. - - - - - - - - -@klass: - - - - - - -@Returns: - - - - - - -@format: -@args...: - - - - - - -@audiosink: -@format: - - - -Frequencies of a spectrum analysis. - - - - - -GstAudioSrc - - - - -Indicate that this pad will become available depending -on the media type. Use this in the factory definition. - - - - - - - - -@cat: -@format: -@args...: - - - -Reads data from a file. You can seek to a specific location by setting -the offset. - - - - - - - - -@name: -@Returns: - - - - - - -@obj: - @@ -3163,11 +2551,693 @@ the offset. @buffer: @Returns: - + -Get the current number of bytes read. + +@pool: +@buffer: + + + + + + +@pool: +@Returns: + + + + + + +@pool: +@create: +@user_data: + + + + + + +@pool: +@destroy: +@user_data: + + + + + + +@buffer: +@meta: + + + + + + +@fromcaps: +@tocaps: +@Returns: + + + + + + +@name: +@mime: +@props: +@Returns: + + + + + + +@factory: +@Returns: + + + + + + +@factory: +@counter: +@Returns: +@count: + + + + + + +@Returns: + + + + + + +@name: +@Returns: + + + + + + +@connection: + + + + + + +@Returns: + + + + + + +@element: +@state: +@Returns: + + + + + + +@Returns: + + + + + + +@self: +@parent: +@Returns: +@elements: + + + + + +@argc: +@argv: +@Returns: + + + + + + +@Returns: + + + + + + +@element: +@templ: +@Returns: +@temp: + + + + + + +@element: +@parent: +@Returns: + + + + + + +@elementfactory: +@id: + + + + + + +@elementfactory: +@id: + + + + + + +@factory: +@caps: +@Returns: + + + + + + +@factory: +@caps: +@Returns: + + + + + + +@elementfactory: + + + + + + +@parent: +@Returns: + + + + + + +@elementfactory: + + + + + + +@factory: +@parent: +@Returns: + + + + + + +@pad: +@buf: + + + + + + +@Returns: + + + + + + +@name: +@Returns: + + + + + + +@esdsink: +@channels: + + + + + + +@esdsink: +@format: + + + + + + +@esdsink: +@frequency: + + + + + + +@esdsink: + + + + + + +@pad: +@buf: + + + + + + +@Returns: + + + + + + +@name: +@Returns: + + + + + + +@Returns: + + + + + + +@name: +@Returns: + + + + + + +@src: + + + + + + +@pad: +@buf: + + + + + + +@Returns: + + + + + + +@name: +@Returns: + + + + + + +@name: +@fd: +@Returns: + + + + + + +@Returns: + + + + + + +@Returns: + + + + + + +@name: +@Returns: + + + + + + +@Returns: + + + + + + +@pad: +@buf: + + + + + + +@Returns: + + + + + + +@name: +@Returns: + + + +Create new meta data. + + +@type: the type of the meta data to create + + + + + + +@size: +@Returns: + + + + + + +@meta: + + + + + + +@meta: + + + + + + +@Returns: + + + + + + +@Returns: + + + + + + +@pad: +@parent: + + + +Call the EOS function of the pad + + +@pad: the pad to call the eos function of. + + + + + + +@pad: +@Returns: + + + + + + +@pad: +@name: +@Returns: + + + + + + +@pad: +@Returns: + + + + + + +@pad: +@Returns: + + + + + + +@pad: +@Returns: + + + + + + +@Returns: + + + + + + +@pad: +@Returns: + + + + + + +@pad: +@qos_message: + + + + + + +@pad: +@offset: +@size: +@Returns: + + + + + + +@pad: +@parent: + + + + + + +@pad: +@parent: +@Returns: + + + + + + +@nextpad: +@Varargs: +@Returns: + + + + + + +@pad: +@caps: + + + + + + +@pad: +@Returns: + + + + + + +@pad: +@eos: + + + + + + +@pad: +@pull: + + + + + + +@pad: +@qos: + + + + + + +@pad: +@id: + + + + + + +@name_template: +@direction: +@presence: +@caps: +@Returns: + + + + + + +@Returns: + + + + + + +@plugin: +@factory: + + + + + + +@plugin: +@factory: + + + + + + +@plugin: +@factory: + + + + + + +@plugin: +@Returns: + + + + + + +@plugin: +@Returns: + + + + + + +@plugin: +@Returns: @@ -3175,35 +3245,210 @@ Get the current number of bytes read. - + -@meta: -@bands: -@channels: -@interleaved: -@lowfreq: -@highfreq: -@steps: +@name: +@Returns: - -plugin - - - + -@obj: +@name: +@Returns: - + +@mime: + + + + + + +@factory: +@Returns: + + + + + + +@factory: +@counter: +@Returns: + + + + + + +@pad: +@buf: + + + + + + +@Returns: + + + + + + +@name: +@Returns: + + + + + + +@connection: + + + + + + +@Returns: + + + + + + +@name: +@Returns: + + + + + + +@src: + + + + + + +@Returns: + + + + + + +@name: +@Returns: + + + + + + +@Returns: + + + + + + +@src: + + + + + + +@src: +@offset: +@size: + + + + + + +@src: + + + + + + +@pad: +@buf: + + + + + + +@Returns: + + + + + + +@name: +@Returns: + + + + + + +@tee: +@Returns: + + + + + + +@Returns: + + + + + + +@thread: + + + + + + +@arg: + + + + + + +@id: +@sink: + + + + + + +@id: +@src: @@ -3211,49 +3456,114 @@ plugin - + + + + + +@sinkid: +@srcid: +@Returns: + + + + + + +@id: +@Returns: + + + + + + +@id: +@Returns: + + - + -@klass: +@parent: +@Returns: - + -@klass: +@type: +@parent: +@Returns: - + -@obj: +@parent: +@Returns: - + -Indicates this pad is active + +@factory: +@parent: +@Returns: - + + + + + +@object: +@argname: +@Returns: + + + + + + +@buffer: +@size: +@root: +@Returns: + + - + + + + + +@name: +@Returns: + + + + + + +@name: +@Returns: + + -A GstSrc is the start of a filter graph. It typically is a file or an -audio source. It provides data for the next element in the graph. diff --git a/docs/gst/tmpl/gsttee.sgml b/docs/gst/tmpl/gsttee.sgml index 31527214b3..972d8244fe 100644 --- a/docs/gst/tmpl/gsttee.sgml +++ b/docs/gst/tmpl/gsttee.sgml @@ -14,7 +14,7 @@ A tee can be used to split out the filter graph. - + diff --git a/docs/gst/tmpl/gstthread.sgml b/docs/gst/tmpl/gstthread.sgml index bc4f3af839..29151cb704 100644 --- a/docs/gst/tmpl/gstthread.sgml +++ b/docs/gst/tmpl/gstthread.sgml @@ -45,7 +45,7 @@ Thread flags: @Returns: - + TRUE if the thread should be created. diff --git a/docs/gst/tmpl/gsttype.sgml b/docs/gst/tmpl/gsttype.sgml index 472d244f44..9b2ec82daa 100644 --- a/docs/gst/tmpl/gsttype.sgml +++ b/docs/gst/tmpl/gsttype.sgml @@ -71,13 +71,14 @@ A type. @id: @mime: @exts: -@typefindfuncs: +@factories: The struct with the typefactory information. +@feature: @mime: @exts: @typefindfunc: @@ -126,22 +127,3 @@ The struct with the typefactory information. @Returns: - - - - - -@parent: -@Returns: - - - - - - - -@factory: -@parent: -@Returns: - - diff --git a/docs/random/wtay/events b/docs/random/wtay/events index 2e9b7c5a50..5498a68faa 100644 --- a/docs/random/wtay/events +++ b/docs/random/wtay/events @@ -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; -} - - diff --git a/docs/random/wtay/events2 b/docs/random/wtay/events2 new file mode 100644 index 0000000000..2e9b7c5a50 --- /dev/null +++ b/docs/random/wtay/events2 @@ -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; +} + + diff --git a/editor/gsteditorproject.c b/editor/gsteditorproject.c index 867972de00..e21b563c29 100644 --- a/editor/gsteditorproject.c +++ b/editor/gsteditorproject.c @@ -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); } diff --git a/examples/Makefile.am b/examples/Makefile.am index 6fe9c9c70b..b81c1568f7 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -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 \ diff --git a/examples/autoplug/autoplug.c b/examples/autoplug/autoplug.c index 550b182530..9de5ba56f2 100644 --- a/examples/autoplug/autoplug.c +++ b/examples/autoplug/autoplug.c @@ -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 diff --git a/examples/mixer/mixer.c b/examples/mixer/mixer.c index 0edbfa539f..7a02eddcb4 100644 --- a/examples/mixer/mixer.c +++ b/examples/mixer/mixer.c @@ -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); diff --git a/gst/Makefile.am b/gst/Makefile.am index 640288224a..6e7583219a 100644 --- a/gst/Makefile.am +++ b/gst/Makefile.am @@ -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) diff --git a/gst/autoplug/gstautoplugger.c b/gst/autoplug/gstautoplugger.c index 68ed930915..6138ff3657 100644 --- a/gst/autoplug/gstautoplugger.c +++ b/gst/autoplug/gstautoplugger.c @@ -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"); } diff --git a/gst/elements/Makefile.am b/gst/elements/Makefile.am index 61c5ad7c16..f50e4f75b4 100644 --- a/gst/elements/Makefile.am +++ b/gst/elements/Makefile.am @@ -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) diff --git a/gst/elements/gstaggregator.c b/gst/elements/gstaggregator.c index eb6c3013d9..49ec28f167 100644 --- a/gst/elements/gstaggregator.c +++ b/gst/elements/gstaggregator.c @@ -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; diff --git a/gst/elements/gstdisksrc.c b/gst/elements/gstdisksrc.c index ab13968eb9..ffe1b352e1 100644 --- a/gst/elements/gstdisksrc.c +++ b/gst/elements/gstdisksrc.c @@ -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) diff --git a/gst/elements/gstdisksrc.h b/gst/elements/gstdisksrc.h index 155a362c2d..4591254734 100644 --- a/gst/elements/gstdisksrc.h +++ b/gst/elements/gstdisksrc.h @@ -64,6 +64,7 @@ struct _GstDiskSrc { gchar *filename; /* fd */ gint fd; + GstBufferPool *bufferpool; /* mapping parameters */ gulong size; /* how long is the file? */ diff --git a/gst/elements/gstfakesink.c b/gst/elements/gstfakesink.c index 11eac007d1..02eb921fa3 100644 --- a/gst/elements/gstfakesink.c +++ b/gst/elements/gstfakesink.c @@ -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"); - } -} diff --git a/gst/elements/gstfakesink.h b/gst/elements/gstfakesink.h index cafc18b87c..85aa9fbdb7 100644 --- a/gst/elements/gstfakesink.h +++ b/gst/elements/gstfakesink.h @@ -57,6 +57,7 @@ struct _GstFakeSink { GSList *sinkpads; gint numsinkpads; gboolean silent; + gboolean dump; }; struct _GstFakeSinkClass { diff --git a/gst/elements/gstfakesrc.c b/gst/elements/gstfakesrc.c index d946529434..bed56e486f 100644 --- a/gst/elements/gstfakesrc.c +++ b/gst/elements/gstfakesrc.c @@ -21,6 +21,9 @@ */ +#include +#include + #include @@ -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) { diff --git a/gst/elements/gstfakesrc.h b/gst/elements/gstfakesrc.h index ce5c2a9439..550015b2af 100644 --- a/gst/elements/gstfakesrc.h +++ b/gst/elements/gstfakesrc.h @@ -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 { diff --git a/gst/elements/gstfilesrc.c b/gst/elements/gstfilesrc.c index 36214941e1..f53548f328 100644 --- a/gst/elements/gstfilesrc.c +++ b/gst/elements/gstfilesrc.c @@ -27,6 +27,7 @@ #include #include #include +#include /********************************************************************** @@ -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,®ion); + map = g_tree_search (src->map_regions, + (GCompareFunc) gst_filesrc_search_region_match, + ®ion); // 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; } diff --git a/gst/elements/gstsinesrc.c b/gst/elements/gstsinesrc.c new file mode 100644 index 0000000000..75ca6ba3b9 --- /dev/null +++ b/gst/elements/gstsinesrc.c @@ -0,0 +1,452 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * 2001 Steve Baker + * + * 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 +#include +#include + +#include + + +GstElementDetails gst_sinesrc_details = { + "Sine-wave src", + "Source/Audio", + "Create a sine wave of a given frequency and volume", + VERSION, + "Erik Walthinsen ", + "(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; +} diff --git a/gst/elements/gstsinesrc.h b/gst/elements/gstsinesrc.h new file mode 100644 index 0000000000..58e03fd72b --- /dev/null +++ b/gst/elements/gstsinesrc.h @@ -0,0 +1,96 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * 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 +#include + +#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__ */ diff --git a/gst/elements/gsttee.c b/gst/elements/gsttee.c index 729b95ec03..d7e0544bb0 100644 --- a/gst/elements/gsttee.c +++ b/gst/elements/gsttee.c @@ -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; diff --git a/gst/gobject2gtk.c b/gst/gobject2gtk.c index c53aa366ad..72165d39c8 100644 --- a/gst/gobject2gtk.c +++ b/gst/gobject2gtk.c @@ -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; } - diff --git a/gst/gobject2gtk.h b/gst/gobject2gtk.h index 309fe97b0a..6201c12a78 100644 --- a/gst/gobject2gtk.h +++ b/gst/gobject2gtk.h @@ -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 diff --git a/gst/gst.c b/gst/gst.c index d3a9f63f5a..8ecacbacfc 100644 --- a/gst/gst.c +++ b/gst/gst.c @@ -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; +} + diff --git a/gst/gst.h b/gst/gst.h index 2addc92658..032d5d2c57 100644 --- a/gst/gst.h +++ b/gst/gst.h @@ -50,6 +50,7 @@ #include #include #include +#include #include #include diff --git a/gst/gstautoplug.c b/gst/gstautoplug.c index af6a29f94e..612cd4b9ce 100644 --- a/gst/gstautoplug.c +++ b/gst/gstautoplug.c @@ -21,6 +21,9 @@ */ //#define GST_DEBUG_ENABLED + +#include + #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 */ diff --git a/gst/gstbin.c b/gst/gstbin.c index 1b97b98a5b..4396fe3da4 100644 --- a/gst/gstbin.c +++ b/gst/gstbin.c @@ -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 */ /** diff --git a/gst/gstbuffer.c b/gst/gstbuffer.c index fc61d55907..c330b2e1ce 100644 --- a/gst/gstbuffer.c +++ b/gst/gstbuffer.c @@ -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); } diff --git a/gst/gstbuffer.h b/gst/gstbuffer.h index 269bf3ee0e..9eef49c8d0 100644 --- a/gst/gstbuffer.h +++ b/gst/gstbuffer.h @@ -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 #include #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 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 */ diff --git a/gst/gstbufferpool.c b/gst/gstbufferpool.c index c742be0335..d04c8a22e3 100644 --- a/gst/gstbufferpool.c +++ b/gst/gstbufferpool.c @@ -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); diff --git a/gst/gstcaps.c b/gst/gstcaps.c index ddb75ad500..19f68c53b1 100644 --- a/gst/gstcaps.c +++ b/gst/gstcaps.c @@ -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 */ diff --git a/gst/gstcaps.h b/gst/gstcaps.h index 87482751be..77a8767d98 100644 --- a/gst/gstcaps.h +++ b/gst/gstcaps.h @@ -24,14 +24,7 @@ #ifndef __GST_CAPS_H__ #define __GST_CAPS_H__ -#include // 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 #include @@ -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__ */ diff --git a/gst/gstconfig.h b/gst/gstconfig.h new file mode 100644 index 0000000000..844c2df8a2 --- /dev/null +++ b/gst/gstconfig.h @@ -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 + + // 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__ */ diff --git a/gst/gstdata.h b/gst/gstdata.h new file mode 100644 index 0000000000..198ae7e822 --- /dev/null +++ b/gst/gstdata.h @@ -0,0 +1,46 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * 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 + +#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__ */ diff --git a/gst/gstelement.c b/gst/gstelement.c index e945f406b3..332c91be6e 100644 --- a/gst/gstelement.c +++ b/gst/gstelement.c @@ -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: diff --git a/gst/gstelement.h b/gst/gstelement.h index 22d218b8e5..1d05451878 100644 --- a/gst/gstelement.h +++ b/gst/gstelement.h @@ -24,14 +24,7 @@ #ifndef __GST_ELEMENT_H__ #define __GST_ELEMENT_H__ -#include // 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 #include #include @@ -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; diff --git a/gst/gstelementfactory.c b/gst/gstelementfactory.c index 8ecc553db5..0f4dde38c0 100644 --- a/gst/gstelementfactory.c +++ b/gst/gstelementfactory.c @@ -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); diff --git a/gst/gstevent.c b/gst/gstevent.c new file mode 100644 index 0000000000..10aa9c3ca0 --- /dev/null +++ b/gst/gstevent.c @@ -0,0 +1,96 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * 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; +} diff --git a/gst/gstevent.h b/gst/gstevent.h index 0b5b13402c..2e45b2b855 100644 --- a/gst/gstevent.h +++ b/gst/gstevent.h @@ -25,6 +25,7 @@ #define __GST_EVENT_H__ #include +#include #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 */ diff --git a/gst/gstinfo.c b/gst/gstinfo.c index 3518ec2ecb..ea63ea630e 100644 --- a/gst/gstinfo.c +++ b/gst/gstinfo.c @@ -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 */ diff --git a/gst/gstinfo.h b/gst/gstinfo.h index f5c06bd5f2..4f3f605d7c 100644 --- a/gst/gstinfo.h +++ b/gst/gstinfo.h @@ -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__ */ diff --git a/gst/gstobject.c b/gst/gstobject.c index 3e8d0b9434..70d81227c3 100644 --- a/gst/gstobject.c +++ b/gst/gstobject.c @@ -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 */ diff --git a/gst/gstobject.h b/gst/gstobject.h index d8140c7ac6..681dcadde4 100644 --- a/gst/gstobject.h +++ b/gst/gstobject.h @@ -24,10 +24,7 @@ #ifndef __GST_OBJECT_H__ #define __GST_OBJECT_H__ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - +#include #ifdef USE_GLIB2 #include // note that this gets wrapped in __GST_OBJECT_H__ @@ -36,15 +33,13 @@ #include #endif -#include -#include - -#include - #ifdef HAVE_ATOMIC_H #include #endif +#include +#include + // 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); diff --git a/gst/gstpad.c b/gst/gstpad.c index a21a96415f..c5c985d025 100644 --- a/gst/gstpad.c +++ b/gst/gstpad.c @@ -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); + } +} + diff --git a/gst/gstpad.h b/gst/gstpad.h index cda8b229b0..70f0a39647 100644 --- a/gst/gstpad.h +++ b/gst/gstpad.h @@ -24,14 +24,7 @@ #ifndef __GST_PAD_H__ #define __GST_PAD_H__ -#include // 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 #include #include @@ -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, diff --git a/gst/gstparse.c b/gst/gstparse.c index cf7fc1ff1f..b7e519175a 100644 --- a/gst/gstparse.c +++ b/gst/gstparse.c @@ -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)); diff --git a/gst/gstplugin.c b/gst/gstplugin.c index a540a77b4b..9f1f1408b2 100644 --- a/gst/gstplugin.c +++ b/gst/gstplugin.c @@ -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 */ /** diff --git a/gst/gstplugin.h b/gst/gstplugin.h index e678f58a3b..58eb018f2e 100644 --- a/gst/gstplugin.h +++ b/gst/gstplugin.h @@ -24,15 +24,9 @@ #ifndef __GST_PLUGIN_H__ #define __GST_PLUGIN_H__ -#include -#include // NOTE: this is xml-config's fault +#include -// 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 #include diff --git a/gst/gstprops.c b/gst/gstprops.c index 037eb304dc..670498d283 100644 --- a/gst/gstprops.c +++ b/gst/gstprops.c @@ -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 */ diff --git a/gst/gstprops.h b/gst/gstprops.h index 1d7730994a..9fc6dce2e3 100644 --- a/gst/gstprops.h +++ b/gst/gstprops.h @@ -24,16 +24,9 @@ #ifndef __GST_PROPS_H__ #define __GST_PROPS_H__ +#include + #include -#include // 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__ */ diff --git a/gst/gstscheduler.c b/gst/gstscheduler.c index b24012d9f0..fc4abe0a72 100644 --- a/gst/gstscheduler.c +++ b/gst/gstscheduler.c @@ -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; } /* diff --git a/gst/gstthread.c b/gst/gstthread.c index 322c91b223..27ae96c6d7 100644 --- a/gst/gstthread.c +++ b/gst/gstthread.c @@ -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); } diff --git a/gst/gstversion.h.in b/gst/gstversion.h.in index 820e7fc7f7..0cfd4dbe25 100644 --- a/gst/gstversion.h.in +++ b/gst/gstversion.h.in @@ -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__ */ diff --git a/gst/gstxml.h b/gst/gstxml.h index f3fd8d0437..b66aba2608 100644 --- a/gst/gstxml.h +++ b/gst/gstxml.h @@ -23,17 +23,10 @@ #ifndef __GST_XML_H__ #define __GST_XML_H__ +#include + #ifndef GST_DISABLE_LOADSAVE -#include - -// 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 #ifdef __cplusplus diff --git a/gst/utils/gstbytestream.c b/gst/utils/gstbytestream.c new file mode 100644 index 0000000000..5cc36639ce --- /dev/null +++ b/gst/utils/gstbytestream.c @@ -0,0 +1,113 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * 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 +#include + +#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); +} diff --git a/gst/utils/gstbytestream.h b/gst/utils/gstbytestream.h new file mode 100644 index 0000000000..f368bb31b4 --- /dev/null +++ b/gst/utils/gstbytestream.h @@ -0,0 +1,56 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * 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 + +#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__ */ diff --git a/gstplay/gstplay.c b/gstplay/gstplay.c index 4c4073266b..42071c33f6 100644 --- a/gstplay/gstplay.c +++ b/gstplay/gstplay.c @@ -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); diff --git a/gstplay/main.c b/gstplay/main.c index 0d968dce21..f8a6859b0f 100644 --- a/gstplay/main.c +++ b/gstplay/main.c @@ -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(); diff --git a/libs/Makefile.am b/libs/Makefile.am index 23bcb8ad45..581277f9d2 100644 --- a/libs/Makefile.am +++ b/libs/Makefile.am @@ -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 diff --git a/libs/bytestream/Makefile.am b/libs/bytestream/Makefile.am new file mode 100644 index 0000000000..0a6e8ee9cf --- /dev/null +++ b/libs/bytestream/Makefile.am @@ -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 diff --git a/libs/bytestream/gstbstest.c b/libs/bytestream/gstbstest.c new file mode 100644 index 0000000000..087d63ade7 --- /dev/null +++ b/libs/bytestream/gstbstest.c @@ -0,0 +1,294 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * 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 +#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 ", + "(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;icount;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;icount;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 +}; + diff --git a/libs/bytestream/gstbytestream.c b/libs/bytestream/gstbytestream.c new file mode 100644 index 0000000000..6f4d18a3f1 --- /dev/null +++ b/libs/bytestream/gstbytestream.c @@ -0,0 +1,394 @@ +/* GStreamer + * Copyright (C) 2001 Erik Walthinsen + * + * 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 +#include +#include + +#include +#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)); + } +} diff --git a/libs/bytestream/gstbytestream.h b/libs/bytestream/gstbytestream.h new file mode 100644 index 0000000000..fd01a973ee --- /dev/null +++ b/libs/bytestream/gstbytestream.h @@ -0,0 +1,53 @@ +/* GStreamer + * Copyright (C) 2001 Erik Walthinsen + * + * 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 + +#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__ */ diff --git a/plugins/elements/Makefile.am b/plugins/elements/Makefile.am index 61c5ad7c16..f50e4f75b4 100644 --- a/plugins/elements/Makefile.am +++ b/plugins/elements/Makefile.am @@ -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) diff --git a/plugins/elements/gstaggregator.c b/plugins/elements/gstaggregator.c index eb6c3013d9..49ec28f167 100644 --- a/plugins/elements/gstaggregator.c +++ b/plugins/elements/gstaggregator.c @@ -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; diff --git a/plugins/elements/gstdisksrc.c b/plugins/elements/gstdisksrc.c index ab13968eb9..ffe1b352e1 100644 --- a/plugins/elements/gstdisksrc.c +++ b/plugins/elements/gstdisksrc.c @@ -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) diff --git a/plugins/elements/gstdisksrc.h b/plugins/elements/gstdisksrc.h index 155a362c2d..4591254734 100644 --- a/plugins/elements/gstdisksrc.h +++ b/plugins/elements/gstdisksrc.h @@ -64,6 +64,7 @@ struct _GstDiskSrc { gchar *filename; /* fd */ gint fd; + GstBufferPool *bufferpool; /* mapping parameters */ gulong size; /* how long is the file? */ diff --git a/plugins/elements/gstfakesink.c b/plugins/elements/gstfakesink.c index 11eac007d1..02eb921fa3 100644 --- a/plugins/elements/gstfakesink.c +++ b/plugins/elements/gstfakesink.c @@ -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"); - } -} diff --git a/plugins/elements/gstfakesink.h b/plugins/elements/gstfakesink.h index cafc18b87c..85aa9fbdb7 100644 --- a/plugins/elements/gstfakesink.h +++ b/plugins/elements/gstfakesink.h @@ -57,6 +57,7 @@ struct _GstFakeSink { GSList *sinkpads; gint numsinkpads; gboolean silent; + gboolean dump; }; struct _GstFakeSinkClass { diff --git a/plugins/elements/gstfakesrc.c b/plugins/elements/gstfakesrc.c index d946529434..bed56e486f 100644 --- a/plugins/elements/gstfakesrc.c +++ b/plugins/elements/gstfakesrc.c @@ -21,6 +21,9 @@ */ +#include +#include + #include @@ -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) { diff --git a/plugins/elements/gstfakesrc.h b/plugins/elements/gstfakesrc.h index ce5c2a9439..550015b2af 100644 --- a/plugins/elements/gstfakesrc.h +++ b/plugins/elements/gstfakesrc.h @@ -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 { diff --git a/plugins/elements/gstfilesrc.c b/plugins/elements/gstfilesrc.c index 36214941e1..f53548f328 100644 --- a/plugins/elements/gstfilesrc.c +++ b/plugins/elements/gstfilesrc.c @@ -27,6 +27,7 @@ #include #include #include +#include /********************************************************************** @@ -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,®ion); + map = g_tree_search (src->map_regions, + (GCompareFunc) gst_filesrc_search_region_match, + ®ion); // 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; } diff --git a/plugins/elements/gstsinesrc.c b/plugins/elements/gstsinesrc.c new file mode 100644 index 0000000000..75ca6ba3b9 --- /dev/null +++ b/plugins/elements/gstsinesrc.c @@ -0,0 +1,452 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * 2001 Steve Baker + * + * 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 +#include +#include + +#include + + +GstElementDetails gst_sinesrc_details = { + "Sine-wave src", + "Source/Audio", + "Create a sine wave of a given frequency and volume", + VERSION, + "Erik Walthinsen ", + "(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; +} diff --git a/plugins/elements/gstsinesrc.h b/plugins/elements/gstsinesrc.h new file mode 100644 index 0000000000..58e03fd72b --- /dev/null +++ b/plugins/elements/gstsinesrc.h @@ -0,0 +1,96 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * 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 +#include + +#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__ */ diff --git a/plugins/elements/gsttee.c b/plugins/elements/gsttee.c index 729b95ec03..d7e0544bb0 100644 --- a/plugins/elements/gsttee.c +++ b/plugins/elements/gsttee.c @@ -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; diff --git a/test/ac3play.c b/test/ac3play.c index 292440e2a9..23f6fa7890 100644 --- a/test/ac3play.c +++ b/test/ac3play.c @@ -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); diff --git a/test/aviparse.c b/test/aviparse.c index 1cb43138d3..44f876acf2 100644 --- a/test/aviparse.c +++ b/test/aviparse.c @@ -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"); diff --git a/test/bufspeed/.gitignore b/test/bufspeed/.gitignore new file mode 100644 index 0000000000..25d1705737 --- /dev/null +++ b/test/bufspeed/.gitignore @@ -0,0 +1,10 @@ +Makefile +Makefile.in +*.o +*.lo +*.la +.deps +.libs +*.xml +test1 +test2 diff --git a/test/bufspeed/Makefile.am b/test/bufspeed/Makefile.am new file mode 100644 index 0000000000..e86b7a7699 --- /dev/null +++ b/test/bufspeed/Makefile.am @@ -0,0 +1,6 @@ +noinst_PROGRAMS = test1 test2 + +test1_SOURCES = test1.c gstbuffer.c gstmempool.c + +#LIBS += $(GST_LIBS) +CFLAGS += $(GST_CFLAGS) diff --git a/test/bufspeed/README b/test/bufspeed/README new file mode 100644 index 0000000000..8bb6600a9f --- /dev/null +++ b/test/bufspeed/README @@ -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 diff --git a/test/bufspeed/gstbuffer.c b/test/bufspeed/gstbuffer.c new file mode 100644 index 0000000000..35a92ee90a --- /dev/null +++ b/test/bufspeed/gstbuffer.c @@ -0,0 +1,495 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * 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); +} diff --git a/test/bufspeed/gstbuffer.h b/test/bufspeed/gstbuffer.h new file mode 100644 index 0000000000..d3a5a875b4 --- /dev/null +++ b/test/bufspeed/gstbuffer.h @@ -0,0 +1,174 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * 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 + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_ATOMIC_H +#include +#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 + +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__ */ diff --git a/test/bufspeed/gstmempool.c b/test/bufspeed/gstmempool.c new file mode 100644 index 0000000000..c9f956e6f3 --- /dev/null +++ b/test/bufspeed/gstmempool.c @@ -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 +} diff --git a/test/bufspeed/gstmempool.h b/test/bufspeed/gstmempool.h new file mode 100644 index 0000000000..307b768892 --- /dev/null +++ b/test/bufspeed/gstmempool.h @@ -0,0 +1,43 @@ +#include + +typedef struct _GstMemPool GstMemPool; +typedef struct _GstMemPoolElement GstMemPoolElement; + +typedef void (*GstMemPoolAllocFunc) (GstMemPool *pool, gpointer data); +typedef void (*GstMemPoolFreeFunc) (GstMemPool *pool, gpointer data); + +struct _GstMemPoolElement +{ + GstMemPoolElement *link; /* next cell in the lifo */ + GstMemPoolElement *area; +}; + +struct _GstMemPool +{ + volatile GstMemPoolElement *free; /* the first free element */ + volatile gulong cnt; /* used to avoid ABA problem */ + + gchar *name; + gulong area_size; + gulong pool_size; + gulong atom_size; + gboolean cleanup; + GstMemPoolAllocFunc alloc_func; + GstMemPoolFreeFunc free_func; + GMutex *chunk_lock; +}; + + +GstMemPool* gst_mem_pool_new (gchar *name, + gint atom_size, + gulong area_size, + gint type, + GstMemPoolAllocFunc alloc_func, + GstMemPoolFreeFunc free_func); + +void gst_mem_pool_destroy (GstMemPool *mem_pool); + +gpointer gst_mem_pool_alloc (GstMemPool *mem_pool); +gpointer gst_mem_pool_alloc0 (GstMemPool *mem_pool); +void gst_mem_pool_free (GstMemPool *mem_pool, + gpointer mem); diff --git a/test/bufspeed/test1.c b/test/bufspeed/test1.c new file mode 100644 index 0000000000..951af46067 --- /dev/null +++ b/test/bufspeed/test1.c @@ -0,0 +1,19 @@ +#include "gstbuffer.h" + +int +main (int argc, char *argv[]) +{ + GstBuffer *buf; + guint i; + + g_thread_init (NULL); + gtk_init (&argc, &argv); + _gst_buffer_initialize (); + + for (i=0; i<5000000; i++) { + buf = gst_buffer_new (); + gst_buffer_unref (buf); + } + + return 0; +} diff --git a/test/bufspeed/test2.c b/test/bufspeed/test2.c new file mode 100644 index 0000000000..616ad1f554 --- /dev/null +++ b/test/bufspeed/test2.c @@ -0,0 +1,19 @@ +#include + +int +main (int argc, char *argv[]) +{ + GstBuffer *buf; + guint i; + + g_thread_init (NULL); + gtk_init (&argc, &argv); + _gst_buffer_initialize (); + + for (i=0; i<5000000; i++) { + buf = gst_buffer_new (); + gst_buffer_unref (buf); + } + + return 0; +} diff --git a/test/dvshow.c b/test/dvshow.c index 833e3feabd..d82c4d0f2a 100644 --- a/test/dvshow.c +++ b/test/dvshow.c @@ -86,7 +86,9 @@ main (int argc,char *argv[]) gtk_widget_show_all(appwindow); +#ifndef GST_DISABLE_LOADSAVE xmlSaveFile("dvshow.xml",gst_xml_write(GST_ELEMENT(bin))); +#endif gst_element_set_state(GST_ELEMENT(bin),GST_STATE_PLAYING); diff --git a/test/events/Makefile.am b/test/events/Makefile.am new file mode 100644 index 0000000000..f2300be1ac --- /dev/null +++ b/test/events/Makefile.am @@ -0,0 +1,4 @@ +noinst_PROGRAMS = seek + +LIBS += $(GST_LIBS) +CFLAGS += $(GST_CFLAGS) diff --git a/test/events/seek.c b/test/events/seek.c new file mode 100644 index 0000000000..89a6e27189 --- /dev/null +++ b/test/events/seek.c @@ -0,0 +1,68 @@ +#include + +int +main (int argc, char *argv[]) +{ + GstBin *bin; + GstElement *src, *sink; + GstPad *srcpad, *sinkpad; + +// _gst_plugin_spew = TRUE; + gst_init (&argc, &argv); + + bin = GST_BIN (gst_pipeline_new ("pipeline")); + g_return_val_if_fail (bin != NULL, -1); + + g_print ("--- creating src and sink elements\n"); + src = gst_elementfactory_make ("fakesrc", "src"); + g_return_val_if_fail (src != NULL, -1); + sink = gst_elementfactory_make ("fakesink", "sink"); + g_return_val_if_fail (sink != NULL, -1); + + g_print ("--- about to add the elements to the bin\n"); + gst_bin_add (bin, GST_ELEMENT (src)); + gst_bin_add (bin, GST_ELEMENT (sink)); + + g_print ("--- getting pads\n"); + srcpad = gst_element_get_pad (src, "src"); + g_return_val_if_fail (srcpad != NULL, -1); + sinkpad = gst_element_get_pad (sink, "sink"); + g_return_val_if_fail (srcpad != NULL, -1); + + g_print ("--- connecting\n"); + gst_pad_connect (srcpad, sinkpad); + + g_print ("--- setting up\n"); + gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING); + + g_print ("--- iterating\n"); + gst_bin_iterate (bin); + gst_bin_iterate (bin); + + g_print ("--- seek to 100\n"); + gst_pad_send_event (srcpad, gst_event_new_seek (GST_SEEK_ANY, 100, FALSE)); + + g_print ("--- seek done, iterating\n"); + gst_bin_iterate (bin); + gst_bin_iterate (bin); + + g_print ("--- seek to 200 with flush\n"); + gst_pad_send_event (srcpad, gst_event_new_seek (GST_SEEK_ANY, 200, TRUE)); + + g_print ("--- seek done, iterating\n"); + gst_bin_iterate (bin); + gst_bin_iterate (bin); + gst_bin_iterate (bin); + + g_print ("--- flush\n"); + gst_pad_send_event (srcpad, gst_event_new_flush ()); + + g_print ("--- flush done, iterating\n"); + gst_bin_iterate (bin); + gst_bin_iterate (bin); + + g_print ("--- cleaning up\n"); + gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL); + + return 0; +} diff --git a/test/main.c b/test/main.c index 35f23d0016..5c71c6f4d7 100644 --- a/test/main.c +++ b/test/main.c @@ -140,7 +140,9 @@ gst_play_have_type (GstElement *typefind, GstCaps *caps, GstPlayInfo *info) gst_element_set_state (pipeline, GST_STATE_PLAYING); +#ifndef GST_DISABLE_LOADSAVE xmlSaveFile("xmlTest.gst", gst_xml_write (GST_ELEMENT (pipeline))); +#endif } diff --git a/test/memchunk/Makefile.am b/test/memchunk/Makefile.am new file mode 100644 index 0000000000..e3198c289e --- /dev/null +++ b/test/memchunk/Makefile.am @@ -0,0 +1,7 @@ +noinst_PROGRAMS = gmemchunktest gstmemchunktest + +gmemchunktest_SOURCES = gmemchunktest.c +gstmemchunktest_SOURCES = gstmemchunktest.c gstmemchunk.c gstmemchunk.h + +LIBS += $(GST_LIBS) +CFLAGS += $(GST_CFLAGS) diff --git a/test/memchunk/gmemchunktest.c b/test/memchunk/gmemchunktest.c new file mode 100644 index 0000000000..b3301f13dd --- /dev/null +++ b/test/memchunk/gmemchunktest.c @@ -0,0 +1,78 @@ +#include + +#define MAX_THREADS 100 + +static GMemChunk *_chunks; +static GMutex *_lock; + +static gint num_allocs; +static gint num_threads; + +static gpointer +alloc_chunk (void) +{ + gpointer ret; + g_mutex_lock (_lock); + ret = g_mem_chunk_alloc (_chunks); + g_mutex_unlock (_lock); + + return ret; +} + +static void +free_chunk (gpointer chunk) +{ + g_mutex_lock (_lock); + g_mem_chunk_free (_chunks, chunk); + g_mutex_unlock (_lock); +} + + +void* +run_test (void *threadid) +{ + gint i; + gpointer chunk; + sleep(1); + + for (i = 0; i \n", argv[0]); + exit (-1); + } + + num_threads = atoi (argv[1]); + num_allocs = atoi (argv[2]); + + _chunks = g_mem_chunk_new ("test", 32, 32 * 16, G_ALLOC_AND_FREE); + _lock = g_mutex_new (); + + for(t=0; t < num_threads; t++) { + rc = pthread_create (&threads[t], NULL, run_test, (void *)t); + if (rc) { + printf ("ERROR: return code from pthread_create() is %d\n", rc); + printf ("Code %d= %s\n", rc, strerror(rc)); + exit (-1); + } + } + printf ("main(): Created %d threads.\n", t); + + pthread_exit (NULL); + g_mem_chunk_info(); +} diff --git a/test/memchunk/gstmemchunk.c b/test/memchunk/gstmemchunk.c new file mode 100644 index 0000000000..be99be5a79 --- /dev/null +++ b/test/memchunk/gstmemchunk.c @@ -0,0 +1,162 @@ +#include "gstmemchunk.h" + +#ifdef __SMP__ +#define CHUNK_LOCK "lock ; " +#else +#define CHUNK_LOCK "" +#endif + +#define GST_MEM_CHUNK_AREA(chunk) (((GstMemChunkElement*)(chunk))->area) +#define GST_MEM_CHUNK_DATA(chunk) ((gpointer)(((GstMemChunkElement*)(chunk)) + 1)) +#define GST_MEM_CHUNK_LINK(mem) ((GstMemChunkElement*)((guint8*)(mem) - sizeof (GstMemChunkElement))) + +/******************************************************* + * area size + * +-----------------------------------------+ + * chunk size + * +------------+ + * + * !next!data... !next!data.... !next!data... + * ! ^ ! ^ ! + * +-------------+ +------------+ +---> NULL + * + */ +static gboolean +populate (GstMemChunk *mem_chunk) +{ + guint8 *area; + gint i; + + if (mem_chunk->cleanup) + return FALSE; + + area = (guint8 *) g_malloc (mem_chunk->area_size); + g_print ("alloc %p\n", area); + + for (i=0; i < mem_chunk->area_size; i += mem_chunk->chunk_size) { + GST_MEM_CHUNK_AREA (area + i) = (GstMemChunkElement *)area; + gst_mem_chunk_free (mem_chunk, GST_MEM_CHUNK_DATA (area + i)); + } + + return TRUE; +} + + +GstMemChunk* +gst_mem_chunk_new (gchar* name, gint atom_size, gulong area_size, gint type) +{ + GstMemChunk *mem_chunk; + + g_return_val_if_fail (atom_size > 0, NULL); + g_return_val_if_fail (area_size >= atom_size, NULL); + + mem_chunk = g_malloc (sizeof (GstMemChunk)); + + mem_chunk->chunk_size = atom_size + sizeof (GstMemChunkElement); + area_size = (area_size/atom_size) * mem_chunk->chunk_size; + + mem_chunk->name = g_strdup (name); + mem_chunk->free = NULL; + mem_chunk->cnt = 0; + mem_chunk->atom_size = atom_size; + mem_chunk->area_size = area_size; + mem_chunk->cleanup = FALSE; + + populate (mem_chunk); + + return mem_chunk; +} + +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_chunk_destroy (GstMemChunk *mem_chunk) +{ + GHashTable *elements = g_hash_table_new (NULL, NULL); + gpointer data; + + mem_chunk->cleanup = TRUE; + + data = gst_mem_chunk_alloc (mem_chunk); + while (data) { + GstMemChunkElement *elem = GST_MEM_CHUNK_LINK (data); + + g_hash_table_insert (elements, GST_MEM_CHUNK_AREA (elem), NULL); + + data = gst_mem_chunk_alloc (mem_chunk); + } + g_hash_table_foreach_remove (elements, free_area, NULL); + + g_hash_table_destroy (elements); + g_free (mem_chunk->name); + g_free (mem_chunk); +} + +gpointer +gst_mem_chunk_alloc (GstMemChunk *mem_chunk) +{ + GstMemChunkElement *chunk = NULL; + + g_return_val_if_fail (mem_chunk != NULL, NULL); + +again: + __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" + CHUNK_LOCK "cmpxchg8b %1 \n\t" + " jz 20f \n\t" + " testl %%eax, %%eax \n\t" + " jnz 10b \n" + "20:\t" + :"=a" (chunk) + :"m" (*mem_chunk), "a" (mem_chunk->free), "d" (mem_chunk->cnt) + :"ecx", "ebx"); + + if (!chunk) { + //g_print ("extending\n"); + if (populate (mem_chunk)) + goto again; + else + return NULL; + } + return GST_MEM_CHUNK_DATA (chunk); +} + +gpointer +gst_mem_chunk_alloc0 (GstMemChunk *mem_chunk) +{ + gpointer mem = gst_mem_chunk_alloc (mem_chunk); + + if (mem) + memset (mem, 0, mem_chunk->atom_size); + + return mem; +} + +void +gst_mem_chunk_free (GstMemChunk *mem_chunk, gpointer mem) +{ + GstMemChunkElement *chunk; + + g_return_if_fail (mem_chunk != NULL); + g_return_if_fail (mem != NULL); + + chunk = GST_MEM_CHUNK_LINK (mem); + + __asm__ __volatile__ ( "1: \t" + " movl %2, (%1) \n" + CHUNK_LOCK "cmpxchg %1, %0 \n\t" + " jnz 1b \n\t" + : + :"m" (*mem_chunk), "r" (chunk), "a" (mem_chunk->free)); +} diff --git a/test/memchunk/gstmemchunk.h b/test/memchunk/gstmemchunk.h new file mode 100644 index 0000000000..c71660a567 --- /dev/null +++ b/test/memchunk/gstmemchunk.h @@ -0,0 +1,34 @@ + +#include + +typedef struct _GstMemChunk GstMemChunk; +typedef struct _GstMemChunkElement GstMemChunkElement; + +struct _GstMemChunkElement +{ + GstMemChunkElement *link; /* next cell in the lifo */ + GstMemChunkElement *area; +}; + +struct _GstMemChunk +{ + volatile GstMemChunkElement *free; /* the first free element */ + volatile gulong cnt; /* used to avoid ABA problem */ + + gchar *name; + gulong area_size; + gulong chunk_size; + gulong atom_size; + gboolean cleanup; +}; + +GstMemChunk* gst_mem_chunk_new (gchar *name, + gint atom_size, + gulong area_size, + gint type); + +void gst_mem_chunk_destroy (GstMemChunk *mem_chunk); + +gpointer gst_mem_chunk_alloc (GstMemChunk *mem_chunk); +void gst_mem_chunk_free (GstMemChunk *mem_chunk, + gpointer mem); diff --git a/test/memchunk/gstmemchunktest.c b/test/memchunk/gstmemchunktest.c new file mode 100644 index 0000000000..05acccb104 --- /dev/null +++ b/test/memchunk/gstmemchunktest.c @@ -0,0 +1,79 @@ +#include +#include "gstmemchunk.h" + +#define MAX_THREADS 100 + +static GstMemChunk *_chunks; + +static gint num_allocs; +static gint num_threads; + +static gpointer +alloc_chunk (void) +{ + gpointer ret; + ret = gst_mem_chunk_alloc (_chunks); + + return ret; +} + +static void +free_chunk (gpointer chunk) +{ + gst_mem_chunk_free (_chunks, chunk); +} + + +void* +run_test (void *threadid) +{ + gint i; + gpointer chunk; + sleep(1); + + for (i = 0; i \n", argv[0]); + exit (-1); + } + + num_threads = atoi (argv[1]); + num_allocs = atoi (argv[2]); + + _chunks = gst_mem_chunk_new ("test", 32, 32 * 16, G_ALLOC_AND_FREE); + + for(t=0; t < num_threads; t++) { + rc = pthread_create (&threads[t], NULL, run_test, (void *)t); + if (rc) { + printf ("ERROR: return code from pthread_create() is %d\n", rc); + printf ("Code %d= %s\n", rc, strerror(rc)); + exit (-1); + } + } + printf ("main(): Created %d threads.\n", t); + + for(t=0; t < num_threads; t++) { + pthread_join (threads[t], NULL); + } + g_mem_chunk_info(); + + gst_mem_chunk_destroy (_chunks); + + return 0; +} diff --git a/test/mpeg2parse2.c b/test/mpeg2parse2.c index 75a04c42f2..29f2d98d39 100644 --- a/test/mpeg2parse2.c +++ b/test/mpeg2parse2.c @@ -16,7 +16,7 @@ gboolean idle_func(gpointer data) { void mpeg2parse_newpad(GstElement *parser,GstPad *pad, GstElement *pipeline) { - g_print("***** a new pad %s was created\n", gst_pad_get_name(pad)); + g_print("***** a new pad %s was created %p\n", gst_pad_get_name(pad), pipeline); gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_PAUSED); if (strncmp(gst_pad_get_name(pad), "video_", 6) == 0) { diff --git a/tests/Makefile.am b/tests/Makefile.am index 257a9ed1c6..43ac3402a0 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,8 +1,15 @@ SUBDIRS = sched eos nego muxing -noinst_PROGRAMS = init loadall simplefake states caps queue registry \ -paranoia rip mp3encode autoplug props case4 markup load tee autoplug2 autoplug3 \ -capsconnect padfactory autoplug4 incsched reaping threadlock mp1vid reconnect \ +if GST_DISABLE_LOADSAVE +GST_LOADSAVE_PROG = +else +GST_LOADSAVE_PROG = caps registry autoplug props tee autoplug2 capsconnect \ + padfactory autoplug4 +endif + +noinst_PROGRAMS = $(GST_LOADSAVE_PROG) init loadall simplefake states queue \ +paranoia rip mp3encode case4 markup load autoplug3 \ +incsched reaping threadlock mp1vid reconnect \ faketest events timecache # we have nothing but apps here, we can do this safely diff --git a/tests/old/examples/Makefile.am b/tests/old/examples/Makefile.am index 6fe9c9c70b..b81c1568f7 100644 --- a/tests/old/examples/Makefile.am +++ b/tests/old/examples/Makefile.am @@ -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 \ diff --git a/tests/old/examples/autoplug/autoplug.c b/tests/old/examples/autoplug/autoplug.c index 550b182530..9de5ba56f2 100644 --- a/tests/old/examples/autoplug/autoplug.c +++ b/tests/old/examples/autoplug/autoplug.c @@ -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 diff --git a/tests/old/examples/mixer/mixer.c b/tests/old/examples/mixer/mixer.c index 0edbfa539f..7a02eddcb4 100644 --- a/tests/old/examples/mixer/mixer.c +++ b/tests/old/examples/mixer/mixer.c @@ -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); diff --git a/tests/old/testsuite/bytestream/.gitignore b/tests/old/testsuite/bytestream/.gitignore new file mode 100644 index 0000000000..7df60c92d6 --- /dev/null +++ b/tests/old/testsuite/bytestream/.gitignore @@ -0,0 +1,8 @@ +Makefile +Makefile.in +*.o +*.lo +*.la +.deps +.libs +test1 diff --git a/tests/old/testsuite/bytestream/Makefile.am b/tests/old/testsuite/bytestream/Makefile.am new file mode 100644 index 0000000000..75aeed7915 --- /dev/null +++ b/tests/old/testsuite/bytestream/Makefile.am @@ -0,0 +1,13 @@ +filterdir = $(libdir)/gst + +testprogs = test1 + +check_PROGRAMS = $(testprogs) + +test1_SOURCES = test1.c gstbstest.c mem.c +test1_LDFLAGS = -L$(top_builddir)/libs/bytestream/ -lgstbytestream + + +# we have nothing but apps here, we can do this safely +LIBS += $(GST_LIBS) +CFLAGS += $(GST_CFLAGS) diff --git a/tests/old/testsuite/bytestream/gstbstest.c b/tests/old/testsuite/bytestream/gstbstest.c new file mode 100644 index 0000000000..4199a905f6 --- /dev/null +++ b/tests/old/testsuite/bytestream/gstbstest.c @@ -0,0 +1,407 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * gstbstest.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 +#include + +#include +#include + +#define GST_TYPE_BSTEST (gst_bstest_get_type()) +#define GST_BSTEST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BSTEST,GstBsTest)) +#define GST_BSTEST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BSTEST,GstBsTestClass)) +#define GST_IS_BSTEST(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BSTEST)) +#define GST_IS_BSTEST_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BSTEST)) + +typedef struct _GstBsTest GstBsTest; +typedef struct _GstBsTestClass GstBsTestClass; + +struct _GstBsTest +{ + GstElement element; + + GstPad *sinkpad; + GstPad *srcpad; + + GstByteStream *bs; + + gchar *accesspattern; + guint num_patterns; + gchar **patterns; + guint sizemin; + guint sizemax; + gint count; + gboolean silent; +}; + +struct _GstBsTestClass +{ + GstElementClass parent_class; +}; + +GType gst_bstest_get_type (void); + + +GstElementDetails gst_bstest_details = { + "ByteStreamTest", + "Filter", + "Test for the GstByteStream code", + VERSION, + "Erik Walthinsen ," "Wim Taymans ", + "(C) 2001", +}; + + +/* BsTest signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + ARG_0, + ARG_SIZEMIN, + ARG_SIZEMAX, + ARG_COUNT, + ARG_SILENT, + ARG_ACCESSPATTERN, +}; + + +static void gst_bstest_class_init (GstBsTestClass * klass); +static void gst_bstest_init (GstBsTest * bstest); + +static void gst_bstest_set_property (GObject * object, guint prop_id, const GValue * value, + GParamSpec * pspec); +static void gst_bstest_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec); + +static GstElementStateReturn gst_bstest_change_state (GstElement *element); +static void gst_bstest_loop (GstElement * element); + +static GstElementClass *parent_class = NULL; + +// static guint gst_bstest_signals[LAST_SIGNAL] = { 0 }; + +GType +gst_bstest_get_type (void) +{ + static GType bstest_type = 0; + + if (!bstest_type) { + static const GTypeInfo bstest_info = { + sizeof (GstBsTestClass), NULL, + NULL, + (GClassInitFunc) gst_bstest_class_init, + NULL, + NULL, + sizeof (GstBsTest), + 0, + (GInstanceInitFunc) gst_bstest_init, + }; + + bstest_type = g_type_register_static (GST_TYPE_ELEMENT, "BSTest", &bstest_info, 0); + } + return bstest_type; +} + +static void +gst_bstest_class_init (GstBsTestClass * 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_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, + 384, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ACCESSPATTERN, + g_param_spec_string ("accesspattern", "accesspattern", "accesspattern", + "r", 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)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT, + g_param_spec_boolean ("silent", "silent", "silent", + FALSE, G_PARAM_READWRITE)); + + gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_bstest_set_property); + gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_bstest_get_property); + + gstelement_class->change_state = gst_bstest_change_state; + +} + +static GstPadNegotiateReturn +gst_bstest_negotiate_src (GstPad * pad, GstCaps ** caps, gpointer * data) +{ + GstBsTest *bstest; + + bstest = GST_BSTEST (gst_pad_get_parent (pad)); + + return gst_pad_negotiate_proxy (pad, bstest->sinkpad, caps); +} + +static GstPadNegotiateReturn +gst_bstest_negotiate_sink (GstPad * pad, GstCaps ** caps, gpointer * data) +{ + GstBsTest *bstest; + + bstest = GST_BSTEST (gst_pad_get_parent (pad)); + + return gst_pad_negotiate_proxy (pad, bstest->srcpad, caps); +} + +static void +gst_bstest_init (GstBsTest * bstest) +{ + bstest->sinkpad = gst_pad_new ("sink", GST_PAD_SINK); + gst_element_add_pad (GST_ELEMENT (bstest), bstest->sinkpad); + gst_pad_set_negotiate_function (bstest->sinkpad, gst_bstest_negotiate_sink); + + bstest->srcpad = gst_pad_new ("src", GST_PAD_SRC); + gst_element_add_pad (GST_ELEMENT (bstest), bstest->srcpad); + gst_pad_set_negotiate_function (bstest->srcpad, gst_bstest_negotiate_src); + + gst_element_set_loop_function (GST_ELEMENT (bstest), gst_bstest_loop); + + bstest->sizemin = 0; + bstest->sizemax = 384; + bstest->accesspattern = g_strdup ("r"); + bstest->patterns = g_strsplit (bstest->accesspattern, ":", 0); + bstest->count = 5; + bstest->silent = FALSE; + bstest->bs = NULL; +} + +static guint +gst_bstest_get_size (GstBsTest *bstest, gchar *sizestring, guint prevsize) +{ + guint size; + + if (sizestring[0] == 0) { + size = bstest->sizemax; + } + else if (sizestring[0] == 'r') { + size = bstest->sizemin + (guint8)(((gfloat)bstest->sizemax)*rand()/(RAND_MAX + (gfloat)bstest->sizemin)); + } + else if (sizestring[0] == '<') { + size = prevsize; + } + else { + size = atoi (sizestring); + } + + if (size == 0) size++; + + return size; +} + +static void +gst_bstest_loop (GstElement * element) +{ + GstBsTest *bstest; + GstBuffer *buf = NULL; + + g_return_if_fail (element != NULL); + g_return_if_fail (GST_IS_BSTEST (element)); + + bstest = GST_BSTEST (element); + + do { + guint size = 0; + guint i = 0; + + while (i < bstest->num_patterns) { + buf = NULL; + + if (bstest->patterns[i][0] == 'r') { + size = gst_bstest_get_size (bstest, &bstest->patterns[i][1], size); + if (!bstest->silent) g_print ("bstest: ***** read %d bytes\n", size); + buf = gst_bytestream_read (bstest->bs, size); + } + else if (bstest->patterns[i][0] == 'f') { + size = gst_bstest_get_size (bstest, &bstest->patterns[i][1], size); + if (!bstest->silent) g_print ("bstest: ***** flush %d bytes\n", size); + gst_bytestream_flush (bstest->bs, size); + } + else if (!strncmp (bstest->patterns[i], "pb", 2)) { + size = gst_bstest_get_size (bstest, &bstest->patterns[i][2], size); + if (!bstest->silent) g_print ("bstest: ***** peek bytes %d bytes\n", size); + gst_bytestream_peek_bytes (bstest->bs, size); + } + else if (bstest->patterns[i][0] == 'p') { + size = gst_bstest_get_size (bstest, &bstest->patterns[i][1], size); + if (!bstest->silent) g_print ("bstest: ***** peek %d bytes\n", size); + buf = gst_bytestream_peek (bstest->bs, size); + gst_buffer_unref (buf); + buf = NULL; + } + + if (buf) + gst_pad_push (bstest->srcpad, buf); + + i++; + } + } while (!GST_ELEMENT_IS_COTHREAD_STOPPING (element)); +} + +static void +gst_bstest_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstBsTest *bstest; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail (GST_IS_BSTEST (object)); + + bstest = GST_BSTEST (object); + + switch (prop_id) { + case ARG_SIZEMIN: + bstest->sizemin = g_value_get_int (value); + break; + case ARG_SIZEMAX: + bstest->sizemax = g_value_get_int (value); + break; + case ARG_ACCESSPATTERN: + if (bstest->accesspattern) { + g_free (bstest->accesspattern); + g_strfreev (bstest->patterns); + } + if (g_value_get_string (value) == NULL) { + gst_element_set_state (GST_ELEMENT (object), GST_STATE_NULL); + bstest->accesspattern = NULL; + bstest->num_patterns = 0; + } else { + guint i = 0; + + bstest->accesspattern = g_strdup (g_value_get_string (value)); + bstest->patterns = g_strsplit (bstest->accesspattern, ":", 0); + while (bstest->patterns[i++]); + bstest->num_patterns = i-1; + } + break; + case ARG_COUNT: + bstest->count = g_value_get_uint (value); + break; + case ARG_SILENT: + bstest->silent = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_bstest_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstBsTest *bstest; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail (GST_IS_BSTEST (object)); + + bstest = GST_BSTEST (object); + + switch (prop_id) { + case ARG_SIZEMIN: + g_value_set_int (value, bstest->sizemin); + break; + case ARG_SIZEMAX: + g_value_set_int (value, bstest->sizemax); + break; + case ARG_ACCESSPATTERN: + g_value_set_string (value, bstest->accesspattern); + break; + case ARG_COUNT: + g_value_set_uint (value, bstest->count); + break; + case ARG_SILENT: + g_value_set_boolean (value, bstest->silent); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstElementStateReturn +gst_bstest_change_state (GstElement *element) +{ + GstBsTest *bstest; + + g_return_val_if_fail (GST_IS_BSTEST (element), GST_STATE_FAILURE); + + bstest = GST_BSTEST (element); + + if (GST_STATE_PENDING (element) == GST_STATE_NULL) { + if (bstest->bs) { + gst_bytestream_destroy (bstest->bs); + bstest->bs = NULL; + } + } + else { + if (!bstest->bs) { + bstest->bs = gst_bytestream_new (bstest->sinkpad); + } + } + + if (GST_ELEMENT_CLASS (parent_class)->change_state) + return GST_ELEMENT_CLASS (parent_class)->change_state (element); + + return GST_STATE_SUCCESS; +} + +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 ("bstest", GST_TYPE_BSTEST, &gst_bstest_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; +} + +GST_PLUGIN_DESC (GST_VERSION_MAJOR, GST_VERSION_MINOR, "bstest", plugin_init); diff --git a/tests/old/testsuite/bytestream/mem.c b/tests/old/testsuite/bytestream/mem.c new file mode 100644 index 0000000000..d1c36cb5aa --- /dev/null +++ b/tests/old/testsuite/bytestream/mem.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include +#include + +int vmsize() { + int pid,fd,size,i,mem; + char filename[17], buf[256], *ptr, *end; + + pid = getpid(); + snprintf(filename,17,"/proc/%d/stat",pid); + fd = open(filename,O_RDONLY); + size = read(fd,buf,240); + ptr = buf; + for (i=0;i<22;i++) + ptr = (char *)strchr(ptr,' ') + 1; + end = (char *)strchr(ptr,' '); + *end = 0; + sscanf(ptr,"%d",&mem); + close(fd); + return mem; +} diff --git a/tests/old/testsuite/bytestream/mem.h b/tests/old/testsuite/bytestream/mem.h new file mode 100644 index 0000000000..28999db2c3 --- /dev/null +++ b/tests/old/testsuite/bytestream/mem.h @@ -0,0 +1 @@ +int vmsize(); diff --git a/tests/old/testsuite/bytestream/test1.c b/tests/old/testsuite/bytestream/test1.c new file mode 100644 index 0000000000..0670849e84 --- /dev/null +++ b/tests/old/testsuite/bytestream/test1.c @@ -0,0 +1,230 @@ +#include +#include + +#include +#include "mem.h" + +#define VM_THRES 1000 +#define MAX_CONFIG_LINE 255 +#define MAX_CONFIG_PATTERN 64 + +typedef struct +{ + gint src_data; + gint src_sizetype; + + gchar *bs_accesspattern; + + gboolean integrity_check; +} TestParam; + +static GSList *params = NULL; + +static guint8 count; +static guint iterations; +static gboolean integrity_check = TRUE; +static gboolean verbose = FALSE; +static gboolean dump = FALSE; + +static void +handoff (GstElement *element, GstBuffer *buf, GstPad *pad, gpointer data) +{ + if (GST_IS_BUFFER (buf)) { + if (integrity_check) { + gint i; + guint8 *ptr = GST_BUFFER_DATA (buf); + + for (i=0; isrc_sizetype == 2 ? "fixed" : "random"), + (param->src_data == 1 ? "src" : "subbuffer"), + param->bs_accesspattern); + return desc; +} + +static gboolean +read_param_file (gchar *filename) +{ + FILE *fp; + gchar line[MAX_CONFIG_LINE+1]; + guint linenr = 0; + gchar pattern[MAX_CONFIG_PATTERN]; + gint data, sizetype, integrity_check; + gchar *scan_str; + gboolean res = TRUE; + + fp = fopen (filename, "r"); + if (fp == NULL) + return FALSE; + + scan_str = g_strdup_printf ("%%d %%d %%%ds %%d", MAX_CONFIG_PATTERN-1); + + while (fgets (line, MAX_CONFIG_LINE, fp)) { + linenr++; + + if (line[0] == '\n' || line[0] == '#') + continue; + + if (sscanf (line, scan_str, &data, &sizetype, pattern, &integrity_check) != 4) { + g_print ("error on line: %d\n", linenr); + res = FALSE; + break; + } + else { + TestParam *param = g_malloc (sizeof (TestParam)); + + param->src_data = data; + param->src_sizetype = sizetype; + param->bs_accesspattern = g_strdup (pattern); + param->integrity_check = (integrity_check == 0 ? FALSE : TRUE); + + params = g_slist_append (params, param); + } + } + g_free (scan_str); + + return res; +} + +static void +run_test (GstBin *pipeline, gint iters) +{ + gint vm = 0; + gint maxiters = iters; + gint prev_percent = -1; + + count = 0; + gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING); + + while (iters) { + gint newvm = vmsize(); + gint percent; + + percent = (gint)((maxiters-iters+1)*100.0/maxiters); + + if (percent != prev_percent || newvm - vm > VM_THRES) { + g_print ("\r%d (delta %d) %.3d%% ", newvm, newvm - vm, percent); + prev_percent = percent; + vm = newvm; + } + gst_bin_iterate (pipeline); + + if (iters > 0) iters--; + } + gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); +} + +static void +usage (char *argv[]) +{ + g_print ("usage: %s [--verbose] [--dump] \n", argv[0]); +} + +int +main (int argc, char *argv[]) +{ + GstElement *src; + GstElement *sink; + GstElement *bs; + GstElement *pipeline; + gint testnum = 0; + GSList *walk; + gint arg_walk; + + gst_init (&argc, &argv); + + arg_walk = 1; + while ((arg_walk < argc) && (argv[arg_walk][0] == '-')) { + if (!strncmp (argv[arg_walk], "--verbose", 9)) + verbose = TRUE; + else if (!strncmp (argv[arg_walk], "--dump", 6)) + dump = TRUE; + else { + g_print ("unknown option %s (ignored)\n", argv[arg_walk]); + } + + arg_walk++; + } + if (argc - arg_walk < 2) { + usage(argv); + return -1; + } + if (!read_param_file (argv[arg_walk])) { + g_print ("error reading file %s\n", argv[arg_walk]); + usage (argv); + return -1; + } + arg_walk++; + iterations = atoi (argv[arg_walk]); + + pipeline = gst_elementfactory_make ("pipeline", "pipeline"); + g_assert (pipeline); + + src = gst_elementfactory_make ("fakesrc", "src"); + g_assert (src); + + sink = gst_elementfactory_make ("fakesink", "sink"); + g_assert (sink); + g_signal_connect (G_OBJECT (sink), "handoff", G_CALLBACK (handoff), NULL); + + bs = gst_elementfactory_make ("bstest", "bs"); + g_assert (bs); + + gst_element_connect (src, "src", bs, "sink"); + gst_element_connect (bs, "src", sink, "sink"); + + gst_bin_add (GST_BIN (pipeline), src); + gst_bin_add (GST_BIN (pipeline), bs); + gst_bin_add (GST_BIN (pipeline), sink); + + walk = params; + + while (walk) { + gchar *desc; + TestParam *param = (TestParam *) (walk->data); + + integrity_check = param->integrity_check; + + g_print ("\n\nrunning test %d (%d iterations):\n", testnum+1, iterations); + desc = create_desc (param); + g_print ("%s\n", desc); + g_free (desc); + + g_object_set (G_OBJECT (src), "data", param->src_data, + "sizetype", param->src_sizetype, + "filltype", (integrity_check?5:0), + "silent", !verbose, NULL); + + g_object_set (G_OBJECT (bs), "accesspattern", param->bs_accesspattern, + "silent", !verbose, NULL); + + g_object_set (G_OBJECT (sink), "dump", dump, + "silent", !verbose, NULL); + + run_test (GST_BIN (pipeline), iterations); + + testnum++; + + walk = g_slist_next (walk); + } + + g_print ("\n\ndone\n"); + + return 0; + +} diff --git a/tests/old/testsuite/bytestream/testfile1 b/tests/old/testsuite/bytestream/testfile1 new file mode 100644 index 0000000000..68a32dd582 --- /dev/null +++ b/tests/old/testsuite/bytestream/testfile1 @@ -0,0 +1,93 @@ +# lots of parameters here. values for the columns are like: +# +# - data property in fakesrc: 1 = allocate, 2 = subbuffer +# - sizetype property in fakesrc: 2 = fixed, 3 = random +# +# - accesspattern for bstest +# [:...] +# +# can be: +# r = read +# p = peek +# pb = peek bytes +# f = flush +# can be: +# = fixed size +# r = random size +# < = previous size +# = this size +# +# - integrity check: 0 = no, 1 = yes +# +1 2 r 1 +1 2 rr 1 +1 3 r 1 +1 3 rr 1 +2 2 r 1 +2 2 rr 1 +2 3 r 1 +2 3 rr 1 +1 2 p:r< 1 +1 2 pr:r< 1 +1 3 p:r< 1 +1 3 pr:r< 1 +2 2 p:r< 1 +2 2 pr:r< 1 +2 3 p:r< 1 +2 3 pr:r< 1 +1 2 p:rr 1 +1 2 pr:rr 1 +1 3 p:rr 1 +1 3 pr:rr 1 +2 2 p:rr 1 +2 2 pr:rr 1 +2 3 p:rr 1 +2 3 pr:rr 1 +1 2 pb:r 1 +1 2 pbr:r 1 +1 3 pb:r 1 +1 3 pbr:r 1 +2 2 pb:r 1 +2 2 pbr:r 1 +2 3 pb:r 1 +2 3 pbr:r 1 +1 2 pb:rr 1 +1 2 pbr:rr 1 +1 3 pb:rr 1 +1 3 pbr:rr 1 +2 2 pb:rr 1 +2 2 pbr:rr 1 +2 3 pb:rr 1 +2 3 pbr:rr 1 +1 2 p:fr:rr 0 +1 2 pr:fr:rr 0 +1 3 p:fr:rr 0 +1 3 pr:fr:rr 0 +2 2 p:fr:rr 0 +2 2 pr:fr:rr 0 +2 3 p:fr:rr 0 +2 3 pr:fr:rr 0 +1 2 fr:rr 0 +1 2 fr:rr 0 +1 3 fr:rr 0 +1 3 fr:rr 0 +2 2 fr:rr 0 +2 2 fr:rr 0 +2 3 fr:rr 0 +2 3 fr:rr 0 +1 2 fr:fr:rr 0 +1 2 fr:fr:rr 0 +1 3 fr:fr:rr 0 +1 3 fr:fr:rr 0 +2 2 fr:fr:rr 0 +2 2 fr:fr:rr 0 +2 3 fr:fr:rr 0 +2 3 fr:fr:rr 0 +1 2 pbr:pbr:rr 1 +1 2 pbr:pbr:rr 1 +1 3 pbr:pbr:rr 1 +1 3 pbr:pbr:rr 1 +2 2 pbr:pbr:rr 1 +2 2 pbr:pbr:rr 1 +2 3 pbr:pbr:rr 1 +2 3 pbr:pbr:rr 1 diff --git a/tests/sched/Makefile.am b/tests/sched/Makefile.am index c1ca8520c6..2894b4ca6d 100644 --- a/tests/sched/Makefile.am +++ b/tests/sched/Makefile.am @@ -1,4 +1,8 @@ +if GST_DISABLE_LOADSAVE +noinst_PROGRAMS = +else noinst_PROGRAMS = runxml +endif # nothing but apps here, this is safe LIBS += $(GST_LIBS) diff --git a/testsuite/bytestream/.gitignore b/testsuite/bytestream/.gitignore new file mode 100644 index 0000000000..7df60c92d6 --- /dev/null +++ b/testsuite/bytestream/.gitignore @@ -0,0 +1,8 @@ +Makefile +Makefile.in +*.o +*.lo +*.la +.deps +.libs +test1 diff --git a/testsuite/bytestream/Makefile.am b/testsuite/bytestream/Makefile.am new file mode 100644 index 0000000000..75aeed7915 --- /dev/null +++ b/testsuite/bytestream/Makefile.am @@ -0,0 +1,13 @@ +filterdir = $(libdir)/gst + +testprogs = test1 + +check_PROGRAMS = $(testprogs) + +test1_SOURCES = test1.c gstbstest.c mem.c +test1_LDFLAGS = -L$(top_builddir)/libs/bytestream/ -lgstbytestream + + +# we have nothing but apps here, we can do this safely +LIBS += $(GST_LIBS) +CFLAGS += $(GST_CFLAGS) diff --git a/testsuite/bytestream/gstbstest.c b/testsuite/bytestream/gstbstest.c new file mode 100644 index 0000000000..4199a905f6 --- /dev/null +++ b/testsuite/bytestream/gstbstest.c @@ -0,0 +1,407 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * gstbstest.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 +#include + +#include +#include + +#define GST_TYPE_BSTEST (gst_bstest_get_type()) +#define GST_BSTEST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BSTEST,GstBsTest)) +#define GST_BSTEST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BSTEST,GstBsTestClass)) +#define GST_IS_BSTEST(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BSTEST)) +#define GST_IS_BSTEST_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BSTEST)) + +typedef struct _GstBsTest GstBsTest; +typedef struct _GstBsTestClass GstBsTestClass; + +struct _GstBsTest +{ + GstElement element; + + GstPad *sinkpad; + GstPad *srcpad; + + GstByteStream *bs; + + gchar *accesspattern; + guint num_patterns; + gchar **patterns; + guint sizemin; + guint sizemax; + gint count; + gboolean silent; +}; + +struct _GstBsTestClass +{ + GstElementClass parent_class; +}; + +GType gst_bstest_get_type (void); + + +GstElementDetails gst_bstest_details = { + "ByteStreamTest", + "Filter", + "Test for the GstByteStream code", + VERSION, + "Erik Walthinsen ," "Wim Taymans ", + "(C) 2001", +}; + + +/* BsTest signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + ARG_0, + ARG_SIZEMIN, + ARG_SIZEMAX, + ARG_COUNT, + ARG_SILENT, + ARG_ACCESSPATTERN, +}; + + +static void gst_bstest_class_init (GstBsTestClass * klass); +static void gst_bstest_init (GstBsTest * bstest); + +static void gst_bstest_set_property (GObject * object, guint prop_id, const GValue * value, + GParamSpec * pspec); +static void gst_bstest_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec); + +static GstElementStateReturn gst_bstest_change_state (GstElement *element); +static void gst_bstest_loop (GstElement * element); + +static GstElementClass *parent_class = NULL; + +// static guint gst_bstest_signals[LAST_SIGNAL] = { 0 }; + +GType +gst_bstest_get_type (void) +{ + static GType bstest_type = 0; + + if (!bstest_type) { + static const GTypeInfo bstest_info = { + sizeof (GstBsTestClass), NULL, + NULL, + (GClassInitFunc) gst_bstest_class_init, + NULL, + NULL, + sizeof (GstBsTest), + 0, + (GInstanceInitFunc) gst_bstest_init, + }; + + bstest_type = g_type_register_static (GST_TYPE_ELEMENT, "BSTest", &bstest_info, 0); + } + return bstest_type; +} + +static void +gst_bstest_class_init (GstBsTestClass * 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_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, + 384, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ACCESSPATTERN, + g_param_spec_string ("accesspattern", "accesspattern", "accesspattern", + "r", 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)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT, + g_param_spec_boolean ("silent", "silent", "silent", + FALSE, G_PARAM_READWRITE)); + + gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_bstest_set_property); + gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_bstest_get_property); + + gstelement_class->change_state = gst_bstest_change_state; + +} + +static GstPadNegotiateReturn +gst_bstest_negotiate_src (GstPad * pad, GstCaps ** caps, gpointer * data) +{ + GstBsTest *bstest; + + bstest = GST_BSTEST (gst_pad_get_parent (pad)); + + return gst_pad_negotiate_proxy (pad, bstest->sinkpad, caps); +} + +static GstPadNegotiateReturn +gst_bstest_negotiate_sink (GstPad * pad, GstCaps ** caps, gpointer * data) +{ + GstBsTest *bstest; + + bstest = GST_BSTEST (gst_pad_get_parent (pad)); + + return gst_pad_negotiate_proxy (pad, bstest->srcpad, caps); +} + +static void +gst_bstest_init (GstBsTest * bstest) +{ + bstest->sinkpad = gst_pad_new ("sink", GST_PAD_SINK); + gst_element_add_pad (GST_ELEMENT (bstest), bstest->sinkpad); + gst_pad_set_negotiate_function (bstest->sinkpad, gst_bstest_negotiate_sink); + + bstest->srcpad = gst_pad_new ("src", GST_PAD_SRC); + gst_element_add_pad (GST_ELEMENT (bstest), bstest->srcpad); + gst_pad_set_negotiate_function (bstest->srcpad, gst_bstest_negotiate_src); + + gst_element_set_loop_function (GST_ELEMENT (bstest), gst_bstest_loop); + + bstest->sizemin = 0; + bstest->sizemax = 384; + bstest->accesspattern = g_strdup ("r"); + bstest->patterns = g_strsplit (bstest->accesspattern, ":", 0); + bstest->count = 5; + bstest->silent = FALSE; + bstest->bs = NULL; +} + +static guint +gst_bstest_get_size (GstBsTest *bstest, gchar *sizestring, guint prevsize) +{ + guint size; + + if (sizestring[0] == 0) { + size = bstest->sizemax; + } + else if (sizestring[0] == 'r') { + size = bstest->sizemin + (guint8)(((gfloat)bstest->sizemax)*rand()/(RAND_MAX + (gfloat)bstest->sizemin)); + } + else if (sizestring[0] == '<') { + size = prevsize; + } + else { + size = atoi (sizestring); + } + + if (size == 0) size++; + + return size; +} + +static void +gst_bstest_loop (GstElement * element) +{ + GstBsTest *bstest; + GstBuffer *buf = NULL; + + g_return_if_fail (element != NULL); + g_return_if_fail (GST_IS_BSTEST (element)); + + bstest = GST_BSTEST (element); + + do { + guint size = 0; + guint i = 0; + + while (i < bstest->num_patterns) { + buf = NULL; + + if (bstest->patterns[i][0] == 'r') { + size = gst_bstest_get_size (bstest, &bstest->patterns[i][1], size); + if (!bstest->silent) g_print ("bstest: ***** read %d bytes\n", size); + buf = gst_bytestream_read (bstest->bs, size); + } + else if (bstest->patterns[i][0] == 'f') { + size = gst_bstest_get_size (bstest, &bstest->patterns[i][1], size); + if (!bstest->silent) g_print ("bstest: ***** flush %d bytes\n", size); + gst_bytestream_flush (bstest->bs, size); + } + else if (!strncmp (bstest->patterns[i], "pb", 2)) { + size = gst_bstest_get_size (bstest, &bstest->patterns[i][2], size); + if (!bstest->silent) g_print ("bstest: ***** peek bytes %d bytes\n", size); + gst_bytestream_peek_bytes (bstest->bs, size); + } + else if (bstest->patterns[i][0] == 'p') { + size = gst_bstest_get_size (bstest, &bstest->patterns[i][1], size); + if (!bstest->silent) g_print ("bstest: ***** peek %d bytes\n", size); + buf = gst_bytestream_peek (bstest->bs, size); + gst_buffer_unref (buf); + buf = NULL; + } + + if (buf) + gst_pad_push (bstest->srcpad, buf); + + i++; + } + } while (!GST_ELEMENT_IS_COTHREAD_STOPPING (element)); +} + +static void +gst_bstest_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstBsTest *bstest; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail (GST_IS_BSTEST (object)); + + bstest = GST_BSTEST (object); + + switch (prop_id) { + case ARG_SIZEMIN: + bstest->sizemin = g_value_get_int (value); + break; + case ARG_SIZEMAX: + bstest->sizemax = g_value_get_int (value); + break; + case ARG_ACCESSPATTERN: + if (bstest->accesspattern) { + g_free (bstest->accesspattern); + g_strfreev (bstest->patterns); + } + if (g_value_get_string (value) == NULL) { + gst_element_set_state (GST_ELEMENT (object), GST_STATE_NULL); + bstest->accesspattern = NULL; + bstest->num_patterns = 0; + } else { + guint i = 0; + + bstest->accesspattern = g_strdup (g_value_get_string (value)); + bstest->patterns = g_strsplit (bstest->accesspattern, ":", 0); + while (bstest->patterns[i++]); + bstest->num_patterns = i-1; + } + break; + case ARG_COUNT: + bstest->count = g_value_get_uint (value); + break; + case ARG_SILENT: + bstest->silent = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_bstest_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstBsTest *bstest; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail (GST_IS_BSTEST (object)); + + bstest = GST_BSTEST (object); + + switch (prop_id) { + case ARG_SIZEMIN: + g_value_set_int (value, bstest->sizemin); + break; + case ARG_SIZEMAX: + g_value_set_int (value, bstest->sizemax); + break; + case ARG_ACCESSPATTERN: + g_value_set_string (value, bstest->accesspattern); + break; + case ARG_COUNT: + g_value_set_uint (value, bstest->count); + break; + case ARG_SILENT: + g_value_set_boolean (value, bstest->silent); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstElementStateReturn +gst_bstest_change_state (GstElement *element) +{ + GstBsTest *bstest; + + g_return_val_if_fail (GST_IS_BSTEST (element), GST_STATE_FAILURE); + + bstest = GST_BSTEST (element); + + if (GST_STATE_PENDING (element) == GST_STATE_NULL) { + if (bstest->bs) { + gst_bytestream_destroy (bstest->bs); + bstest->bs = NULL; + } + } + else { + if (!bstest->bs) { + bstest->bs = gst_bytestream_new (bstest->sinkpad); + } + } + + if (GST_ELEMENT_CLASS (parent_class)->change_state) + return GST_ELEMENT_CLASS (parent_class)->change_state (element); + + return GST_STATE_SUCCESS; +} + +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 ("bstest", GST_TYPE_BSTEST, &gst_bstest_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; +} + +GST_PLUGIN_DESC (GST_VERSION_MAJOR, GST_VERSION_MINOR, "bstest", plugin_init); diff --git a/testsuite/bytestream/mem.c b/testsuite/bytestream/mem.c new file mode 100644 index 0000000000..d1c36cb5aa --- /dev/null +++ b/testsuite/bytestream/mem.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include +#include + +int vmsize() { + int pid,fd,size,i,mem; + char filename[17], buf[256], *ptr, *end; + + pid = getpid(); + snprintf(filename,17,"/proc/%d/stat",pid); + fd = open(filename,O_RDONLY); + size = read(fd,buf,240); + ptr = buf; + for (i=0;i<22;i++) + ptr = (char *)strchr(ptr,' ') + 1; + end = (char *)strchr(ptr,' '); + *end = 0; + sscanf(ptr,"%d",&mem); + close(fd); + return mem; +} diff --git a/testsuite/bytestream/mem.h b/testsuite/bytestream/mem.h new file mode 100644 index 0000000000..28999db2c3 --- /dev/null +++ b/testsuite/bytestream/mem.h @@ -0,0 +1 @@ +int vmsize(); diff --git a/testsuite/bytestream/test1.c b/testsuite/bytestream/test1.c new file mode 100644 index 0000000000..0670849e84 --- /dev/null +++ b/testsuite/bytestream/test1.c @@ -0,0 +1,230 @@ +#include +#include + +#include +#include "mem.h" + +#define VM_THRES 1000 +#define MAX_CONFIG_LINE 255 +#define MAX_CONFIG_PATTERN 64 + +typedef struct +{ + gint src_data; + gint src_sizetype; + + gchar *bs_accesspattern; + + gboolean integrity_check; +} TestParam; + +static GSList *params = NULL; + +static guint8 count; +static guint iterations; +static gboolean integrity_check = TRUE; +static gboolean verbose = FALSE; +static gboolean dump = FALSE; + +static void +handoff (GstElement *element, GstBuffer *buf, GstPad *pad, gpointer data) +{ + if (GST_IS_BUFFER (buf)) { + if (integrity_check) { + gint i; + guint8 *ptr = GST_BUFFER_DATA (buf); + + for (i=0; isrc_sizetype == 2 ? "fixed" : "random"), + (param->src_data == 1 ? "src" : "subbuffer"), + param->bs_accesspattern); + return desc; +} + +static gboolean +read_param_file (gchar *filename) +{ + FILE *fp; + gchar line[MAX_CONFIG_LINE+1]; + guint linenr = 0; + gchar pattern[MAX_CONFIG_PATTERN]; + gint data, sizetype, integrity_check; + gchar *scan_str; + gboolean res = TRUE; + + fp = fopen (filename, "r"); + if (fp == NULL) + return FALSE; + + scan_str = g_strdup_printf ("%%d %%d %%%ds %%d", MAX_CONFIG_PATTERN-1); + + while (fgets (line, MAX_CONFIG_LINE, fp)) { + linenr++; + + if (line[0] == '\n' || line[0] == '#') + continue; + + if (sscanf (line, scan_str, &data, &sizetype, pattern, &integrity_check) != 4) { + g_print ("error on line: %d\n", linenr); + res = FALSE; + break; + } + else { + TestParam *param = g_malloc (sizeof (TestParam)); + + param->src_data = data; + param->src_sizetype = sizetype; + param->bs_accesspattern = g_strdup (pattern); + param->integrity_check = (integrity_check == 0 ? FALSE : TRUE); + + params = g_slist_append (params, param); + } + } + g_free (scan_str); + + return res; +} + +static void +run_test (GstBin *pipeline, gint iters) +{ + gint vm = 0; + gint maxiters = iters; + gint prev_percent = -1; + + count = 0; + gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING); + + while (iters) { + gint newvm = vmsize(); + gint percent; + + percent = (gint)((maxiters-iters+1)*100.0/maxiters); + + if (percent != prev_percent || newvm - vm > VM_THRES) { + g_print ("\r%d (delta %d) %.3d%% ", newvm, newvm - vm, percent); + prev_percent = percent; + vm = newvm; + } + gst_bin_iterate (pipeline); + + if (iters > 0) iters--; + } + gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); +} + +static void +usage (char *argv[]) +{ + g_print ("usage: %s [--verbose] [--dump] \n", argv[0]); +} + +int +main (int argc, char *argv[]) +{ + GstElement *src; + GstElement *sink; + GstElement *bs; + GstElement *pipeline; + gint testnum = 0; + GSList *walk; + gint arg_walk; + + gst_init (&argc, &argv); + + arg_walk = 1; + while ((arg_walk < argc) && (argv[arg_walk][0] == '-')) { + if (!strncmp (argv[arg_walk], "--verbose", 9)) + verbose = TRUE; + else if (!strncmp (argv[arg_walk], "--dump", 6)) + dump = TRUE; + else { + g_print ("unknown option %s (ignored)\n", argv[arg_walk]); + } + + arg_walk++; + } + if (argc - arg_walk < 2) { + usage(argv); + return -1; + } + if (!read_param_file (argv[arg_walk])) { + g_print ("error reading file %s\n", argv[arg_walk]); + usage (argv); + return -1; + } + arg_walk++; + iterations = atoi (argv[arg_walk]); + + pipeline = gst_elementfactory_make ("pipeline", "pipeline"); + g_assert (pipeline); + + src = gst_elementfactory_make ("fakesrc", "src"); + g_assert (src); + + sink = gst_elementfactory_make ("fakesink", "sink"); + g_assert (sink); + g_signal_connect (G_OBJECT (sink), "handoff", G_CALLBACK (handoff), NULL); + + bs = gst_elementfactory_make ("bstest", "bs"); + g_assert (bs); + + gst_element_connect (src, "src", bs, "sink"); + gst_element_connect (bs, "src", sink, "sink"); + + gst_bin_add (GST_BIN (pipeline), src); + gst_bin_add (GST_BIN (pipeline), bs); + gst_bin_add (GST_BIN (pipeline), sink); + + walk = params; + + while (walk) { + gchar *desc; + TestParam *param = (TestParam *) (walk->data); + + integrity_check = param->integrity_check; + + g_print ("\n\nrunning test %d (%d iterations):\n", testnum+1, iterations); + desc = create_desc (param); + g_print ("%s\n", desc); + g_free (desc); + + g_object_set (G_OBJECT (src), "data", param->src_data, + "sizetype", param->src_sizetype, + "filltype", (integrity_check?5:0), + "silent", !verbose, NULL); + + g_object_set (G_OBJECT (bs), "accesspattern", param->bs_accesspattern, + "silent", !verbose, NULL); + + g_object_set (G_OBJECT (sink), "dump", dump, + "silent", !verbose, NULL); + + run_test (GST_BIN (pipeline), iterations); + + testnum++; + + walk = g_slist_next (walk); + } + + g_print ("\n\ndone\n"); + + return 0; + +} diff --git a/testsuite/bytestream/testfile1 b/testsuite/bytestream/testfile1 new file mode 100644 index 0000000000..68a32dd582 --- /dev/null +++ b/testsuite/bytestream/testfile1 @@ -0,0 +1,93 @@ +# lots of parameters here. values for the columns are like: +# +# - data property in fakesrc: 1 = allocate, 2 = subbuffer +# - sizetype property in fakesrc: 2 = fixed, 3 = random +# +# - accesspattern for bstest +# [:...] +# +# can be: +# r = read +# p = peek +# pb = peek bytes +# f = flush +# can be: +# = fixed size +# r = random size +# < = previous size +# = this size +# +# - integrity check: 0 = no, 1 = yes +# +1 2 r 1 +1 2 rr 1 +1 3 r 1 +1 3 rr 1 +2 2 r 1 +2 2 rr 1 +2 3 r 1 +2 3 rr 1 +1 2 p:r< 1 +1 2 pr:r< 1 +1 3 p:r< 1 +1 3 pr:r< 1 +2 2 p:r< 1 +2 2 pr:r< 1 +2 3 p:r< 1 +2 3 pr:r< 1 +1 2 p:rr 1 +1 2 pr:rr 1 +1 3 p:rr 1 +1 3 pr:rr 1 +2 2 p:rr 1 +2 2 pr:rr 1 +2 3 p:rr 1 +2 3 pr:rr 1 +1 2 pb:r 1 +1 2 pbr:r 1 +1 3 pb:r 1 +1 3 pbr:r 1 +2 2 pb:r 1 +2 2 pbr:r 1 +2 3 pb:r 1 +2 3 pbr:r 1 +1 2 pb:rr 1 +1 2 pbr:rr 1 +1 3 pb:rr 1 +1 3 pbr:rr 1 +2 2 pb:rr 1 +2 2 pbr:rr 1 +2 3 pb:rr 1 +2 3 pbr:rr 1 +1 2 p:fr:rr 0 +1 2 pr:fr:rr 0 +1 3 p:fr:rr 0 +1 3 pr:fr:rr 0 +2 2 p:fr:rr 0 +2 2 pr:fr:rr 0 +2 3 p:fr:rr 0 +2 3 pr:fr:rr 0 +1 2 fr:rr 0 +1 2 fr:rr 0 +1 3 fr:rr 0 +1 3 fr:rr 0 +2 2 fr:rr 0 +2 2 fr:rr 0 +2 3 fr:rr 0 +2 3 fr:rr 0 +1 2 fr:fr:rr 0 +1 2 fr:fr:rr 0 +1 3 fr:fr:rr 0 +1 3 fr:fr:rr 0 +2 2 fr:fr:rr 0 +2 2 fr:fr:rr 0 +2 3 fr:fr:rr 0 +2 3 fr:fr:rr 0 +1 2 pbr:pbr:rr 1 +1 2 pbr:pbr:rr 1 +1 3 pbr:pbr:rr 1 +1 3 pbr:pbr:rr 1 +2 2 pbr:pbr:rr 1 +2 2 pbr:pbr:rr 1 +2 3 pbr:pbr:rr 1 +2 3 pbr:pbr:rr 1 diff --git a/tools/Makefile.am b/tools/Makefile.am index b45f29d3de..bef06f9476 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -5,6 +5,12 @@ else GST_REGISTRY_SRC = gstreamer-register endif +if GST_DISABLE_LOADSAVE +GST_LOADSAVE_SRC = +else +GST_LOADSAVE_SRC = gstreamer-compprep +endif + if USE_GLIB2 GST_GUI_LAUNCH = else @@ -12,16 +18,16 @@ GST_GUI_LAUNCH = gstreamer-guilaunch endif bin_PROGRAMS = gstreamer-launch \ - $(GST_GUI_LAUNCH) \ + $(GST_GUI_LAUNCH) \ $(GST_REGISTRY_SRC) \ gstreamer-inspect \ - gstreamer-compprep \ + $(GST_LOADSAVE_SRC) \ gstreamer-complete man_MANS = gstreamer-launch.1 gstreamer-register.1 gstreamer-inspect.1 \ gstreamer-complete.1 gstreamer-compprep.1 LDADD = $(GST_LIBS) -CFLAGS = $(LIBGST_CFLAGS) -DGST_CONFIG_DIR=\"$(GST_CONFIG_DIR)\" +CFLAGS = $(LIBGST_CFLAGS) -DGST_CONFIG_DIR=\"$(GST_CONFIG_DIR)\" EXTRA_DIST = $(man_MANS) diff --git a/tools/gstreamer-inspect.c b/tools/gstreamer-inspect.c index 2ec45ac589..6ac84be18a 100644 --- a/tools/gstreamer-inspect.c +++ b/tools/gstreamer-inspect.c @@ -221,10 +221,12 @@ print_element_info (GstElementFactory *factory) printf(" Has change_state() function: %s\n", GST_DEBUG_FUNCPTR_NAME(gstelement_class->change_state)); +#ifndef GST_DISABLE_LOADSAVE printf(" Has custom save_thyself() function: %s\n", GST_DEBUG_FUNCPTR_NAME(gstobject_class->save_thyself)); printf(" Has custom restore_thyself() function: %s\n", GST_DEBUG_FUNCPTR_NAME(gstobject_class->restore_thyself)); +#endif diff --git a/tools/gstreamer-launch.c b/tools/gstreamer-launch.c index af7a494685..821bb38c8a 100644 --- a/tools/gstreamer-launch.c +++ b/tools/gstreamer-launch.c @@ -61,7 +61,11 @@ arg_search (GstBin *bin, gchar *argname, found_handler handler, void *priv) gboolean idle_func (gpointer data) { - return gst_bin_iterate (GST_BIN (data)); + if (!gst_bin_iterate (GST_BIN (data))) { + gtk_main_quit (); + return FALSE; + } + return TRUE; } void @@ -148,9 +152,11 @@ main(int argc, char *argv[]) gst_parse_launch (cmdline, GST_BIN (pipeline)); +#ifndef GST_DISABLE_LOADSAVE if (save_pipeline) { xmlSaveFile (savefile, gst_xml_write (pipeline)); } +#endif if (run_pipeline) { arg_search(GST_BIN(pipeline),"xid",xid_handler,NULL);