added autoplugging capability

This commit is contained in:
maroy 2005-06-22 14:37:21 +00:00
parent 70a2c6bb64
commit c63c290d68
6 changed files with 1047 additions and 25 deletions

View file

@ -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}:

View file

@ -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 <string>
#include <iostream>
#include <gst/gst.h>
#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);
}

View file

@ -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 <cppunit/extensions/HelperMacros.h>
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

View file

@ -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 <gst/gst.h>
#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;
}

View file

@ -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 <gst/gst.h>
/* ================================================================ 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 */