diff --git a/livesupport/modules/gstreamerElements/etc/Makefile.in b/livesupport/modules/gstreamerElements/etc/Makefile.in index 13ddf4953..35f626164 100644 --- a/livesupport/modules/gstreamerElements/etc/Makefile.in +++ b/livesupport/modules/gstreamerElements/etc/Makefile.in @@ -21,7 +21,7 @@ # # # Author : $Author: maroy $ -# Version : $Revision: 1.4 $ +# Version : $Revision: 1.5 $ # Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/gstreamerElements/etc/Makefile.in,v $ # # @configure_input@ @@ -76,6 +76,9 @@ TEST_RESULTS = ${DOC_DIR}/testResults.xml # the text result XSLT has to be relative to the test result file, e.g. TMP_DIR TEST_XSLT = ../etc/testResultToHtml.xsl +GSTREAMER_ELEMENTS_LIB = livesupport_gstreamerelements +GSTREAMER_ELEMENTS_LIB_FILE = ${LIB_DIR}/lib${GSTREAMER_ELEMENTS_LIB}.a + ONESHOT_READER_LIB = livesupport_oneshotreader ONESHOT_READER_LIB_FILE = ${LIB_DIR}/lib${ONESHOT_READER_LIB}.so MINIMAL_AUDIO_SMIL_LIB = livesupport_minimalaudiosmil @@ -122,26 +125,22 @@ LDFLAGS = @LDFLAGS@ ${GSTREAMER_LIBS} \ #------------------------------------------------------------------------------- # Dependencies #------------------------------------------------------------------------------- +GSTREAMER_ELEMENTS_LIB_OBJS = ${TMP_DIR}/seek.o \ + ${TMP_DIR}/util.o \ + ${TMP_DIR}/seek-pack.o \ + ${TMP_DIR}/autoplug.o \ + ${TMP_DIR}/smil-util.o + ONESHOT_READER_LIB_OBJS = ${TMP_DIR}/oneshot-reader.o -MINIMAL_AUDIO_SMIL_LIB_OBJS = ${TMP_DIR}/seek.o \ - ${TMP_DIR}/util.o \ - ${TMP_DIR}/seek-pack.o \ - ${TMP_DIR}/minimal-audio-smil.o +MINIMAL_AUDIO_SMIL_LIB_OBJS = ${TMP_DIR}/minimal-audio-smil.o -PARTIAL_PLAY_LIB_OBJS = ${TMP_DIR}/seek.o \ - ${TMP_DIR}/util.o \ - ${TMP_DIR}/seek-pack.o \ - ${TMP_DIR}/smil-util.o \ - ${TMP_DIR}/partial-play.o +PARTIAL_PLAY_LIB_OBJS = ${TMP_DIR}/partial-play.o -SWITCHER_LIB_OBJS = ${TMP_DIR}/smil-util.o \ - ${TMP_DIR}/switcher.o +SWITCHER_LIB_OBJS = ${TMP_DIR}/switcher.o TEST_RUNNER_OBJS = ${TMP_DIR}/TestRunner.o \ - ${TMP_DIR}/seek.o \ - ${TMP_DIR}/util.o \ - ${TMP_DIR}/seek-pack.o \ + ${TMP_DIR}/AutoplugTest.o \ ${TMP_DIR}/SeekTest.o \ ${TMP_DIR}/SwitcherTest.o \ ${TMP_DIR}/SeekPackTest.o \ @@ -149,7 +148,8 @@ TEST_RUNNER_OBJS = ${TMP_DIR}/TestRunner.o \ ${TMP_DIR}/OneshotReaderTest.o \ ${TMP_DIR}/MinimalAudioSmilTest.o -TEST_RUNNER_LIBS = -l${CORE_LIB} -lcppunit -ldl -lxmlrpc++ +TEST_RUNNER_LIBS = -l${GSTREAMER_ELEMENTS_LIB} -l${CORE_LIB} \ + -lcppunit -ldl -lxmlrpc++ #------------------------------------------------------------------------------- @@ -157,7 +157,8 @@ TEST_RUNNER_LIBS = -l${CORE_LIB} -lcppunit -ldl -lxmlrpc++ #------------------------------------------------------------------------------- .PHONY: all dir_setup doc clean docclean depclean distclean -all: dir_setup ${ONESHOT_READER_LIB_FILE} \ +all: dir_setup ${GSTREAMER_ELEMENTS_LIB_FILE} \ + ${ONESHOT_READER_LIB_FILE} \ ${MINIMAL_AUDIO_SMIL_LIB_FILE} \ ${PARTIAL_PLAY_LIB_FILE} \ ${SWITCHER_LIB_FILE} \ @@ -172,6 +173,7 @@ doc: ${DOXYGEN} ${DOXYGEN_CONFIG} clean: + ${RM} ${GSTREAMER_ELEMENTS_LIB_OBJS} ${GSTREAMER_ELEMENTS_LIB_FILE} ${RM} ${ONESHOT_READER_LIB_OBJS} ${ONESHOT_READER_LIB_FILE} ${RM} ${MINIMAL_AUDIO_SMIL_LIB_OBJS} ${MINIMAL_AUDIO_SMIL_LIB_FILE} ${RM} ${PARTIAL_PLAY_LIB_OBJS} ${PARTIAL_PLAY_LIB_FILE} @@ -196,17 +198,24 @@ check: all ${TEST_RUNNER} #------------------------------------------------------------------------------- # Specific targets #------------------------------------------------------------------------------- -${ONESHOT_READER_LIB_FILE}: ${ONESHOT_READER_LIB_OBJS} +${GSTREAMER_ELEMENTS_LIB_FILE}: ${GSTREAMER_ELEMENTS_LIB_OBJS} + ${AR} crus $@ $^ + +${ONESHOT_READER_LIB_FILE}: ${GSTREAMER_ELEMENTS_LIB_FILE} \ + ${ONESHOT_READER_LIB_OBJS} ${CC} -shared -o $@ $^ ${GST_LDFLAGS} -${MINIMAL_AUDIO_SMIL_LIB_FILE}: ${MINIMAL_AUDIO_SMIL_LIB_OBJS} - ${CC} -shared ${GST_LDFLAGS} -o $@ $^ +${MINIMAL_AUDIO_SMIL_LIB_FILE}: ${GSTREAMER_ELEMENTS_LIB_FILE} \ + ${MINIMAL_AUDIO_SMIL_LIB_OBJS} + ${CC} -shared -o $@ $^ ${GST_LDFLAGS} -${PARTIAL_PLAY_LIB_FILE}: ${PARTIAL_PLAY_LIB_OBJS} - ${CC} -shared ${GST_LDFLAGS} -o $@ $^ +${PARTIAL_PLAY_LIB_FILE}: ${GSTREAMER_ELEMENTS_LIB_FILE} \ + ${PARTIAL_PLAY_LIB_OBJS} + ${CC} -shared -o $@ $^ ${GST_LDFLAGS} -${SWITCHER_LIB_FILE}: ${SWITCHER_LIB_OBJS} - ${CC} -shared ${GST_LDFLAGS} -o $@ $^ +${SWITCHER_LIB_FILE}: ${SWITCHER_LIB_OBJS} \ + ${GSTREAMER_ELEMENTS_LIB_FILE} + ${CC} -shared -o $@ $^ ${GST_LDFLAGS} ${TMP_DIR}: ${MKDIR} ${TMP_DIR} @@ -214,7 +223,8 @@ ${TMP_DIR}: ${DOXYGEN_DIR}: ${MKDIR} ${DOXYGEN_DIR} -${TEST_RUNNER}: ${CORE_LIB_FILE} ${TEST_RUNNER_OBJS} +${TEST_RUNNER}: ${CORE_LIB_FILE} ${GSTREAMER_ELEMENTS_LIB_FILE} \ + ${TEST_RUNNER_OBJS} ${CXX} ${LDFLAGS} -o $@ ${TEST_RUNNER_OBJS} ${TEST_RUNNER_LIBS} ${CORE_LIB_FILE}: diff --git a/livesupport/modules/gstreamerElements/src/AutoplugTest.cxx b/livesupport/modules/gstreamerElements/src/AutoplugTest.cxx new file mode 100644 index 000000000..64993f7db --- /dev/null +++ b/livesupport/modules/gstreamerElements/src/AutoplugTest.cxx @@ -0,0 +1,169 @@ +/*------------------------------------------------------------------------------ + + Copyright (c) 2004 Media Development Loan Fund + + This file is part of the LiveSupport project. + http://livesupport.campware.org/ + To report bugs, send an e-mail to bugs@campware.org + + LiveSupport is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + LiveSupport 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LiveSupport; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + Author : $Author: maroy $ + Version : $Revision: 1.1 $ + Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/gstreamerElements/src/AutoplugTest.cxx,v $ + +------------------------------------------------------------------------------*/ + +/* ============================================================ include files */ + +#ifdef HAVE_CONFIG_H +#include "configure.h" +#endif + +#include +#include + +#include + +#include "autoplug.h" +#include "AutoplugTest.h" + + +using namespace LiveSupport::GstreamerElements; + +/* =================================================== local data structures */ + + +/* ================================================ local constants & macros */ + +CPPUNIT_TEST_SUITE_REGISTRATION(AutoplugTest); + +/** + * An mp3 test file. + */ +static const char * mp3TestFile = "var/5seccounter.mp3"; + +/** + * An ogg vorbis test file. + */ +static const char * oggTestFile = "var/5seccounter.ogg"; + + +/* =============================================== local function prototypes */ + + +/* ============================================================= module code */ + +/*------------------------------------------------------------------------------ + * Set up the test environment + *----------------------------------------------------------------------------*/ +void +AutoplugTest :: setUp(void) throw () +{ +} + + +/*------------------------------------------------------------------------------ + * Clean up the test environment + *----------------------------------------------------------------------------*/ +void +AutoplugTest :: tearDown(void) throw () +{ +} + + +/*------------------------------------------------------------------------------ + * Play an audio file + *----------------------------------------------------------------------------*/ +gint64 +AutoplugTest :: playFile(const char * audioFile) + throw (CPPUNIT_NS::Exception) +{ + GstElement * pipeline; + GstElement * source; + GstElement * decoder; + GstElement * sink; + GstFormat format; + gint64 timePlayed; + + /* initialize GStreamer */ + gst_init(0, 0); + + /* create elements */ + pipeline = gst_pipeline_new("audio-player"); + source = gst_element_factory_make("filesrc", "source"); + sink = gst_element_factory_make("alsasink", "alsa-output"); + + g_object_set(G_OBJECT(source), "location", audioFile, NULL); + + decoder = autoplug_plug_source(source); + + gst_element_link(decoder, sink); + gst_bin_add_many(GST_BIN(pipeline), source, decoder, sink, NULL); + + gst_element_set_state(source, GST_STATE_PAUSED); + gst_element_set_state(decoder, GST_STATE_PAUSED); + gst_element_set_state(sink, GST_STATE_PAUSED); + gst_element_set_state(pipeline, GST_STATE_PLAYING); + gst_bin_sync_children_state(GST_BIN(pipeline)); + + // iterate until playTo is reached + while (gst_bin_iterate(GST_BIN(pipeline))); + + format = GST_FORMAT_TIME; + gst_element_query(sink, GST_QUERY_POSITION, &format, &timePlayed); + + /* clean up nicely */ + gst_element_set_state(pipeline, GST_STATE_NULL); + gst_object_unref(GST_OBJECT (pipeline)); + + return timePlayed; +} + + +/*------------------------------------------------------------------------------ + * A simple smoke test. + *----------------------------------------------------------------------------*/ +void +AutoplugTest :: firstTest(void) + throw (CPPUNIT_NS::Exception) +{ + gint64 timePlayed; + char str[256]; + + timePlayed = playFile(mp3TestFile); + g_snprintf(str, 256, "time played: %" G_GINT64_FORMAT, timePlayed); + CPPUNIT_ASSERT_MESSAGE(str, timePlayed > 4.9 * GST_SECOND); + CPPUNIT_ASSERT_MESSAGE(str, timePlayed < 5.1 * GST_SECOND); +} + + +/*------------------------------------------------------------------------------ + * An ogg vorbis test. + *----------------------------------------------------------------------------*/ +void +AutoplugTest :: oggVorbisTest(void) + throw (CPPUNIT_NS::Exception) +{ + gint64 timePlayed; + char str[256]; + + timePlayed = playFile(oggTestFile); + g_snprintf(str, 256, "time played: %" G_GINT64_FORMAT, timePlayed); + CPPUNIT_ASSERT_MESSAGE(str, timePlayed > 4.9 * GST_SECOND); + CPPUNIT_ASSERT_MESSAGE(str, timePlayed < 5.1 * GST_SECOND); +} + diff --git a/livesupport/modules/gstreamerElements/src/AutoplugTest.h b/livesupport/modules/gstreamerElements/src/AutoplugTest.h new file mode 100644 index 000000000..e65a8450e --- /dev/null +++ b/livesupport/modules/gstreamerElements/src/AutoplugTest.h @@ -0,0 +1,129 @@ +/*------------------------------------------------------------------------------ + + Copyright (c) 2004 Media Development Loan Fund + + This file is part of the LiveSupport project. + http://livesupport.campware.org/ + To report bugs, send an e-mail to bugs@campware.org + + LiveSupport is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + LiveSupport 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LiveSupport; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + Author : $Author: maroy $ + Version : $Revision: 1.1 $ + Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/gstreamerElements/src/AutoplugTest.h,v $ + +------------------------------------------------------------------------------*/ +#ifndef AutoplugTest_h +#define AutoplugTest_h + +#ifndef __cplusplus +#error This is a C++ include file +#endif + + +/* ============================================================ include files */ + +#ifdef HAVE_CONFIG_H +#include "configure.h" +#endif + +#include + + +namespace LiveSupport { +namespace GstreamerElements { + +/* ================================================================ constants */ + + +/* =================================================================== macros */ + + +/* =============================================================== data types */ + +/** + * Unit test for the partialplay gstreamer element. + * + * @author $Author: maroy $ + * @version $Revision: 1.1 $ + */ +class AutoplugTest : public CPPUNIT_NS::TestFixture +{ + CPPUNIT_TEST_SUITE(AutoplugTest); + CPPUNIT_TEST(firstTest); + CPPUNIT_TEST(oggVorbisTest); + CPPUNIT_TEST_SUITE_END(); + + private: + + /** + * Play a specific file, from and until a specific timepoint. + * + * @param audioFile the audio file to play. + * @return the number of milliseconds played. + * @exception CPPUNIT_NS::Exception on test failures. + */ + gint64 + playFile(const char * audioFile) + throw (CPPUNIT_NS::Exception); + + + protected: + + /** + * A simple smoke test. + * + * @exception CPPUNIT_NS::Exception on test failures. + */ + void + firstTest(void) throw (CPPUNIT_NS::Exception); + + /** + * Test an Ogg Vorbis file. + * + * @exception CPPUNIT_NS::Exception on test failures. + */ + void + oggVorbisTest(void) throw (CPPUNIT_NS::Exception); + + + public: + + /** + * Set up the environment for the test case. + */ + void + setUp(void) throw (); + + /** + * Clean up the environment after the test case. + */ + void + tearDown(void) throw (); +}; + + +/* ================================================= external data structures */ + + +/* ====================================================== function prototypes */ + + +} // namespace GstreamerElements +} // namespace LiveSupport + +#endif // AutoplugTest_h + diff --git a/livesupport/modules/gstreamerElements/src/autoplug.c b/livesupport/modules/gstreamerElements/src/autoplug.c new file mode 100644 index 000000000..496585289 --- /dev/null +++ b/livesupport/modules/gstreamerElements/src/autoplug.c @@ -0,0 +1,634 @@ +/*------------------------------------------------------------------------------ + + Copyright (c) 2004 Media Development Loan Fund + + This file is part of the LiveSupport project. + http://livesupport.campware.org/ + To report bugs, send an e-mail to bugs@campware.org + + LiveSupport is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + LiveSupport 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LiveSupport; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + This code is based on the examples/manual/dynamic.c sample file + provided in the gstreamer-0.8.10 source tarball, which is published + under the GNU LGPL license. + + + Author : $Author: maroy $ + Version : $Revision: 1.1 $ + Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/gstreamerElements/src/autoplug.c,v $ + +------------------------------------------------------------------------------*/ + +/* ============================================================ include files */ + +#include + +#include "autoplug.h" + + +/* =================================================== local data structures */ + +typedef struct _Typefind Typefind; + +/** + * Data structure to hold information related to typefindinf. + */ +struct _Typefind { + GList * factories; + + GstElement * pipeline; + GstElement * bin; + GstElement * source; + GstElement * typefind; + GstElement * audiosink; + GstElement * sink; + + gulong typefindSignal; + + gboolean done; +}; + + +/* ================================================ local constants & macros */ + + +/* =============================================== local function prototypes */ + +/** + * Handle typefinding error. + * + * @param pipeline the pipeline generating the error. + * @param source the source element with the error + * @param error the error itself. + * @param message the error message. + * @param userData user-specific data. + */ +static void +autoplug_error_handler(GstElement * pipeline, + GstElement * source, + GError * error, + gchar * message, + gpointer userData); + +/** + * Handle event of the typefinder finding a type. + * + * @param typefind the typefind element that found the type. + * @param probability the probability of the find. + * @param caps the found capabilities. + * @param userData user-specific data, a pointer to a related Typefind + * structure. + */ +static void +autoplug_typefound_handler(GstElement * typefind, + gint probability, + GstCaps * caps, + gpointer userData); + +/** + * Initialize a typefind object. + * + * @param typefind the Typefind structure to init. + */ +static void +autoplug_init(Typefind * typefind); + +/** + * A filter specifying the kind of factories we're interested in. + * + * @param feature the feature to test + * @param userData user-specific data + * @return TRUE if we're interested in the supplied feature, FALSE otherwise + */ +static gboolean +autoplug_feature_filter(GstPluginFeature * feature, + gpointer userData); + +/** + * A comparison function based on the ranks of two features. + * + * @param feature1 one of the features to compare. + * @param feature2 the other feature to compare. + * @return 0 if the two features match in terms of their ranks, + * <0 if feature1 is higher, >0 if feature2 is higher in + * their ranks. + */ +static gint +autoplug_compare_ranks(GstPluginFeature * feature1, + GstPluginFeature * feature2); + +/** + * Type to plug an appropriate element to a pad, according to the specified + * capabilities. + * + * @param typefind the Typefind structure to do the plugging for + * @param pad the pad to plug. + * @param caps the capabilities to plug with. + */ +static void +autoplug_try_to_plug(Typefind * typefind, + GstPad * pad, + const GstCaps * caps); + +/** + * Close a found link. + * + * @param typefind the Typefind structure to do close the link for. + * @param srcpad the source pad to close linking for. + * @param sinkelement the sink element to link the src pad to. + * @param padname the name of sink pad in sinkelement to link srcpad to. + * @param templlist a pad template list (TODO: what's this for?) + */ +static void +autoplug_close_link(Typefind * typefind, + GstPad * srcpad, + GstElement * sinkelement, + const gchar * padname, + const GList * templlist); + +/** + * Handle the event of new pads created on elements with dynamic pads. + * + * @param element the element that the new pad was created on. + * @param pad the new pad. + * @param userData user-specific data. + */ +static void +autoplug_newpad(GstElement * element, + GstPad * pad, + gpointer data); + + +/** + * Remove all typefind elements inside the bin, traversing to lower binds + * if necessary. The pads linked through the removed typefind elements are + * linked directly instead. + * + * @param bin the bin to remove the typefind elements from. + */ +static void +autoplug_remove_typefind_elements(GstBin * bin); + + +/* ============================================================= module code */ + +/*------------------------------------------------------------------------------ + * Filter the features that we're interested in. + *----------------------------------------------------------------------------*/ +static gboolean +autoplug_feature_filter(GstPluginFeature * feature, + gpointer userData) +{ + const gchar * klass; + guint rank; + + /* we only care about element factories */ + if (!GST_IS_ELEMENT_FACTORY(feature)) { + return FALSE; + } + + /* only parsers, demuxers and decoders */ + klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(feature)); + if (g_strrstr(klass, "Demux") == NULL && + g_strrstr(klass, "Decoder") == NULL && + g_strrstr(klass, "Parse") == NULL) { + + return FALSE; + } + + /* only select elements with autoplugging rank */ + rank = gst_plugin_feature_get_rank(feature); + if (rank < GST_RANK_MARGINAL) { + return FALSE; + } + + return TRUE; +} + + +/*------------------------------------------------------------------------------ + * Compare the ranks of two features. + *----------------------------------------------------------------------------*/ +static gint +autoplug_compare_ranks(GstPluginFeature * feature1, + GstPluginFeature * feature2) +{ + return gst_plugin_feature_get_rank(feature2) + - gst_plugin_feature_get_rank(feature1); +} + + +/*------------------------------------------------------------------------------ + * Initialize a Typefind object, like the factories that we care about. + *----------------------------------------------------------------------------*/ +static void +autoplug_init(Typefind * typefind) +{ + /* first filter out the interesting element factories */ + typefind->factories = gst_registry_pool_feature_filter( + (GstPluginFeatureFilter) autoplug_feature_filter, + FALSE, NULL); + + /* sort them according to their ranks */ + typefind->factories = g_list_sort(typefind->factories, + (GCompareFunc) autoplug_compare_ranks); + + typefind->pipeline = gst_pipeline_new("pipeline"); + typefind->bin = gst_bin_new("bin"); + typefind->typefind = gst_element_factory_make("typefind", "tf"); + typefind->audiosink = gst_element_factory_make("audioconvert", "audiosink"); + typefind->sink = gst_element_factory_make("fakesink", "fakesink"); + + gst_element_add_ghost_pad(typefind->bin, + gst_element_get_pad(typefind->typefind, "sink"), + "sink"); + gst_bin_add_many(GST_BIN(typefind->bin), + typefind->typefind, + NULL); + + g_signal_connect(typefind->bin, + "error", + G_CALLBACK(autoplug_error_handler), + NULL); + typefind->typefindSignal = g_signal_connect(typefind->typefind, + "have-type", + G_CALLBACK(autoplug_typefound_handler), + typefind); + + gst_element_link(typefind->source, typefind->bin); + gst_bin_add_many(GST_BIN(typefind->pipeline), + typefind->source, + typefind->bin, + NULL); + + typefind->done = FALSE; +} + + +/*------------------------------------------------------------------------------ + * Handle the event of a new pad being created on an element with + * request pads. + *----------------------------------------------------------------------------*/ +static void +autoplug_newpad(GstElement * element, + GstPad * pad, + gpointer userData) +{ + GstCaps * caps; + Typefind * typefind = (Typefind*) userData; + + g_return_if_fail(typefind != NULL); + + GST_DEBUG("created new pad %s for element %s", + gst_pad_get_name(pad), gst_element_get_name(element)); + caps = gst_pad_get_caps(pad); + autoplug_try_to_plug(typefind, pad, caps); + gst_caps_free(caps); +} + + + +/*------------------------------------------------------------------------------ + * Close the link. + *----------------------------------------------------------------------------*/ +static void +autoplug_close_link(Typefind * typefind, + GstPad * srcpad, + GstElement * sinkelement, + const gchar * padname, + const GList * templlist) +{ + GstPad * pad; + gboolean has_dynamic_pads = FALSE; + + GST_DEBUG("Plugging pad %s:%s to newly created %s:%s", + gst_object_get_name (GST_OBJECT (gst_pad_get_parent (srcpad))), + gst_pad_get_name (srcpad), + gst_object_get_name (GST_OBJECT (sinkelement)), padname); + + /* add the element to the pipeline and set correct state */ + gst_element_set_state(sinkelement, GST_STATE_PAUSED); + gst_bin_add(GST_BIN(typefind->bin), sinkelement); + pad = gst_element_get_pad(sinkelement, padname); + gst_pad_link(srcpad, pad); + gst_bin_sync_children_state(GST_BIN(typefind->bin)); + + /* if we have static source pads, link those. If we have dynamic + * source pads, listen for new-pad signals on the element */ + for ( ; templlist != NULL; templlist = templlist->next) { + GstPadTemplate *templ = GST_PAD_TEMPLATE (templlist->data); + + /* only sourcepads, no request pads */ + if (templ->direction != GST_PAD_SRC || + templ->presence == GST_PAD_REQUEST) { + continue; + } + + switch (templ->presence) { + case GST_PAD_ALWAYS: { + GstPad * pad = gst_element_get_pad(sinkelement, + templ->name_template); + GstCaps * caps = gst_pad_get_caps(pad); + + /* link */ + autoplug_try_to_plug(typefind, pad, caps); + gst_caps_free(caps); + } break; + + case GST_PAD_SOMETIMES: + has_dynamic_pads = TRUE; + break; + + default: + break; + } + } + + /* listen for newly created pads if this element supports that */ + if (has_dynamic_pads) { + g_signal_connect(sinkelement, + "new-pad", + G_CALLBACK(autoplug_newpad), + typefind); + } +} + + +/*------------------------------------------------------------------------------ + * Try to plug a pad with the specified capabilities. + *----------------------------------------------------------------------------*/ +static void +autoplug_try_to_plug(Typefind * typefind, + GstPad * pad, + const GstCaps * caps) +{ + GstObject * parent = GST_OBJECT(gst_pad_get_parent(pad)); + const gchar * mime; + const GList * item; + GstCaps * res; + GstCaps * audiocaps; + + g_return_if_fail(typefind != NULL); + + /* don't plug if we're already plugged */ + if (GST_PAD_IS_LINKED(gst_element_get_pad(typefind->audiosink, "sink"))) { + GST_DEBUG("Omitting link for pad %s:%s because we're already linked", + gst_object_get_name (parent), gst_pad_get_name (pad)); + return; + } + + /* as said above, we only try to plug audio... Omit video */ + mime = gst_structure_get_name(gst_caps_get_structure(caps, 0)); + if (g_strrstr(mime, "video")) { + GST_DEBUG("Omitting link for pad %s:%s because " + "mimetype %s is non-audio\n", + gst_object_get_name (parent), gst_pad_get_name (pad), mime); + return; + } + + /* can it link to the audiopad? */ + audiocaps = gst_pad_get_caps(gst_element_get_pad(typefind->audiosink, + "sink")); + res = gst_caps_intersect(caps, audiocaps); + if (res && !gst_caps_is_empty(res)) { + GST_DEBUG("Found pad to link to audiosink - plugging is now done"); + typefind->done = TRUE; + + autoplug_close_link(typefind, pad, typefind->audiosink, "sink", NULL); + + gst_element_add_ghost_pad(typefind->bin, + gst_element_get_pad(typefind->audiosink, "src"), + "src"); + gst_element_link(typefind->bin, typefind->sink); + gst_bin_add(GST_BIN(typefind->pipeline), typefind->sink); + gst_bin_sync_children_state(GST_BIN(typefind->bin)); + gst_bin_sync_children_state(GST_BIN(typefind->pipeline)); + + gst_caps_free (audiocaps); + gst_caps_free (res); + return; + } + gst_caps_free (audiocaps); + gst_caps_free (res); + + /* try to plug from our list */ + for (item = typefind->factories; item != NULL; item = item->next) { + GstElementFactory * factory = GST_ELEMENT_FACTORY(item->data); + const GList * pads; + + for (pads = gst_element_factory_get_pad_templates(factory); + pads != NULL; + pads = pads->next) { + GstPadTemplate * templ = GST_PAD_TEMPLATE(pads->data); + + if (!GST_IS_PAD_TEMPLATE(templ)) { + continue; + } + /* find the sink template - need an always pad*/ + if (templ->direction != GST_PAD_SINK || + templ->presence != GST_PAD_ALWAYS) { + continue; + } + + /* can it link? */ + res = gst_caps_intersect(caps, templ->caps); + if (res && !gst_caps_is_empty(res)) { + GstElement * element; + const GList * padTemplates; + + /* close link and return */ + gst_caps_free(res); + element = gst_element_factory_create(factory, NULL); + padTemplates = gst_element_factory_get_pad_templates(factory); + autoplug_close_link(typefind, + pad, + element, + templ->name_template, + padTemplates); + return; + } + gst_caps_free (res); + + /* we only check one sink template per factory, so move on to the + * next factory now */ + break; + } + } + + /* if we get here, no item was found */ + GST_DEBUG("No compatible pad found to decode %s on %s:%s", + mime, gst_object_get_name(parent), gst_pad_get_name(pad)); +} + + +/*------------------------------------------------------------------------------ + * Handle the event when a new type was found. + *----------------------------------------------------------------------------*/ +static void +autoplug_typefound_handler(GstElement * typefind, + gint probability, + GstCaps * caps, + gpointer userData) +{ + gchar * str; + Typefind * tf = (Typefind*) userData; + + g_return_if_fail(tf != NULL); + + str = gst_caps_to_string(caps); + GST_DEBUG("Detected media type %s", str); + g_free(str); + + /* actually plug now */ + autoplug_try_to_plug(tf, gst_element_get_pad(typefind, "src"), caps); +} + + +/*------------------------------------------------------------------------------ + * Filter the features that we're interested in. + *----------------------------------------------------------------------------*/ +static void +autoplug_error_handler(GstElement * pipeline, + GstElement * source, + GError * error, + gchar * message, + gpointer userData) +{ + /* TODO: handle error somehow */ + GST_DEBUG("error: %s", message); +} + + +/*------------------------------------------------------------------------------ + * Remove all typefind elements inside the bin, traversing to lower binds + * if necessary. The pads linked to the removed typefind elements are + * linked directly instead. + *----------------------------------------------------------------------------*/ +static void +autoplug_remove_typefind_elements(GstBin * bin) +{ + GstElement * element; + const GList * elements; + + elements = gst_bin_get_list(GST_BIN(bin)); + while (elements) { + GstElementFactory * factory; + GType type; + + element = (GstElement*) elements->data; + factory = gst_element_get_factory(element); + type = gst_element_factory_get_element_type(factory); + + GST_DEBUG("found factory: %s of type %s, is bin: %d", + gst_element_factory_get_longname(factory), + g_type_name(type), + g_type_is_a(type, GST_TYPE_BIN)); + + if (GST_IS_BIN(element)) { + autoplug_remove_typefind_elements(GST_BIN(element)); + } else if (g_strrstr(gst_element_factory_get_longname(factory), + "TypeFind")) { + GstPad * tfSinkPad; + GstPad * tfSrcPad; + GstPad * sinkPad; + GstElement * sinkElement; + GstPad * srcPad; + GstElement * srcElement; + GstElement * parent; + GstPad * parentSrcPad; + GstPad * parentSinkPad; + + tfSinkPad = gst_element_get_pad(element, "sink"); + tfSrcPad = gst_element_get_pad(element, "src"); + sinkPad = gst_pad_get_peer(tfSrcPad); + sinkElement = gst_pad_get_parent(sinkPad); + srcPad = gst_pad_get_peer(tfSinkPad); + srcElement = gst_pad_get_parent(srcPad); + parent = (GstElement*) gst_element_get_parent(element); + parentSrcPad = gst_element_get_pad(parent, "src"); + parentSinkPad = gst_element_get_pad(parent, "sink"); + + gst_element_unlink(srcElement, element); + gst_element_unlink(element, sinkElement); + + if (GST_PAD_REALIZE(parentSrcPad) == (GstRealPad*) tfSrcPad) { + /* if the pad we want to relink is ghosted by the container */ + gst_element_remove_pad(parent, parentSrcPad); + gst_element_add_ghost_pad(parent, srcPad, "src"); + gst_element_link(parent, sinkElement); + } else if (GST_PAD_REALIZE(parentSinkPad) == + (GstRealPad*) tfSinkPad) { + /* if the pad we want to relink is ghosted by the container */ + gst_element_remove_pad(parent, parentSinkPad); + gst_element_add_ghost_pad(parent, sinkPad, "sink"); + gst_element_link(srcElement, parent); + } else { + gst_element_link(srcElement, sinkElement); + } + + gst_bin_remove(bin, element); + + /* start iteration from the beginning, as probably the element + * list is invalidated with us removing the typefind element */ + elements = gst_bin_get_list(GST_BIN(bin)); + continue; + } + + elements = elements->next; + } +} + + +/*------------------------------------------------------------------------------ + * Filter the features that we're interested in. + *----------------------------------------------------------------------------*/ +GstElement * +autoplug_plug_source(GstElement * source) +{ + Typefind typefind; + + typefind.source = source; + autoplug_init(&typefind); + + gst_element_set_state(typefind.audiosink, GST_STATE_PAUSED); + gst_element_set_state(typefind.sink, GST_STATE_PAUSED); + gst_element_set_state(typefind.bin, GST_STATE_PLAYING); + gst_element_set_state(typefind.pipeline, GST_STATE_PLAYING); + + /* run */ + while (!typefind.done && gst_bin_iterate(GST_BIN(typefind.pipeline))); + + /* remove the sink element */ + gst_element_unlink(typefind.bin, typefind.sink); + gst_bin_remove(GST_BIN(typefind.pipeline), typefind.sink); + + /* remove the typefind elements, and re-link with the source */ + g_signal_handler_disconnect(typefind.typefind, typefind.typefindSignal); + autoplug_remove_typefind_elements(GST_BIN(typefind.bin)); + gst_element_link(typefind.source, typefind.bin); + + /* destory the pipeline, but keep source and bin */ + g_object_ref(typefind.source); + g_object_ref(typefind.bin); + gst_bin_remove(GST_BIN(typefind.pipeline), typefind.bin); + gst_object_unref(GST_OBJECT(typefind.pipeline)); + + gst_element_set_state(typefind.bin, GST_STATE_PAUSED); + gst_bin_sync_children_state(GST_BIN(typefind.bin)); + + return typefind.bin; +} + diff --git a/livesupport/modules/gstreamerElements/src/autoplug.h b/livesupport/modules/gstreamerElements/src/autoplug.h new file mode 100644 index 000000000..e5ff2c434 --- /dev/null +++ b/livesupport/modules/gstreamerElements/src/autoplug.h @@ -0,0 +1,80 @@ +/*------------------------------------------------------------------------------ + + Copyright (c) 2004 Media Development Loan Fund + + This file is part of the LiveSupport project. + http://livesupport.campware.org/ + To report bugs, send an e-mail to bugs@campware.org + + LiveSupport is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + LiveSupport 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LiveSupport; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + Author : $Author: maroy $ + Version : $Revision: 1.1 $ + Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/gstreamerElements/src/Attic/autoplug.h,v $ + +------------------------------------------------------------------------------*/ +#ifndef Audioplug_h +#define Audioplug_h + +/** + * @file + * Functions for autoplugging gstreamer elements based on their MIME types. + * + * @author $Author: maroy $ + * @version $Revision: 1.1 $ + */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/* ============================================================ include files */ + +#include + + +/* ================================================================ constants */ + + +/* =================================================================== macros */ + + +/* =============================================================== data types */ + + +/* ====================================================== function prototypes */ + +/** + * Autoplug a source element, that contains some form of audio. + * The result will be a gstreamer element, that is linked with + * source, and produces raw audio on its src pad as it output. + * + * @param source the source to autoplug. + * @return a gstreamer element already linked to source, that produces + * the audio provided by source in audio/x-raw-int or + * audio/x-raw-float format, as needed. + */ +GstElement * +autoplug_plug_source(GstElement * source); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* Audioplug_h */ + diff --git a/livesupport/modules/gstreamerElements/var/5seccounter.ogg b/livesupport/modules/gstreamerElements/var/5seccounter.ogg new file mode 100644 index 000000000..30e5ddb37 Binary files /dev/null and b/livesupport/modules/gstreamerElements/var/5seccounter.ogg differ