completed autoplugging, to recognize and work with SMIL files

This commit is contained in:
maroy 2005-06-23 17:45:57 +00:00
parent 59920a2d14
commit 06873e1c08
8 changed files with 203 additions and 52 deletions

View file

@ -21,7 +21,7 @@
#
#
# Author : $Author: maroy $
# Version : $Revision: 1.5 $
# Version : $Revision: 1.6 $
# Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/gstreamerElements/etc/Makefile.in,v $
#
# @configure_input@
@ -140,7 +140,7 @@ PARTIAL_PLAY_LIB_OBJS = ${TMP_DIR}/partial-play.o
SWITCHER_LIB_OBJS = ${TMP_DIR}/switcher.o
TEST_RUNNER_OBJS = ${TMP_DIR}/TestRunner.o \
${TMP_DIR}/AutoplugTest.o \
${TMP_DIR}/AutoplugTest.o \
${TMP_DIR}/SeekTest.o \
${TMP_DIR}/SwitcherTest.o \
${TMP_DIR}/SeekPackTest.o \
@ -201,16 +201,16 @@ check: all ${TEST_RUNNER}
${GSTREAMER_ELEMENTS_LIB_FILE}: ${GSTREAMER_ELEMENTS_LIB_OBJS}
${AR} crus $@ $^
${ONESHOT_READER_LIB_FILE}: ${GSTREAMER_ELEMENTS_LIB_FILE} \
${ONESHOT_READER_LIB_OBJS}
${ONESHOT_READER_LIB_FILE}: ${ONESHOT_READER_LIB_OBJS} \
${GSTREAMER_ELEMENTS_LIB_FILE}
${CC} -shared -o $@ $^ ${GST_LDFLAGS}
${MINIMAL_AUDIO_SMIL_LIB_FILE}: ${GSTREAMER_ELEMENTS_LIB_FILE} \
${MINIMAL_AUDIO_SMIL_LIB_OBJS}
${MINIMAL_AUDIO_SMIL_LIB_FILE}: ${MINIMAL_AUDIO_SMIL_LIB_OBJS} \
${GSTREAMER_ELEMENTS_LIB_FILE}
${CC} -shared -o $@ $^ ${GST_LDFLAGS}
${PARTIAL_PLAY_LIB_FILE}: ${GSTREAMER_ELEMENTS_LIB_FILE} \
${PARTIAL_PLAY_LIB_OBJS}
${PARTIAL_PLAY_LIB_FILE}: ${PARTIAL_PLAY_LIB_OBJS} \
${GSTREAMER_ELEMENTS_LIB_FILE}
${CC} -shared -o $@ $^ ${GST_LDFLAGS}
${SWITCHER_LIB_FILE}: ${SWITCHER_LIB_OBJS} \

View file

@ -22,7 +22,7 @@
Author : $Author: maroy $
Version : $Revision: 1.2 $
Version : $Revision: 1.3 $
Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/gstreamerElements/src/AutoplugTest.cxx,v $
------------------------------------------------------------------------------*/
@ -61,6 +61,16 @@ static const char * mp3TestFile = "var/5seccounter.mp3";
*/
static const char * oggTestFile = "var/5seccounter.ogg";
/**
* A SMIL test file.
*/
static const char * smilTestFile = "var/simple.smil";
/**
* A file we can't plug.
*/
static const char * badFile = "src/AutoplugTest.cxx";
/* =============================================== local function prototypes */
@ -111,6 +121,14 @@ AutoplugTest :: playFile(const char * audioFile)
decoder = autoplug_plug_source(source);
if (!decoder) {
gst_object_unref(GST_OBJECT(sink));
gst_object_unref(GST_OBJECT(source));
gst_object_unref(GST_OBJECT(pipeline));
return 0LL;
}
gst_element_link(decoder, sink);
gst_bin_add_many(GST_BIN(pipeline), source, decoder, sink, NULL);
@ -130,7 +148,7 @@ AutoplugTest :: playFile(const char * audioFile)
/* clean up nicely */
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(GST_OBJECT (pipeline));
gst_object_unref(GST_OBJECT(pipeline));
return timePlayed;
}
@ -169,3 +187,36 @@ AutoplugTest :: oggVorbisTest(void)
CPPUNIT_ASSERT_MESSAGE(str, timePlayed < 5.1 * GST_SECOND);
}
/*------------------------------------------------------------------------------
* A SMIL test.
*----------------------------------------------------------------------------*/
void
AutoplugTest :: smilTest(void)
throw (CPPUNIT_NS::Exception)
{
gint64 timePlayed;
char str[256];
timePlayed = playFile(smilTestFile);
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);
}
/*------------------------------------------------------------------------------
* Test somethign we can't plug.
*----------------------------------------------------------------------------*/
void
AutoplugTest :: negativeTest(void)
throw (CPPUNIT_NS::Exception)
{
gint64 timePlayed;
char str[256];
timePlayed = playFile(badFile);
g_snprintf(str, 256, "time played: %" G_GINT64_FORMAT, timePlayed);
CPPUNIT_ASSERT_MESSAGE(str, timePlayed == 0LL);
}

View file

@ -22,7 +22,7 @@
Author : $Author: maroy $
Version : $Revision: 1.1 $
Version : $Revision: 1.2 $
Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/gstreamerElements/src/AutoplugTest.h,v $
------------------------------------------------------------------------------*/
@ -58,13 +58,15 @@ namespace GstreamerElements {
* Unit test for the partialplay gstreamer element.
*
* @author $Author: maroy $
* @version $Revision: 1.1 $
* @version $Revision: 1.2 $
*/
class AutoplugTest : public CPPUNIT_NS::TestFixture
{
CPPUNIT_TEST_SUITE(AutoplugTest);
CPPUNIT_TEST(firstTest);
CPPUNIT_TEST(oggVorbisTest);
CPPUNIT_TEST(smilTest);
CPPUNIT_TEST(negativeTest);
CPPUNIT_TEST_SUITE_END();
private:
@ -99,6 +101,22 @@ class AutoplugTest : public CPPUNIT_NS::TestFixture
void
oggVorbisTest(void) throw (CPPUNIT_NS::Exception);
/**
* Test a SMIL file.
*
* @exception CPPUNIT_NS::Exception on test failures.
*/
void
smilTest(void) throw (CPPUNIT_NS::Exception);
/**
* A negative test.
*
* @exception CPPUNIT_NS::Exception on test failures.
*/
void
negativeTest(void) throw (CPPUNIT_NS::Exception);
public:

View file

@ -22,7 +22,7 @@
Author : $Author: maroy $
Version : $Revision: 1.1 $
Version : $Revision: 1.2 $
Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/gstreamerElements/src/OneshotReaderTest.cxx,v $
------------------------------------------------------------------------------*/
@ -125,7 +125,7 @@ OneshotReaderTest :: firstTest(void)
gst_element_set_state(pipeline, GST_STATE_PLAYING);
// well, actually don't run, by setting to state PLAYING,
// we already have what we're looking for.
//while (gst_bin_iterate (GST_BIN (pipeline)));
while (gst_bin_iterate(GST_BIN(pipeline)));
g_object_get(G_OBJECT(oneshot), "contents", &contents, NULL);
g_object_get(G_OBJECT(oneshot), "length", &length, NULL);
@ -135,7 +135,6 @@ OneshotReaderTest :: firstTest(void)
verifyContents = new char[length];
ifs.open(testFile);
CPPUNIT_ASSERT(ifs.good());
// read length - 1, as oneshotreader appends an extra NULL character
ifs.read(verifyContents, length);
CPPUNIT_ASSERT(!memcmp(contents, verifyContents, length));

View file

@ -27,7 +27,7 @@
Author : $Author: maroy $
Version : $Revision: 1.1 $
Version : $Revision: 1.2 $
Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/gstreamerElements/src/autoplug.c,v $
------------------------------------------------------------------------------*/
@ -106,6 +106,14 @@ autoplug_typefound_handler(GstElement * typefind,
static void
autoplug_init(Typefind * typefind);
/**
* De-initialize a typefind object.
*
* @param typefind the Typefind structure to de-init.
*/
static void
autoplug_deinit(Typefind * typefind);
/**
* A filter specifying the kind of factories we're interested in.
*
@ -176,11 +184,15 @@ autoplug_newpad(GstElement * element,
* 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.
* The typefind member of the supplied Typefind object is also removed,
* and changed to NULL.
*
* @param typefind the typefind object to work on.
* @param bin the bin to remove the typefind elements from.
*/
static void
autoplug_remove_typefind_elements(GstBin * bin);
autoplug_remove_typefind_elements(Typefind * typefind,
GstBin * bin);
/* ============================================================= module code */
@ -277,6 +289,28 @@ autoplug_init(Typefind * typefind)
typefind->done = FALSE;
}
/*------------------------------------------------------------------------------
* De-initialize a Typefind object.
*----------------------------------------------------------------------------*/
static void
autoplug_deinit(Typefind * typefind)
{
g_list_free(typefind->factories);
if (typefind->typefind) {
g_signal_handler_disconnect(typefind->typefind,
typefind->typefindSignal);
}
if (typefind->audiosink && !gst_element_get_parent(typefind->audiosink)) {
gst_object_unref(GST_OBJECT(typefind->audiosink));
}
if (typefind->sink && !gst_element_get_parent(typefind->sink)) {
gst_object_unref(GST_OBJECT(typefind->sink));
}
gst_object_unref(GST_OBJECT(typefind->pipeline));
}
/*------------------------------------------------------------------------------
* Handle the event of a new pad being created on an element with
@ -311,20 +345,37 @@ autoplug_close_link(Typefind * typefind,
const gchar * padname,
const GList * templlist)
{
GstPad * pad;
gboolean has_dynamic_pads = FALSE;
GstPad * pad;
gboolean has_dynamic_pads = FALSE;
GstElement * srcelement;
srcelement = GST_ELEMENT(gst_pad_get_parent(srcpad));
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);
gst_object_get_name(GST_OBJECT(srcelement)),
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));
/* FIXME: this is a nasty workaround for lack of time
* the minimalaudiosmil will try to read the input immediately
* from it sink pad as its set to PLAYING state,
* but that will result in a zillion such gstreamer warnings:
* "deadlock detected, disabling group 0xXXXXXX"
* but for example the vorbis demuxer needs to be in PLAYING
* state so that it can dynamically connect its request pads.
* fix this as soon as possible!
*/
if (!(g_strrstr(gst_object_get_name(GST_OBJECT(srcelement)),
"minimalaudiosmil")
|| g_strrstr(gst_object_get_name(GST_OBJECT(sinkelement)),
"minimalaudiosmil"))) {
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 */
@ -414,7 +465,6 @@ autoplug_try_to_plug(Typefind * typefind,
"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);
@ -448,19 +498,22 @@ autoplug_try_to_plug(Typefind * typefind,
if (res && !gst_caps_is_empty(res)) {
GstElement * element;
const GList * padTemplates;
gchar * templateName;
/* close link and return */
gst_caps_free(res);
templateName = g_strdup(templ->name_template);
element = gst_element_factory_create(factory, NULL);
padTemplates = gst_element_factory_get_pad_templates(factory);
autoplug_close_link(typefind,
pad,
element,
templ->name_template,
templateName,
padTemplates);
g_free(templateName);
return;
}
gst_caps_free (res);
gst_caps_free(res);
/* we only check one sink template per factory, so move on to the
* next factory now */
@ -518,7 +571,8 @@ autoplug_error_handler(GstElement * pipeline,
* linked directly instead.
*----------------------------------------------------------------------------*/
static void
autoplug_remove_typefind_elements(GstBin * bin)
autoplug_remove_typefind_elements(Typefind * typefind,
GstBin * bin)
{
GstElement * element;
const GList * elements;
@ -538,7 +592,7 @@ autoplug_remove_typefind_elements(GstBin * bin)
g_type_is_a(type, GST_TYPE_BIN));
if (GST_IS_BIN(element)) {
autoplug_remove_typefind_elements(GST_BIN(element));
autoplug_remove_typefind_elements(typefind, GST_BIN(element));
} else if (g_strrstr(gst_element_factory_get_longname(factory),
"TypeFind")) {
GstPad * tfSinkPad;
@ -581,6 +635,10 @@ autoplug_remove_typefind_elements(GstBin * bin)
gst_bin_remove(bin, element);
if (element == typefind->typefind) {
typefind->typefind = NULL;
}
/* 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));
@ -599,6 +657,11 @@ GstElement *
autoplug_plug_source(GstElement * source)
{
Typefind typefind;
GstElement * bin;
/* add an additional ref on the source, as we'll put it in a bin
* and remove it from the bin later, which will decrease the ref by one */
g_object_ref(source);
typefind.source = source;
autoplug_init(&typefind);
@ -611,24 +674,31 @@ autoplug_plug_source(GstElement * source)
/* run */
while (!typefind.done && gst_bin_iterate(GST_BIN(typefind.pipeline)));
if (!typefind.done) {
autoplug_deinit(&typefind);
return NULL;
}
/* remove the sink element */
gst_element_unlink(typefind.bin, typefind.sink);
gst_bin_remove(GST_BIN(typefind.pipeline), typefind.sink);
typefind.sink = NULL;
/* 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));
autoplug_remove_typefind_elements(&typefind, 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));
bin = typefind.bin;
return typefind.bin;
autoplug_deinit(&typefind);
gst_element_set_state(bin, GST_STATE_PAUSED);
gst_bin_sync_children_state(GST_BIN(bin));
return bin;
}

View file

@ -22,7 +22,7 @@
Author : $Author: maroy $
Version : $Revision: 1.1 $
Version : $Revision: 1.2 $
Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/gstreamerElements/src/minimal-audio-smil.c,v $
------------------------------------------------------------------------------*/
@ -55,8 +55,8 @@
*/
static GstElementDetails livesupport_minimal_audio_smil_details =
GST_ELEMENT_DETAILS("MinimalAudioSmil",
"Generic",
"A minimal SMIL payer, supporting only audio",
"Parse/Smil",
"A minimal SMIL player, supporting only audio",
"Akos Maroy <maroy@campware.org>");
/**
@ -110,7 +110,7 @@ GST_PLUGIN_DEFINE(GST_VERSION_MAJOR,
"minimalaudiosmil",
"Minimal Audio-only SMIL",
plugin_init,
"$Revision: 1.1 $",
"$Revision: 1.2 $",
"GPL",
"LiveSupport",
"http://livesupport.campware.org/")
@ -242,7 +242,9 @@ read_stream_into_memory(LivesupportMinimalAudioSmil * smil,
*outlength = 0;
oldState = gst_element_get_state(smil->oneshotReader);
gst_element_set_state(smil->oneshotReader, GST_STATE_PLAYING);
if (oldState != GST_STATE_PLAYING) {
gst_element_set_state(smil->oneshotReader, GST_STATE_PLAYING);
}
g_object_get(G_OBJECT(smil->oneshotReader), "length", &length, NULL);
g_object_get(G_OBJECT(smil->oneshotReader), "contents", &buffer, NULL);
@ -438,6 +440,10 @@ process_smil_file(LivesupportMinimalAudioSmil * smil)
xmlDocPtr document;
xmlNode * node;
if (!GST_PAD_IS_LINKED(smil->sinkpad)) {
return FALSE;
}
/* read the source document into memory */
read_stream_into_memory(smil, &buffer, &length);
if (!buffer) {
@ -493,15 +499,22 @@ static GstElementStateReturn
livesupport_minimal_audio_smil_change_state(GstElement * element)
{
LivesupportMinimalAudioSmil * smil;
GstElementState transition = GST_STATE_TRANSITION(element);
smil = LIVESUPPORT_MINIMAL_AUDIO_SMIL(element);
switch (GST_STATE_TRANSITION (element)) {
switch (transition) {
case GST_STATE_NULL_TO_READY:
gst_element_set_state(GST_ELEMENT(smil->bin), GST_STATE_READY);
break;
case GST_STATE_READY_TO_PAUSED:
gst_element_set_state(GST_ELEMENT(smil->bin), GST_STATE_PAUSED);
break;
case GST_STATE_PAUSED_TO_PLAYING:
gst_element_set_state(GST_ELEMENT(smil->bin), GST_STATE_PLAYING);
if (!smil->fileProcessed) {
/* set to true, in case of multiple change events */
smil->fileProcessed = TRUE;
@ -513,11 +526,7 @@ livesupport_minimal_audio_smil_change_state(GstElement * element)
(NULL));
}
}
gst_element_set_state(GST_ELEMENT(smil->bin), GST_STATE_PAUSED);
break;
case GST_STATE_PAUSED_TO_PLAYING:
gst_element_set_state(GST_ELEMENT(smil->bin), GST_STATE_PLAYING);
break;
case GST_STATE_PLAYING_TO_PAUSED:
@ -680,7 +689,7 @@ plugin_init (GstPlugin * plugin)
{
return gst_element_register(plugin,
"minimalaudiosmil",
GST_RANK_NONE,
GST_RANK_SECONDARY,
LIVESUPPORT_TYPE_MINIMAL_AUDIO_SMIL);
}

View file

@ -22,7 +22,7 @@
Author : $Author: maroy $
Version : $Revision: 1.1 $
Version : $Revision: 1.2 $
Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/gstreamerElements/src/oneshot-reader.c,v $
------------------------------------------------------------------------------*/
@ -93,7 +93,7 @@ GST_PLUGIN_DEFINE(GST_VERSION_MAJOR,
"oneshotreaderplugin",
"A reader that reads all of the input on one go",
plugin_init,
"$Revision: 1.1 $",
"$Revision: 1.2 $",
"GPL",
"LiveSupport",
"http://livesupport.campware.org/")
@ -283,6 +283,7 @@ static void
livesupport_one_shot_reader_loop(GstElement * element)
{
LivesupportOneShotReader * reader;
GstData * data;
g_return_if_fail(element != NULL);
g_return_if_fail(GST_IS_ONE_SHOT_READER(element));
@ -302,6 +303,9 @@ livesupport_one_shot_reader_loop(GstElement * element)
reader->processed = TRUE;
}
/* just pull the data from the source and don't care about it */
data = gst_pad_pull(reader->sinkpad);
gst_element_set_eos(element);
}

View file

@ -22,7 +22,7 @@
Author : $Author: maroy $
Version : $Revision: 1.4 $
Version : $Revision: 1.5 $
Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/gstreamerElements/src/switcher.c,v $
------------------------------------------------------------------------------*/
@ -64,7 +64,7 @@ GST_PLUGIN_DEFINE (
"switcher",
"A filter that connects to a swtich, and changes its source",
plugin_init,
"$Revision: 1.4 $",
"$Revision: 1.5 $",
"GPL",
"LiveSupport",
"http://livesupport.campware.org/"
@ -449,7 +449,7 @@ switch_to_next_source(LivesupportSwitcher * switcher)
/*------------------------------------------------------------------------------
* The main chain function.
* The main loop function.
*----------------------------------------------------------------------------*/
static void
livesupport_switcher_loop(GstElement * element)