WIP create (planned) new entities for the player subsystem
This commit is contained in:
parent
ebd6cfca82
commit
899ffa60ca
23 changed files with 3636 additions and 0 deletions
33
src/backend/engine/scheduler-frontend.cpp
Normal file
33
src/backend/engine/scheduler-frontend.cpp
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
RenderEngine - a complete network of processing nodes usable for rendering
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
* *****************************************************/
|
||||
|
||||
|
||||
#include "proc/engine/renderengine.hpp"
|
||||
|
||||
namespace engine {
|
||||
|
||||
|
||||
/** */
|
||||
|
||||
|
||||
|
||||
} // namespace engine
|
||||
58
src/backend/engine/scheduler-frontend.hpp
Normal file
58
src/backend/engine/scheduler-frontend.hpp
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
RENDERENGINE.hpp - a complete network of processing nodes usable for rendering
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ENGINE_RENDERENGINE_H
|
||||
#define ENGINE_RENDERENGINE_H
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "proc/engine/rendergraph.hpp"
|
||||
|
||||
|
||||
using std::list;
|
||||
|
||||
|
||||
namespace engine {
|
||||
|
||||
|
||||
/**
|
||||
* @todo this is planned to become the frontend
|
||||
* to the render node network, which can be considered
|
||||
* at the lower end of the middle layer; the actual
|
||||
* render operations are mostly implemented by the backend
|
||||
* ////////TODO WIP as of 12/2010
|
||||
*/
|
||||
class RenderEngine : public RenderGraph
|
||||
{
|
||||
public:
|
||||
///// TODO: find out about the public operations
|
||||
// note: the play controller lives in the proc-layer,
|
||||
// but is a subsystem separate of the sesison.
|
||||
|
||||
private:
|
||||
list<RenderGraph> renderSegments;
|
||||
|
||||
};
|
||||
|
||||
} // namespace engine
|
||||
#endif
|
||||
72
src/proc/asset/viewer.cpp
Normal file
72
src/proc/asset/viewer.cpp
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
Timeline - independent top-level element of the Session
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2009, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
* *****************************************************/
|
||||
|
||||
|
||||
#include "proc/asset/timeline.hpp"
|
||||
//#include "proc/mobject/session/track.hpp"
|
||||
//#include "proc/mobject/placement.hpp"
|
||||
//#include "proc/mobject/session/mobjectfactory.hpp"
|
||||
#include "proc/mobject/session/binding.hpp"
|
||||
#include "proc/assetmanager.hpp"
|
||||
|
||||
|
||||
namespace asset {
|
||||
|
||||
using lib::AutoRegistered;
|
||||
|
||||
|
||||
|
||||
/** @todo anything significant to do here??? */
|
||||
Timeline::Timeline (const Asset::Ident& idi, RBinding const& sequenceBinding)
|
||||
: Struct (idi)
|
||||
, boundSequence_(sequenceBinding)
|
||||
{
|
||||
REQUIRE (boundSequence_);
|
||||
}
|
||||
|
||||
|
||||
PTimeline
|
||||
Timeline::create (Asset::Ident const& idi, RBinding const& sequenceBinding)
|
||||
{
|
||||
REQUIRE (getRegistry, "can't create a Timeline prior to session initialisation");
|
||||
|
||||
PTimeline newElement (AssetManager::instance().wrap (*new Timeline(idi, sequenceBinding)));
|
||||
getRegistry().append (newElement);
|
||||
|
||||
ENSURE (newElement);
|
||||
ENSURE (getRegistry().isRegistered (*newElement));
|
||||
return newElement;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Timeline::unlink ()
|
||||
{
|
||||
AutoRegistered<Timeline>::detach();
|
||||
boundSequence_.purge();
|
||||
Struct::unlink();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace asset
|
||||
115
src/proc/asset/viewer.hpp
Normal file
115
src/proc/asset/viewer.hpp
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
TIMELINE.hpp - independent top-level element of the Session
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2009, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/** @file timeline.hpp
|
||||
** Top level structural element within the session.
|
||||
** Each Lumiera session may contain multiple top level timeline containers,
|
||||
** which at the same time act as structural asset and as part of the public
|
||||
** session API exposed to clients for discovering the session contents.
|
||||
** Actually, Timelines are facade objects, delegating the implementation to
|
||||
** the BindingMO, the Axis and the Sequences/Tracks.
|
||||
**
|
||||
** Contrary to usual habits in video/sound editing software, in Lumiera the
|
||||
** tracks are \em not part of the timeline, but rather attached directly to
|
||||
** the sequence container. To be usable, a timeline needs a binding to refer
|
||||
** to such a sequence, but this sequence may be bound into multiple timelines
|
||||
** or even virtual clips simultaneously.
|
||||
**
|
||||
** Like every structural asset, the creation of timelines happens automatically
|
||||
** on referral; Timelines can be queried from the StructFactory, providing additional
|
||||
** requested capabilities. Commonly clients will retrieve a given timeline by query
|
||||
** on the name-ID of the timeline: \c Struct::retrieve(Query<Timeline>("id(theName)."))
|
||||
** Additionally, the binding to a specific sequence may be established alongside:
|
||||
** \c "timeline(theTimelineName),bindSequence(theTimelineName,sequenceID)."
|
||||
**
|
||||
** @see Session
|
||||
** @see Sequence
|
||||
** @see StructFactory
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ASSET_TIMELINE_H
|
||||
#define ASSET_TIMELINE_H
|
||||
|
||||
#include "proc/asset/struct.hpp"
|
||||
//#include "proc/mobject/mobject.hpp"
|
||||
//#include "proc/mobject/placement.hpp"
|
||||
#include "proc/mobject/mobject-ref.hpp"
|
||||
//#include "proc/mobject/session/binding.hpp" ////TODO avoidable??
|
||||
#include "lib/p.hpp"
|
||||
#include "lib/element-tracker.hpp"
|
||||
|
||||
|
||||
//#include <vector>
|
||||
//#include <string>
|
||||
|
||||
//using std::vector;
|
||||
//using std::string;
|
||||
|
||||
namespace mobject {
|
||||
namespace session {
|
||||
|
||||
class Binding;
|
||||
typedef MORef<Binding> RBinding;
|
||||
}}
|
||||
|
||||
|
||||
namespace asset {
|
||||
|
||||
|
||||
// using lumiera::P;
|
||||
class Timeline;
|
||||
typedef lumiera::P<Timeline> PTimeline;
|
||||
|
||||
|
||||
/**
|
||||
* TODO type comment
|
||||
*/
|
||||
class Timeline
|
||||
: public Struct
|
||||
, public lib::AutoRegistered<Timeline>
|
||||
{
|
||||
typedef mobject::session::RBinding RBinding;
|
||||
|
||||
RBinding boundSequence_;
|
||||
|
||||
Timeline (Ident const&, RBinding const&);
|
||||
|
||||
public:
|
||||
/** create and register a new Timeline instance */
|
||||
static PTimeline create (Asset::Ident const& idi, RBinding const& sequenceBinding);
|
||||
|
||||
protected:
|
||||
virtual void unlink ();
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////TODO currently just fleshing the API
|
||||
|
||||
|
||||
} // namespace asset
|
||||
#endif
|
||||
42
src/proc/engine/dispatcher.cpp
Normal file
42
src/proc/engine/dispatcher.cpp
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
RenderGraph - render network corresponding to one segment of the timeline
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
* *****************************************************/
|
||||
|
||||
|
||||
#include "proc/engine/rendergraph.hpp"
|
||||
#include "lib/frameid.hpp"
|
||||
#include "proc/state.hpp"
|
||||
|
||||
namespace lumiera {
|
||||
|
||||
/** storage for the unique node-ID counter */
|
||||
ulong NodeID::currID (0);
|
||||
}
|
||||
|
||||
|
||||
namespace engine {
|
||||
|
||||
/** */
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace engine
|
||||
64
src/proc/engine/dispatcher.hpp
Normal file
64
src/proc/engine/dispatcher.hpp
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
RENDERGRAPH.hpp - render network corresponding to one segment of the timeline
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ENGINE_RENDERGRAPH_H
|
||||
#define ENGINE_RENDERGRAPH_H
|
||||
|
||||
#include "proc/common.hpp"
|
||||
#include "proc/state.hpp"
|
||||
#include "lib/time/timevalue.hpp"
|
||||
|
||||
|
||||
|
||||
namespace engine {
|
||||
|
||||
using lib::time::TimeSpan;
|
||||
using lib::time::FSecs;
|
||||
using lib::time::Time;
|
||||
|
||||
class ExitNode;
|
||||
|
||||
/**
|
||||
* @todo likely to be reworked into the engine backbone /////////////TODO WIP as of 12/2010
|
||||
*/
|
||||
class RenderGraph
|
||||
{
|
||||
protected:
|
||||
ExitNode * output;
|
||||
|
||||
/** timerange covered by this RenderGraph */
|
||||
TimeSpan segment_;
|
||||
|
||||
public:
|
||||
RenderGraph()
|
||||
: segment_(Time::ZERO, FSecs(5))
|
||||
{
|
||||
UNIMPLEMENTED ("anything regarding the Fixture datastructure");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace engine
|
||||
#endif
|
||||
382
src/proc/engine/engine-service.cpp
Normal file
382
src/proc/engine/engine-service.cpp
Normal file
|
|
@ -0,0 +1,382 @@
|
|||
/*
|
||||
DummyPlayerService - access point and service implementing a dummy test player
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2009, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
* *****************************************************/
|
||||
|
||||
|
||||
#include "proc/play/dummy-player-service.hpp"
|
||||
#include "proc/play/dummy-image-generator.hpp"
|
||||
#include "proc/play/tick-service.hpp"
|
||||
#include "lib/singleton.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "common/interfacedescriptor.h"
|
||||
}
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <tr1/functional>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
|
||||
|
||||
namespace proc {
|
||||
namespace play{
|
||||
|
||||
using std::string;
|
||||
using lumiera::Subsys;
|
||||
using std::auto_ptr;
|
||||
using boost::scoped_ptr;
|
||||
using std::tr1::bind;
|
||||
|
||||
|
||||
namespace { // hidden local details of the service implementation....
|
||||
|
||||
/** details of how the DummyPlayer service can be started
|
||||
* and used as independent "subsystem" within main() */
|
||||
class DummyPlayerSubsysDescriptor
|
||||
: public Subsys
|
||||
{
|
||||
operator string () const { return "Dummy-Player"; }
|
||||
|
||||
|
||||
bool
|
||||
shouldStart (lumiera::Option&)
|
||||
{
|
||||
return false; // for now the DummyPlayerService only comes "up" as dependency,
|
||||
} // but doesn't start as a subsystem on it's own.
|
||||
|
||||
bool
|
||||
start (lumiera::Option&, Subsys::SigTerm terminationHandle)
|
||||
{
|
||||
ASSERT (!thePlayer_);
|
||||
|
||||
thePlayer_.reset (new DummyPlayerService (terminationHandle));
|
||||
return true;
|
||||
}
|
||||
|
||||
/** manages the actual (single) instance of the player service impl */
|
||||
scoped_ptr<DummyPlayerService> thePlayer_;
|
||||
|
||||
|
||||
void
|
||||
triggerShutdown () throw()
|
||||
{
|
||||
thePlayer_.reset(0);
|
||||
// note: shutdown of the DummyPlayerService instance may block
|
||||
// for a short period, until termination of all tick services
|
||||
}
|
||||
|
||||
bool
|
||||
checkRunningState () throw()
|
||||
{
|
||||
return (thePlayer_);
|
||||
}
|
||||
};
|
||||
|
||||
lib::Singleton<DummyPlayerSubsysDescriptor> theDummyPlayerDescriptor;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* ================== define an lumieraorg_DummyPlayer instance ======================= */
|
||||
|
||||
LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0
|
||||
,lumieraorg_DummyPlayerFacade_descriptor
|
||||
, NULL, NULL, NULL
|
||||
, LUMIERA_INTERFACE_INLINE (name, "\305\162\202\240\075\316\146\100\314\152\075\343\372\065\226\307",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "DummyPlayer"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (brief, "\317\045\366\076\064\072\156\274\220\346\262\207\062\367\057\232",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "Proc Interface: dummy player to test integration with the GUI"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (homepage, "\136\225\033\362\161\251\300\256\117\072\171\102\235\004\235\200",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "http://www.lumiera.org/develompent.html" ;}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (version, "\212\146\344\127\124\116\101\205\211\174\322\241\162\122\023\165",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "0.1~pre"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (author, "\064\226\072\300\054\345\042\357\337\226\155\025\306\051\117\105",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "Hermann Vosseler"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (email, "\041\075\220\112\246\304\261\135\003\135\060\202\230\327\303\206",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "Ichthyostega@web.de"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (copyright, "\232\305\163\271\174\025\270\075\012\201\331\256\327\375\066\210",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{
|
||||
(void)ifa;
|
||||
return
|
||||
"Copyright (C) Lumiera.org\n"
|
||||
" 2009 Hermann Vosseler <Ichthyostega@web.de>";
|
||||
}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (license, "\136\136\073\173\145\357\151\062\040\013\323\272\051\352\305\060",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{
|
||||
(void)ifa;
|
||||
return
|
||||
"This program is free software; you can redistribute it and/or modify\n"
|
||||
"it under the terms of the GNU General Public License as published by\n"
|
||||
"the Free Software Foundation; either version 2 of the License, or\n"
|
||||
"(at your option) any later version.\n"
|
||||
"\n"
|
||||
"This program is distributed in the hope that it will be useful,\n"
|
||||
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
|
||||
"GNU General Public License for more details.\n"
|
||||
"\n"
|
||||
"You should have received a copy of the GNU General Public License\n"
|
||||
"along with this program; if not, write to the Free Software\n"
|
||||
"Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA";
|
||||
}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (state, "\224\251\004\001\165\140\116\246\126\311\115\234\023\026\331\350",
|
||||
int, (LumieraInterface ifa),
|
||||
{(void)ifa; return LUMIERA_INTERFACE_EXPERIMENTAL; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (versioncmp, "\267\155\303\046\353\222\323\014\145\027\043\100\370\311\257\126",
|
||||
int, (const char* a, const char* b),
|
||||
{return 0;} ////////////////////////////////////////////TODO define version ordering
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
using lumiera::facade::LUMIERA_ERROR_FACADE_LIFECYCLE;
|
||||
typedef lib::SingletonRef<DummyPlayerService>::Accessor InstanceRef;
|
||||
|
||||
InstanceRef _instance; ///< a backdoor for the C Language impl to access the actual DummyPlayer implementation...
|
||||
|
||||
typedef ProcessImpl* ProcP;
|
||||
|
||||
|
||||
LUMIERA_INTERFACE_INSTANCE (lumieraorg_DummyPlayer, 0
|
||||
,lumieraorg_DummyPlayerService
|
||||
, LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_DummyPlayerFacade_descriptor)
|
||||
, NULL /* on open */
|
||||
, NULL /* on close */
|
||||
, LUMIERA_INTERFACE_INLINE (startPlay, "\143\323\102\155\051\006\235\004\037\310\354\121\176\142\342\210",
|
||||
LumieraPlayProcess, (LumieraDisplaySlot viewerHandle),
|
||||
{
|
||||
if (!_instance)
|
||||
{
|
||||
lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return static_cast<LumieraPlayProcess> (_instance->start(viewerHandle));
|
||||
}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (togglePlay, "\275\157\316\220\210\053\226\134\057\016\273\265\240\053\112\307",
|
||||
void, (LumieraPlayProcess handle, bool doPlay),
|
||||
{
|
||||
if (!_instance)
|
||||
{
|
||||
lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
REQUIRE (handle);
|
||||
ProcP proc = static_cast<ProcP> (handle);
|
||||
|
||||
proc->doPlay(doPlay);
|
||||
}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (terminate, "\005\265\115\021\076\143\010\215\373\252\370\174\235\136\340\004",
|
||||
void, (LumieraPlayProcess handle),
|
||||
{
|
||||
if (!_instance)
|
||||
{
|
||||
lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
REQUIRE (handle);
|
||||
ProcP proc = static_cast<ProcP> (handle);
|
||||
|
||||
ProcessImpl::terminate (proc);
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
} // (End) hidden service impl details
|
||||
|
||||
|
||||
|
||||
|
||||
DummyPlayerService::DummyPlayerService (Subsys::SigTerm terminationHandle)
|
||||
: error_("")
|
||||
, notifyTermination_(terminationHandle)
|
||||
, implInstance_(this,_instance)
|
||||
, serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_DummyPlayer, 0, lumieraorg_DummyPlayerService))
|
||||
{
|
||||
INFO (progress, "DummyPlayer Facade opened.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** @par implementation note
|
||||
* A new process (implementation) is created, configured
|
||||
* and started here. This may include spawning a thread or
|
||||
* allocating a timer. The newly created process is self-contained
|
||||
* and will be just handed out, without caring for its lifecycle.
|
||||
* If client code accesses this function via the plain C interface,
|
||||
* the client is responsible for terminating this process, whereas
|
||||
* when using the C++ interface, you'll get a Handle object which
|
||||
* manages the lifecycle automatically.
|
||||
*/
|
||||
ProcessImpl*
|
||||
DummyPlayerService::start (LumieraDisplaySlot viewerHandle)
|
||||
{
|
||||
auto_ptr<ProcessImpl> newProcess (new ProcessImpl (viewerHandle));
|
||||
|
||||
REQUIRE (!newProcess->isActive());
|
||||
newProcess->setRate(25);
|
||||
|
||||
return newProcess.release();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* === Process Implementation === */
|
||||
|
||||
|
||||
ProcessImpl::ProcessImpl(LumieraDisplaySlot viewerHandle)
|
||||
: fps_(0)
|
||||
, play_(false)
|
||||
, display_(Display::facade().getHandle (viewerHandle))
|
||||
, imageGen_(0)
|
||||
, tick_(new TickService (bind (&ProcessImpl::doFrame, this)))
|
||||
{ }
|
||||
|
||||
|
||||
ProcessImpl::~ProcessImpl()
|
||||
{
|
||||
INFO (proc_dbg, "Playback process halted...");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ProcessImpl::terminate (ProcessImpl* process) ///< deleter function for lib::Handle
|
||||
{
|
||||
if (process)
|
||||
delete process;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DummyPlayer::Process
|
||||
ProcessImpl::createHandle()
|
||||
{
|
||||
DummyPlayer::Process handle;
|
||||
handle.activate(this, &terminate); // note the deleter function...
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ProcessImpl::setRate (uint fps)
|
||||
{
|
||||
REQUIRE (fps==0 || fps_==0 );
|
||||
REQUIRE (fps==0 || !play_ );
|
||||
REQUIRE (tick_);
|
||||
|
||||
fps_ = fps;
|
||||
play_ = (fps != 0);
|
||||
|
||||
if (play_)
|
||||
imageGen_.reset(new DummyImageGenerator(fps));
|
||||
|
||||
// callbacks with given frequency, starting now
|
||||
tick_->activate(fps);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ProcessImpl::doPlay(bool yes)
|
||||
{
|
||||
REQUIRE (isActive());
|
||||
tick_->activate (yes? fps_:0);
|
||||
play_ = yes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ProcessImpl::doFrame()
|
||||
{
|
||||
REQUIRE (isActive());
|
||||
ASSERT (imageGen_);
|
||||
|
||||
if (play_)
|
||||
display_(imageGen_->next());
|
||||
else
|
||||
display_(imageGen_->current());
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace play
|
||||
|
||||
} // namespace proc
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace lumiera { /* === Forwarding function(s) on the Process handle === */
|
||||
|
||||
void DummyPlayer::Process::play(bool yes) { impl().doPlay(yes); }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** @internal intended for use by main(). */
|
||||
lumiera::Subsys&
|
||||
DummyPlayer::getDescriptor()
|
||||
{
|
||||
return proc::play::theDummyPlayerDescriptor();
|
||||
}
|
||||
|
||||
// emit the vtable here into this translation unit within liblumieraproc.so ...
|
||||
DummyPlayer::~DummyPlayer() { }
|
||||
|
||||
|
||||
} // namespace lumiera
|
||||
161
src/proc/engine/engine-service.hpp
Normal file
161
src/proc/engine/engine-service.hpp
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
DUMMY-PLAYER-SERVICE.hpp - service implementing a dummy test player
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2009, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
/** @file dummy-player-service.hpp
|
||||
** A public service provided by the Proc-Layer, implementing a dummy/mockup playback process.
|
||||
** This is a design sketch; Lumiera isn't able to generate rendered output as of 2/2009. The
|
||||
** idea is, that for each ongoing calculation process, there is a ProcessImpl instance holding
|
||||
** the necessary handles and allocations and providing an uniform API to the client side.
|
||||
** Especially, this ProcessImpl holds a TickService, which generates periodic callbacks, and
|
||||
** it uses an output handle (functor) to push the generated frames up.
|
||||
**
|
||||
** This service is the implementation of a layer separation facade interface. Clients should use
|
||||
** proc::play::DummyPlayer#facade to access this service. This header defines the interface used
|
||||
** to \em provide this service, not to access it.
|
||||
**
|
||||
** @see lumiera::DummyPlayer
|
||||
** @see gui::PlaybackController usage example
|
||||
*/
|
||||
|
||||
|
||||
#ifndef PROC_DUMMYPLAYER_SERVICE_H
|
||||
#define PROC_DUMMYPLAYER_SERVICE_H
|
||||
|
||||
|
||||
#include "include/dummy-player-facade.h"
|
||||
#include "include/display-facade.h"
|
||||
#include "common/instancehandle.hpp"
|
||||
#include "lib/singleton-ref.hpp"
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace proc {
|
||||
namespace play {
|
||||
|
||||
using std::string;
|
||||
using lumiera::Subsys;
|
||||
using lumiera::Display;
|
||||
using lumiera::DummyPlayer;
|
||||
|
||||
|
||||
class DummyImageGenerator;
|
||||
class TickService;
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Actual implementation of a single (dummy) playback process.
|
||||
* The DummyPlayerService (see below) maintains a collection of such
|
||||
* actively running playback processes, while the client code gets
|
||||
* DummyPlayer::Process handles to track any ongoing use. Users of
|
||||
* the plain C interface get a direct bare pointer to the respective
|
||||
* ProcessImpl instance and have to manage the lifecycle manually.
|
||||
*/
|
||||
class ProcessImpl
|
||||
: public lumiera_playprocess,
|
||||
boost::noncopyable
|
||||
{
|
||||
uint fps_;
|
||||
bool play_;
|
||||
|
||||
Display::Sink display_;
|
||||
boost::scoped_ptr<DummyImageGenerator> imageGen_;
|
||||
boost::scoped_ptr<TickService> tick_;
|
||||
|
||||
|
||||
public:
|
||||
ProcessImpl(LumieraDisplaySlot) ;
|
||||
~ProcessImpl() ;
|
||||
|
||||
|
||||
/* Implementation-level API */
|
||||
|
||||
/** activate a playback process
|
||||
* with given specification */
|
||||
void setRate (uint fps);
|
||||
|
||||
bool isActive () { return fps_ != 0; }
|
||||
bool isPlaying() { return play_; }
|
||||
|
||||
void doPlay(bool yes);
|
||||
|
||||
|
||||
/* Lifecycle */
|
||||
|
||||
DummyPlayer::Process createHandle();
|
||||
static void terminate(ProcessImpl* process);
|
||||
|
||||
private:
|
||||
void doFrame (); ///< periodically invoked while playing
|
||||
};
|
||||
|
||||
|
||||
|
||||
/******************************************************
|
||||
* Actual implementation of the DummyPlayer service.
|
||||
* Creating an instance of this class automatically
|
||||
* registers the interface lumieraorg_DummyPlayer with
|
||||
* the Lumiera Interface/Plugin system and creates
|
||||
* a forwarding proxy within the application core to
|
||||
* route calls through this interface.
|
||||
*/
|
||||
class DummyPlayerService
|
||||
: boost::noncopyable
|
||||
{
|
||||
|
||||
string error_;
|
||||
Subsys::SigTerm notifyTermination_;
|
||||
|
||||
|
||||
/* === Interface Lifecycle === */
|
||||
|
||||
typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_DummyPlayer, 0)
|
||||
, DummyPlayer
|
||||
> ServiceInstanceHandle;
|
||||
|
||||
lib::SingletonRef<DummyPlayerService> implInstance_;
|
||||
ServiceInstanceHandle serviceInstance_;
|
||||
|
||||
public:
|
||||
DummyPlayerService(Subsys::SigTerm terminationHandle);
|
||||
|
||||
~DummyPlayerService() { notifyTermination_(&error_); }
|
||||
|
||||
|
||||
|
||||
/** conceptually, this serves as implementation
|
||||
* of the DummyPlayer#start() function. But because
|
||||
* this function sits \em behind the interface, it
|
||||
* just returns an impl pointer. */
|
||||
ProcessImpl* start (LumieraDisplaySlot viewerHandle);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace play
|
||||
|
||||
} // namespace proc
|
||||
#endif
|
||||
86
src/proc/mobject/session/generator-mo.cpp
Normal file
86
src/proc/mobject/session/generator-mo.cpp
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
Clip - a Media Clip
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
* *****************************************************/
|
||||
|
||||
|
||||
#include "proc/mobject/session/clip.hpp"
|
||||
#include "proc/assetmanager.hpp"
|
||||
#include "proc/asset/media.hpp"
|
||||
#include "proc/asset/clip.hpp"
|
||||
#include "lib/time/mutation.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
using lib::time::Mutation;
|
||||
using util::isnil;
|
||||
|
||||
namespace mobject {
|
||||
namespace session {
|
||||
|
||||
/** new clip-MO linked with the given asset::Clip.
|
||||
* Initially, this clip will cover the whole source media length.
|
||||
*/
|
||||
Clip::Clip (const asset::Clip& clipDef, const Media& mediaDef)
|
||||
: mediaDef_(mediaDef)
|
||||
, clipDef_(clipDef)
|
||||
{
|
||||
setupLength();
|
||||
throwIfInvalid();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** implementing the common MObject self test.
|
||||
* Length definition is consitent, underlying
|
||||
* media def is accessible etc. */
|
||||
bool
|
||||
Clip::isValid () const
|
||||
{
|
||||
TODO ("check consistency of clip length def, implies accessing the underlying media def");
|
||||
return !isnil(length_);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Clip::setupLength()
|
||||
{
|
||||
TODO ("really calculate the length of a clip and set length field");
|
||||
this->length_.accept (Mutation::changeDuration(mediaDef_.getLength()));
|
||||
}
|
||||
|
||||
|
||||
PMedia
|
||||
Clip::getMedia () const
|
||||
{
|
||||
return asset::AssetManager::wrap (mediaDef_);
|
||||
}
|
||||
|
||||
|
||||
PClipAsset
|
||||
Clip::findClipAsset () const
|
||||
{
|
||||
return asset::AssetManager::wrap (clipDef_);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}} // namespace mobject::session
|
||||
|
||||
110
src/proc/mobject/session/generator-mo.hpp
Normal file
110
src/proc/mobject/session/generator-mo.hpp
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
CLIP.hpp - a Media Clip
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef MOBJECT_SESSION_CLIP_H
|
||||
#define MOBJECT_SESSION_CLIP_H
|
||||
|
||||
#include "proc/mobject/session/abstractmo.hpp"
|
||||
#include "lib/time/timevalue.hpp"
|
||||
|
||||
|
||||
namespace asset {
|
||||
class Media;
|
||||
class Clip;
|
||||
}
|
||||
|
||||
namespace mobject {
|
||||
namespace session {
|
||||
|
||||
using asset::Media;
|
||||
using lib::time::TimeVar;
|
||||
|
||||
typedef P<Media> PMedia;
|
||||
typedef P<asset::Clip> PClipAsset;
|
||||
|
||||
|
||||
/**
|
||||
* A user visible/editable Clip is a reference to a contiguous
|
||||
* sequence of media data loaded as Asset into the current Session.
|
||||
* As such, it is a virtual (non destructive) cut or edit of the
|
||||
* source material and can be placed into the Session to be rendered
|
||||
* into the output. The actual media type of a clip will be derived
|
||||
* at runtime by resolving this reference to the underlying Asset.
|
||||
*
|
||||
* @todo define how to denote Time positions /lengths. This is tricky,
|
||||
* because it depends on the actual media type, and we want to encapsulate
|
||||
* all these details as much as possible.
|
||||
*/
|
||||
class Clip
|
||||
: public AbstractMO
|
||||
{
|
||||
string
|
||||
initShortID() const
|
||||
{
|
||||
return buildShortID("Clip");
|
||||
}
|
||||
|
||||
void setupLength();
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
/** start position in source */
|
||||
TimeVar start_;
|
||||
|
||||
/** @todo using a mere ref here is against the scheme and only
|
||||
done as temporal solution, until we work out how to handle
|
||||
multichannel clips. It should be a smart pointer of some kind
|
||||
and the unlink() function of the asset should take it into
|
||||
account when breaking circular references.
|
||||
*/
|
||||
|
||||
const Media & mediaDef_;
|
||||
const asset::Clip & clipDef_;
|
||||
|
||||
Clip (const asset::Clip&, const Media&);
|
||||
friend class MObjectFactory;
|
||||
|
||||
|
||||
public:
|
||||
bool isValid() const;
|
||||
|
||||
/** access the underlying media asset */
|
||||
PMedia getMedia () const;
|
||||
|
||||
/** locate the corresponding asset
|
||||
* representing this clip or the whole
|
||||
* compound in case of a multichannel clip
|
||||
*/
|
||||
PClipAsset findClipAsset () const;
|
||||
|
||||
DEFINE_PROCESSABLE_BY (builder::BuilderTool);
|
||||
|
||||
};
|
||||
|
||||
typedef Placement<Clip> PClipMO;
|
||||
|
||||
|
||||
|
||||
}} // namespace mobject::session
|
||||
#endif
|
||||
382
src/proc/play/dummy-play-connection.cpp
Normal file
382
src/proc/play/dummy-play-connection.cpp
Normal file
|
|
@ -0,0 +1,382 @@
|
|||
/*
|
||||
DummyPlayerService - access point and service implementing a dummy test player
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2009, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
* *****************************************************/
|
||||
|
||||
|
||||
#include "proc/play/dummy-player-service.hpp"
|
||||
#include "proc/play/dummy-image-generator.hpp"
|
||||
#include "proc/play/tick-service.hpp"
|
||||
#include "lib/singleton.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "common/interfacedescriptor.h"
|
||||
}
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <tr1/functional>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
|
||||
|
||||
namespace proc {
|
||||
namespace play{
|
||||
|
||||
using std::string;
|
||||
using lumiera::Subsys;
|
||||
using std::auto_ptr;
|
||||
using boost::scoped_ptr;
|
||||
using std::tr1::bind;
|
||||
|
||||
|
||||
namespace { // hidden local details of the service implementation....
|
||||
|
||||
/** details of how the DummyPlayer service can be started
|
||||
* and used as independent "subsystem" within main() */
|
||||
class DummyPlayerSubsysDescriptor
|
||||
: public Subsys
|
||||
{
|
||||
operator string () const { return "Dummy-Player"; }
|
||||
|
||||
|
||||
bool
|
||||
shouldStart (lumiera::Option&)
|
||||
{
|
||||
return false; // for now the DummyPlayerService only comes "up" as dependency,
|
||||
} // but doesn't start as a subsystem on it's own.
|
||||
|
||||
bool
|
||||
start (lumiera::Option&, Subsys::SigTerm terminationHandle)
|
||||
{
|
||||
ASSERT (!thePlayer_);
|
||||
|
||||
thePlayer_.reset (new DummyPlayerService (terminationHandle));
|
||||
return true;
|
||||
}
|
||||
|
||||
/** manages the actual (single) instance of the player service impl */
|
||||
scoped_ptr<DummyPlayerService> thePlayer_;
|
||||
|
||||
|
||||
void
|
||||
triggerShutdown () throw()
|
||||
{
|
||||
thePlayer_.reset(0);
|
||||
// note: shutdown of the DummyPlayerService instance may block
|
||||
// for a short period, until termination of all tick services
|
||||
}
|
||||
|
||||
bool
|
||||
checkRunningState () throw()
|
||||
{
|
||||
return (thePlayer_);
|
||||
}
|
||||
};
|
||||
|
||||
lib::Singleton<DummyPlayerSubsysDescriptor> theDummyPlayerDescriptor;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* ================== define an lumieraorg_DummyPlayer instance ======================= */
|
||||
|
||||
LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0
|
||||
,lumieraorg_DummyPlayerFacade_descriptor
|
||||
, NULL, NULL, NULL
|
||||
, LUMIERA_INTERFACE_INLINE (name, "\305\162\202\240\075\316\146\100\314\152\075\343\372\065\226\307",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "DummyPlayer"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (brief, "\317\045\366\076\064\072\156\274\220\346\262\207\062\367\057\232",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "Proc Interface: dummy player to test integration with the GUI"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (homepage, "\136\225\033\362\161\251\300\256\117\072\171\102\235\004\235\200",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "http://www.lumiera.org/develompent.html" ;}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (version, "\212\146\344\127\124\116\101\205\211\174\322\241\162\122\023\165",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "0.1~pre"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (author, "\064\226\072\300\054\345\042\357\337\226\155\025\306\051\117\105",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "Hermann Vosseler"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (email, "\041\075\220\112\246\304\261\135\003\135\060\202\230\327\303\206",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "Ichthyostega@web.de"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (copyright, "\232\305\163\271\174\025\270\075\012\201\331\256\327\375\066\210",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{
|
||||
(void)ifa;
|
||||
return
|
||||
"Copyright (C) Lumiera.org\n"
|
||||
" 2009 Hermann Vosseler <Ichthyostega@web.de>";
|
||||
}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (license, "\136\136\073\173\145\357\151\062\040\013\323\272\051\352\305\060",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{
|
||||
(void)ifa;
|
||||
return
|
||||
"This program is free software; you can redistribute it and/or modify\n"
|
||||
"it under the terms of the GNU General Public License as published by\n"
|
||||
"the Free Software Foundation; either version 2 of the License, or\n"
|
||||
"(at your option) any later version.\n"
|
||||
"\n"
|
||||
"This program is distributed in the hope that it will be useful,\n"
|
||||
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
|
||||
"GNU General Public License for more details.\n"
|
||||
"\n"
|
||||
"You should have received a copy of the GNU General Public License\n"
|
||||
"along with this program; if not, write to the Free Software\n"
|
||||
"Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA";
|
||||
}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (state, "\224\251\004\001\165\140\116\246\126\311\115\234\023\026\331\350",
|
||||
int, (LumieraInterface ifa),
|
||||
{(void)ifa; return LUMIERA_INTERFACE_EXPERIMENTAL; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (versioncmp, "\267\155\303\046\353\222\323\014\145\027\043\100\370\311\257\126",
|
||||
int, (const char* a, const char* b),
|
||||
{return 0;} ////////////////////////////////////////////TODO define version ordering
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
using lumiera::facade::LUMIERA_ERROR_FACADE_LIFECYCLE;
|
||||
typedef lib::SingletonRef<DummyPlayerService>::Accessor InstanceRef;
|
||||
|
||||
InstanceRef _instance; ///< a backdoor for the C Language impl to access the actual DummyPlayer implementation...
|
||||
|
||||
typedef ProcessImpl* ProcP;
|
||||
|
||||
|
||||
LUMIERA_INTERFACE_INSTANCE (lumieraorg_DummyPlayer, 0
|
||||
,lumieraorg_DummyPlayerService
|
||||
, LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_DummyPlayerFacade_descriptor)
|
||||
, NULL /* on open */
|
||||
, NULL /* on close */
|
||||
, LUMIERA_INTERFACE_INLINE (startPlay, "\143\323\102\155\051\006\235\004\037\310\354\121\176\142\342\210",
|
||||
LumieraPlayProcess, (LumieraDisplaySlot viewerHandle),
|
||||
{
|
||||
if (!_instance)
|
||||
{
|
||||
lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return static_cast<LumieraPlayProcess> (_instance->start(viewerHandle));
|
||||
}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (togglePlay, "\275\157\316\220\210\053\226\134\057\016\273\265\240\053\112\307",
|
||||
void, (LumieraPlayProcess handle, bool doPlay),
|
||||
{
|
||||
if (!_instance)
|
||||
{
|
||||
lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
REQUIRE (handle);
|
||||
ProcP proc = static_cast<ProcP> (handle);
|
||||
|
||||
proc->doPlay(doPlay);
|
||||
}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (terminate, "\005\265\115\021\076\143\010\215\373\252\370\174\235\136\340\004",
|
||||
void, (LumieraPlayProcess handle),
|
||||
{
|
||||
if (!_instance)
|
||||
{
|
||||
lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
REQUIRE (handle);
|
||||
ProcP proc = static_cast<ProcP> (handle);
|
||||
|
||||
ProcessImpl::terminate (proc);
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
} // (End) hidden service impl details
|
||||
|
||||
|
||||
|
||||
|
||||
DummyPlayerService::DummyPlayerService (Subsys::SigTerm terminationHandle)
|
||||
: error_("")
|
||||
, notifyTermination_(terminationHandle)
|
||||
, implInstance_(this,_instance)
|
||||
, serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_DummyPlayer, 0, lumieraorg_DummyPlayerService))
|
||||
{
|
||||
INFO (progress, "DummyPlayer Facade opened.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** @par implementation note
|
||||
* A new process (implementation) is created, configured
|
||||
* and started here. This may include spawning a thread or
|
||||
* allocating a timer. The newly created process is self-contained
|
||||
* and will be just handed out, without caring for its lifecycle.
|
||||
* If client code accesses this function via the plain C interface,
|
||||
* the client is responsible for terminating this process, whereas
|
||||
* when using the C++ interface, you'll get a Handle object which
|
||||
* manages the lifecycle automatically.
|
||||
*/
|
||||
ProcessImpl*
|
||||
DummyPlayerService::start (LumieraDisplaySlot viewerHandle)
|
||||
{
|
||||
auto_ptr<ProcessImpl> newProcess (new ProcessImpl (viewerHandle));
|
||||
|
||||
REQUIRE (!newProcess->isActive());
|
||||
newProcess->setRate(25);
|
||||
|
||||
return newProcess.release();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* === Process Implementation === */
|
||||
|
||||
|
||||
ProcessImpl::ProcessImpl(LumieraDisplaySlot viewerHandle)
|
||||
: fps_(0)
|
||||
, play_(false)
|
||||
, display_(Display::facade().getHandle (viewerHandle))
|
||||
, imageGen_(0)
|
||||
, tick_(new TickService (bind (&ProcessImpl::doFrame, this)))
|
||||
{ }
|
||||
|
||||
|
||||
ProcessImpl::~ProcessImpl()
|
||||
{
|
||||
INFO (proc_dbg, "Playback process halted...");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ProcessImpl::terminate (ProcessImpl* process) ///< deleter function for lib::Handle
|
||||
{
|
||||
if (process)
|
||||
delete process;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DummyPlayer::Process
|
||||
ProcessImpl::createHandle()
|
||||
{
|
||||
DummyPlayer::Process handle;
|
||||
handle.activate(this, &terminate); // note the deleter function...
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ProcessImpl::setRate (uint fps)
|
||||
{
|
||||
REQUIRE (fps==0 || fps_==0 );
|
||||
REQUIRE (fps==0 || !play_ );
|
||||
REQUIRE (tick_);
|
||||
|
||||
fps_ = fps;
|
||||
play_ = (fps != 0);
|
||||
|
||||
if (play_)
|
||||
imageGen_.reset(new DummyImageGenerator(fps));
|
||||
|
||||
// callbacks with given frequency, starting now
|
||||
tick_->activate(fps);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ProcessImpl::doPlay(bool yes)
|
||||
{
|
||||
REQUIRE (isActive());
|
||||
tick_->activate (yes? fps_:0);
|
||||
play_ = yes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ProcessImpl::doFrame()
|
||||
{
|
||||
REQUIRE (isActive());
|
||||
ASSERT (imageGen_);
|
||||
|
||||
if (play_)
|
||||
display_(imageGen_->next());
|
||||
else
|
||||
display_(imageGen_->current());
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace play
|
||||
|
||||
} // namespace proc
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace lumiera { /* === Forwarding function(s) on the Process handle === */
|
||||
|
||||
void DummyPlayer::Process::play(bool yes) { impl().doPlay(yes); }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** @internal intended for use by main(). */
|
||||
lumiera::Subsys&
|
||||
DummyPlayer::getDescriptor()
|
||||
{
|
||||
return proc::play::theDummyPlayerDescriptor();
|
||||
}
|
||||
|
||||
// emit the vtable here into this translation unit within liblumieraproc.so ...
|
||||
DummyPlayer::~DummyPlayer() { }
|
||||
|
||||
|
||||
} // namespace lumiera
|
||||
252
src/proc/play/output-manager.cpp
Normal file
252
src/proc/play/output-manager.cpp
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
DisplayService - service providing access to a display for outputting frames
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2009, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
* *****************************************************/
|
||||
|
||||
|
||||
#include "gui/display-service.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "common/interfacedescriptor.h"
|
||||
}
|
||||
|
||||
|
||||
namespace gui {
|
||||
|
||||
|
||||
|
||||
namespace { // hidden local details of the service implementation....
|
||||
|
||||
|
||||
|
||||
/* ================== define an lumieraorg_Display instance ======================= */
|
||||
|
||||
LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0
|
||||
,lumieraorg_DisplayFacade_descriptor
|
||||
, NULL, NULL, NULL
|
||||
, LUMIERA_INTERFACE_INLINE (name, "\323\343\324\023\064\216\120\201\073\056\366\020\110\263\060\023",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "Display"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (brief, "\305\026\070\133\033\357\014\202\203\270\174\072\341\256\226\235",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "UI Interface: service for outputting frames to a viewer or display"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (homepage, "\170\104\246\175\123\144\332\312\315\263\071\170\164\213\024\275",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "http://www.lumiera.org/develompent.html" ;}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (version, "\265\343\045\346\110\241\276\111\217\120\155\246\230\341\344\124",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "0.1~pre"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (author, "\302\027\122\045\301\166\046\236\257\253\144\035\105\166\070\103",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "Hermann Vosseler"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (email, "\074\013\020\161\075\135\302\265\260\000\301\147\116\355\035\261",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "Ichthyostega@web.de"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (copyright, "\037\232\153\100\114\103\074\342\164\132\370\210\372\164\115\275",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{
|
||||
(void)ifa;
|
||||
return
|
||||
"Copyright (C) Lumiera.org\n"
|
||||
" 2009 Hermann Vosseler <Ichthyostega@web.de>";
|
||||
}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (license, "\026\243\334\056\125\245\315\311\155\375\262\344\007\076\341\254",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{
|
||||
(void)ifa;
|
||||
return
|
||||
"This program is free software; you can redistribute it and/or modify\n"
|
||||
"it under the terms of the GNU General Public License as published by\n"
|
||||
"the Free Software Foundation; either version 2 of the License, or\n"
|
||||
"(at your option) any later version.\n"
|
||||
"\n"
|
||||
"This program is distributed in the hope that it will be useful,\n"
|
||||
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
|
||||
"GNU General Public License for more details.\n"
|
||||
"\n"
|
||||
"You should have received a copy of the GNU General Public License\n"
|
||||
"along with this program; if not, write to the Free Software\n"
|
||||
"Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA";
|
||||
}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (state, "\243\302\332\160\060\272\155\334\212\256\303\141\160\063\164\154",
|
||||
int, (LumieraInterface ifa),
|
||||
{(void)ifa; return LUMIERA_INTERFACE_EXPERIMENTAL; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (versioncmp, "\363\125\123\060\231\147\053\017\131\341\105\157\231\273\334\136",
|
||||
int, (const char* a, const char* b),
|
||||
{return 0;} ////////////////////////////////////////////TODO define version ordering
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
using lumiera::facade::LUMIERA_ERROR_FACADE_LIFECYCLE;
|
||||
typedef lib::SingletonRef<DisplayService>::Accessor InstanceRef;
|
||||
|
||||
InstanceRef _instance; ///< a backdoor for the C Language impl to access the actual DisplayService implementation...
|
||||
|
||||
|
||||
|
||||
LUMIERA_INTERFACE_INSTANCE (lumieraorg_Display, 0
|
||||
,lumieraorg_DisplayService
|
||||
, LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_DisplayFacade_descriptor)
|
||||
, NULL /* on open */
|
||||
, NULL /* on close */
|
||||
, LUMIERA_INTERFACE_INLINE (allocate, "\177\221\146\253\255\161\160\137\015\005\263\362\307\022\243\365",
|
||||
void, (LumieraDisplaySlot slotHandle),
|
||||
{
|
||||
if (!_instance)
|
||||
{
|
||||
lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
REQUIRE (slotHandle);
|
||||
try
|
||||
{
|
||||
_instance->allocate (slotHandle,true);
|
||||
}
|
||||
catch (lumiera::Error&){ /* error state remains set */ }
|
||||
}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (release, "\166\374\106\313\011\142\115\161\111\110\376\016\346\115\240\364",
|
||||
void, (LumieraDisplaySlot slotHandle),
|
||||
{
|
||||
if (!_instance)
|
||||
{
|
||||
lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
REQUIRE (slotHandle);
|
||||
_instance->allocate (slotHandle,false);
|
||||
}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (put, "\340\062\234\227\152\131\370\272\146\207\224\015\361\070\252\135",
|
||||
void, (LumieraDisplaySlot slotHandle, LumieraDisplayFrame frame),
|
||||
{
|
||||
//skipping full checks for performance reasons
|
||||
REQUIRE (_instance && !lumiera_error_peek());
|
||||
|
||||
REQUIRE (slotHandle);
|
||||
DisplayerSlot& slot = _instance->resolve (slotHandle);
|
||||
slot.put (frame);
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
} // (End) hidden service impl details
|
||||
|
||||
|
||||
|
||||
|
||||
DisplayService::DisplayService()
|
||||
: error_("")
|
||||
, implInstance_(this,_instance)
|
||||
, serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_Display, 0, lumieraorg_DisplayService))
|
||||
{
|
||||
INFO (progress, "Display Facade opened.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
LumieraDisplaySlot
|
||||
DisplayService::setUp (FrameDestination const& outputDestination)
|
||||
{
|
||||
DisplayerTab& slots (_instance->slots_);
|
||||
return &slots.manage (new DisplayerSlot (outputDestination));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
DisplayService::allocate (LumieraDisplaySlot handle, bool doAllocate)
|
||||
{
|
||||
REQUIRE (handle);
|
||||
if (doAllocate)
|
||||
{
|
||||
if (handle->put_)
|
||||
throw lumiera::error::Logic("slot already allocated for output");
|
||||
else
|
||||
// Mark the handle as "allocated" and ready for output:
|
||||
// Place the function pointer from the C interface into the handle struct.
|
||||
// calling it will invoke the implementing instance's "put" function
|
||||
// (see the LUMIERA_INTERFACE_INLINE above in this file!)
|
||||
handle->put_ = serviceInstance_.get().put;
|
||||
}
|
||||
else
|
||||
handle->put_ = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DisplayerSlot&
|
||||
DisplayService::resolve (LumieraDisplaySlot handle)
|
||||
{
|
||||
REQUIRE (handle);
|
||||
REQUIRE (handle->put_, "accessing a DisplayerSlot, which hasn't been locked for output");
|
||||
|
||||
return *static_cast<DisplayerSlot*> (handle);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* === DisplayerSlot Implementation === */
|
||||
|
||||
|
||||
DisplayerSlot::DisplayerSlot (FrameDestination const& outputDestination)
|
||||
: currBuffer_(0)
|
||||
{
|
||||
put_ = 0; // mark as not allocated
|
||||
hasFrame_.connect (outputDestination);
|
||||
dispatcher_.connect (sigc::mem_fun (this, &DisplayerSlot::displayCurrentFrame));
|
||||
}
|
||||
|
||||
|
||||
DisplayerSlot::~DisplayerSlot()
|
||||
{
|
||||
TRACE (gui_dbg, "Displayer Slot closing...");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DisplayerSlot::displayCurrentFrame()
|
||||
{
|
||||
hasFrame_.emit (currBuffer_);
|
||||
}
|
||||
|
||||
|
||||
} // namespace proc
|
||||
190
src/proc/play/output-manager.hpp
Normal file
190
src/proc/play/output-manager.hpp
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
DISPLAY-SERVICE.hpp - service providing access to a display for outputting frames
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2009, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
/** @file display-service.hpp
|
||||
** A public service provided by the GUI, implementing the lumiera::Display facade interface.
|
||||
** It serves two purposes:
|
||||
** - It maintains a collection of DisplayerSlot objects, which are the actual connection points
|
||||
** and allow to receive frames and dispatch them to the GTK main event loop thread.
|
||||
** Conceptually, creating such a slot means providing a possible display for output.
|
||||
** - It provides the actual implementation of the Display facade interface, i.e. the function
|
||||
** which is to invoked periodically by the playback processes to dispose a new frame into
|
||||
** the display.
|
||||
**
|
||||
** This service is the implementation of a layer separation facade interface. This header defines
|
||||
** the interface used to \em provide this service, not to access it. Clients get a specific
|
||||
** LumieraDisplaySlot passed as parameter when initiating a playback process from the GUI. Using
|
||||
** this LumieraDisplaySlot handle, clients should then use lumiera::DummyPlayer#facade to access
|
||||
** an implementation instance of this service in order to push actual frames up.
|
||||
**
|
||||
** @see lumiera::Display
|
||||
** @see lumiera::DummyPlayer
|
||||
** @see gui::PlaybackController usage example
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GUI_DISPLAY_SERVICE_H
|
||||
#define GUI_DISPLAY_SERVICE_H
|
||||
|
||||
|
||||
#include "include/display-facade.h"
|
||||
#include "common/instancehandle.hpp"
|
||||
#include "lib/singleton-ref.hpp"
|
||||
#include "lib/scoped-ptrvect.hpp"
|
||||
|
||||
#include <glibmm.h>
|
||||
#include <sigc++/sigc++.h>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace gui {
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using lumiera::Display;
|
||||
using Glib::Dispatcher;
|
||||
|
||||
|
||||
typedef sigc::slot<void, void*> FrameDestination;
|
||||
typedef sigc::signal<void, void*> FrameSignal;
|
||||
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Actual implementation of a single displayer slot. Internally,
|
||||
* it is connected via the Glib::Dispatcher for outputting frames
|
||||
* to a viewer widget, which executes within the GTK event thread.
|
||||
* @note must be created from the GTK event thread.
|
||||
*/
|
||||
class DisplayerSlot
|
||||
: public lumiera_displaySlot,
|
||||
boost::noncopyable
|
||||
{
|
||||
Dispatcher dispatcher_;
|
||||
FrameSignal hasFrame_;
|
||||
|
||||
LumieraDisplayFrame currBuffer_;
|
||||
|
||||
|
||||
public:
|
||||
DisplayerSlot (FrameDestination const&) ;
|
||||
~DisplayerSlot () ;
|
||||
|
||||
/* Implementation-level API to be used by DisplayService */
|
||||
|
||||
/** receive a frame to be displayed */
|
||||
inline void put (LumieraDisplayFrame);
|
||||
|
||||
|
||||
private:
|
||||
/** internal: activated via Dispatcher
|
||||
* and running in GTK main thread */
|
||||
void displayCurrentFrame();
|
||||
|
||||
};
|
||||
|
||||
typedef lib::ScopedPtrVect<DisplayerSlot> DisplayerTab;
|
||||
|
||||
|
||||
|
||||
/******************************************************
|
||||
* Actual implementation of the DisplayService.
|
||||
* Creating an instance of this class automatically
|
||||
* registers the interface lumieraorg_Display with
|
||||
* the Lumiera Interface/Plugin system and creates
|
||||
* a forwarding proxy within the application core to
|
||||
* route calls through this interface.
|
||||
* \par
|
||||
* In addition to the Display interface, this class
|
||||
* implements an additional service for the GUI,
|
||||
* allowing actually to set up display slots, which
|
||||
* then can be handed out to client code in the
|
||||
* course of the play process for outputting frames.
|
||||
*/
|
||||
class DisplayService
|
||||
: boost::noncopyable
|
||||
{
|
||||
|
||||
string error_;
|
||||
DisplayerTab slots_;
|
||||
|
||||
|
||||
/* === Interface Lifecycle === */
|
||||
|
||||
typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_Display, 0)
|
||||
, lumiera::Display
|
||||
> ServiceInstanceHandle;
|
||||
|
||||
lib::SingletonRef<DisplayService> implInstance_;
|
||||
ServiceInstanceHandle serviceInstance_;
|
||||
|
||||
|
||||
public:
|
||||
DisplayService();
|
||||
~DisplayService() {
|
||||
INFO (proc_dbg, "Display service dying...");
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** open a new display, sending frames to the given output destination
|
||||
* @return handle for this slot, can be used to start a play process.
|
||||
* NULL handle in case of any error. */
|
||||
static LumieraDisplaySlot setUp (FrameDestination const&);
|
||||
|
||||
|
||||
/** prepare and the given slot for output
|
||||
* @param doAllocate allocate when true, else release it
|
||||
* @throw lumiera::error::Logic when already in use */
|
||||
void allocate (LumieraDisplaySlot, bool doAllocate);
|
||||
|
||||
|
||||
/** resolve the given display slot handle to yield a ref
|
||||
* to an actual implementation object. In order to be resolvable,
|
||||
* the DisplayerSlot needs to be locked (=allocated) for output use. */
|
||||
DisplayerSlot& resolve (LumieraDisplaySlot);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
DisplayerSlot::put(LumieraDisplayFrame newFrame)
|
||||
{
|
||||
if (newFrame != currBuffer_)
|
||||
{
|
||||
currBuffer_ = newFrame;
|
||||
dispatcher_.emit();
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE (render, "frame dropped?");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace gui
|
||||
#endif
|
||||
161
src/proc/play/play-controller.hpp
Normal file
161
src/proc/play/play-controller.hpp
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
DUMMY-PLAYER-SERVICE.hpp - service implementing a dummy test player
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2009, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
/** @file dummy-player-service.hpp
|
||||
** A public service provided by the Proc-Layer, implementing a dummy/mockup playback process.
|
||||
** This is a design sketch; Lumiera isn't able to generate rendered output as of 2/2009. The
|
||||
** idea is, that for each ongoing calculation process, there is a ProcessImpl instance holding
|
||||
** the necessary handles and allocations and providing an uniform API to the client side.
|
||||
** Especially, this ProcessImpl holds a TickService, which generates periodic callbacks, and
|
||||
** it uses an output handle (functor) to push the generated frames up.
|
||||
**
|
||||
** This service is the implementation of a layer separation facade interface. Clients should use
|
||||
** proc::play::DummyPlayer#facade to access this service. This header defines the interface used
|
||||
** to \em provide this service, not to access it.
|
||||
**
|
||||
** @see lumiera::DummyPlayer
|
||||
** @see gui::PlaybackController usage example
|
||||
*/
|
||||
|
||||
|
||||
#ifndef PROC_DUMMYPLAYER_SERVICE_H
|
||||
#define PROC_DUMMYPLAYER_SERVICE_H
|
||||
|
||||
|
||||
#include "include/dummy-player-facade.h"
|
||||
#include "include/display-facade.h"
|
||||
#include "common/instancehandle.hpp"
|
||||
#include "lib/singleton-ref.hpp"
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace proc {
|
||||
namespace play {
|
||||
|
||||
using std::string;
|
||||
using lumiera::Subsys;
|
||||
using lumiera::Display;
|
||||
using lumiera::DummyPlayer;
|
||||
|
||||
|
||||
class DummyImageGenerator;
|
||||
class TickService;
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Actual implementation of a single (dummy) playback process.
|
||||
* The DummyPlayerService (see below) maintains a collection of such
|
||||
* actively running playback processes, while the client code gets
|
||||
* DummyPlayer::Process handles to track any ongoing use. Users of
|
||||
* the plain C interface get a direct bare pointer to the respective
|
||||
* ProcessImpl instance and have to manage the lifecycle manually.
|
||||
*/
|
||||
class ProcessImpl
|
||||
: public lumiera_playprocess,
|
||||
boost::noncopyable
|
||||
{
|
||||
uint fps_;
|
||||
bool play_;
|
||||
|
||||
Display::Sink display_;
|
||||
boost::scoped_ptr<DummyImageGenerator> imageGen_;
|
||||
boost::scoped_ptr<TickService> tick_;
|
||||
|
||||
|
||||
public:
|
||||
ProcessImpl(LumieraDisplaySlot) ;
|
||||
~ProcessImpl() ;
|
||||
|
||||
|
||||
/* Implementation-level API */
|
||||
|
||||
/** activate a playback process
|
||||
* with given specification */
|
||||
void setRate (uint fps);
|
||||
|
||||
bool isActive () { return fps_ != 0; }
|
||||
bool isPlaying() { return play_; }
|
||||
|
||||
void doPlay(bool yes);
|
||||
|
||||
|
||||
/* Lifecycle */
|
||||
|
||||
DummyPlayer::Process createHandle();
|
||||
static void terminate(ProcessImpl* process);
|
||||
|
||||
private:
|
||||
void doFrame (); ///< periodically invoked while playing
|
||||
};
|
||||
|
||||
|
||||
|
||||
/******************************************************
|
||||
* Actual implementation of the DummyPlayer service.
|
||||
* Creating an instance of this class automatically
|
||||
* registers the interface lumieraorg_DummyPlayer with
|
||||
* the Lumiera Interface/Plugin system and creates
|
||||
* a forwarding proxy within the application core to
|
||||
* route calls through this interface.
|
||||
*/
|
||||
class DummyPlayerService
|
||||
: boost::noncopyable
|
||||
{
|
||||
|
||||
string error_;
|
||||
Subsys::SigTerm notifyTermination_;
|
||||
|
||||
|
||||
/* === Interface Lifecycle === */
|
||||
|
||||
typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_DummyPlayer, 0)
|
||||
, DummyPlayer
|
||||
> ServiceInstanceHandle;
|
||||
|
||||
lib::SingletonRef<DummyPlayerService> implInstance_;
|
||||
ServiceInstanceHandle serviceInstance_;
|
||||
|
||||
public:
|
||||
DummyPlayerService(Subsys::SigTerm terminationHandle);
|
||||
|
||||
~DummyPlayerService() { notifyTermination_(&error_); }
|
||||
|
||||
|
||||
|
||||
/** conceptually, this serves as implementation
|
||||
* of the DummyPlayer#start() function. But because
|
||||
* this function sits \em behind the interface, it
|
||||
* just returns an impl pointer. */
|
||||
ProcessImpl* start (LumieraDisplaySlot viewerHandle);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace play
|
||||
|
||||
} // namespace proc
|
||||
#endif
|
||||
382
src/proc/play/play-process.cpp
Normal file
382
src/proc/play/play-process.cpp
Normal file
|
|
@ -0,0 +1,382 @@
|
|||
/*
|
||||
DummyPlayerService - access point and service implementing a dummy test player
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2009, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
* *****************************************************/
|
||||
|
||||
|
||||
#include "proc/play/dummy-player-service.hpp"
|
||||
#include "proc/play/dummy-image-generator.hpp"
|
||||
#include "proc/play/tick-service.hpp"
|
||||
#include "lib/singleton.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "common/interfacedescriptor.h"
|
||||
}
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <tr1/functional>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
|
||||
|
||||
namespace proc {
|
||||
namespace play{
|
||||
|
||||
using std::string;
|
||||
using lumiera::Subsys;
|
||||
using std::auto_ptr;
|
||||
using boost::scoped_ptr;
|
||||
using std::tr1::bind;
|
||||
|
||||
|
||||
namespace { // hidden local details of the service implementation....
|
||||
|
||||
/** details of how the DummyPlayer service can be started
|
||||
* and used as independent "subsystem" within main() */
|
||||
class DummyPlayerSubsysDescriptor
|
||||
: public Subsys
|
||||
{
|
||||
operator string () const { return "Dummy-Player"; }
|
||||
|
||||
|
||||
bool
|
||||
shouldStart (lumiera::Option&)
|
||||
{
|
||||
return false; // for now the DummyPlayerService only comes "up" as dependency,
|
||||
} // but doesn't start as a subsystem on it's own.
|
||||
|
||||
bool
|
||||
start (lumiera::Option&, Subsys::SigTerm terminationHandle)
|
||||
{
|
||||
ASSERT (!thePlayer_);
|
||||
|
||||
thePlayer_.reset (new DummyPlayerService (terminationHandle));
|
||||
return true;
|
||||
}
|
||||
|
||||
/** manages the actual (single) instance of the player service impl */
|
||||
scoped_ptr<DummyPlayerService> thePlayer_;
|
||||
|
||||
|
||||
void
|
||||
triggerShutdown () throw()
|
||||
{
|
||||
thePlayer_.reset(0);
|
||||
// note: shutdown of the DummyPlayerService instance may block
|
||||
// for a short period, until termination of all tick services
|
||||
}
|
||||
|
||||
bool
|
||||
checkRunningState () throw()
|
||||
{
|
||||
return (thePlayer_);
|
||||
}
|
||||
};
|
||||
|
||||
lib::Singleton<DummyPlayerSubsysDescriptor> theDummyPlayerDescriptor;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* ================== define an lumieraorg_DummyPlayer instance ======================= */
|
||||
|
||||
LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0
|
||||
,lumieraorg_DummyPlayerFacade_descriptor
|
||||
, NULL, NULL, NULL
|
||||
, LUMIERA_INTERFACE_INLINE (name, "\305\162\202\240\075\316\146\100\314\152\075\343\372\065\226\307",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "DummyPlayer"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (brief, "\317\045\366\076\064\072\156\274\220\346\262\207\062\367\057\232",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "Proc Interface: dummy player to test integration with the GUI"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (homepage, "\136\225\033\362\161\251\300\256\117\072\171\102\235\004\235\200",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "http://www.lumiera.org/develompent.html" ;}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (version, "\212\146\344\127\124\116\101\205\211\174\322\241\162\122\023\165",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "0.1~pre"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (author, "\064\226\072\300\054\345\042\357\337\226\155\025\306\051\117\105",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "Hermann Vosseler"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (email, "\041\075\220\112\246\304\261\135\003\135\060\202\230\327\303\206",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "Ichthyostega@web.de"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (copyright, "\232\305\163\271\174\025\270\075\012\201\331\256\327\375\066\210",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{
|
||||
(void)ifa;
|
||||
return
|
||||
"Copyright (C) Lumiera.org\n"
|
||||
" 2009 Hermann Vosseler <Ichthyostega@web.de>";
|
||||
}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (license, "\136\136\073\173\145\357\151\062\040\013\323\272\051\352\305\060",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{
|
||||
(void)ifa;
|
||||
return
|
||||
"This program is free software; you can redistribute it and/or modify\n"
|
||||
"it under the terms of the GNU General Public License as published by\n"
|
||||
"the Free Software Foundation; either version 2 of the License, or\n"
|
||||
"(at your option) any later version.\n"
|
||||
"\n"
|
||||
"This program is distributed in the hope that it will be useful,\n"
|
||||
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
|
||||
"GNU General Public License for more details.\n"
|
||||
"\n"
|
||||
"You should have received a copy of the GNU General Public License\n"
|
||||
"along with this program; if not, write to the Free Software\n"
|
||||
"Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA";
|
||||
}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (state, "\224\251\004\001\165\140\116\246\126\311\115\234\023\026\331\350",
|
||||
int, (LumieraInterface ifa),
|
||||
{(void)ifa; return LUMIERA_INTERFACE_EXPERIMENTAL; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (versioncmp, "\267\155\303\046\353\222\323\014\145\027\043\100\370\311\257\126",
|
||||
int, (const char* a, const char* b),
|
||||
{return 0;} ////////////////////////////////////////////TODO define version ordering
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
using lumiera::facade::LUMIERA_ERROR_FACADE_LIFECYCLE;
|
||||
typedef lib::SingletonRef<DummyPlayerService>::Accessor InstanceRef;
|
||||
|
||||
InstanceRef _instance; ///< a backdoor for the C Language impl to access the actual DummyPlayer implementation...
|
||||
|
||||
typedef ProcessImpl* ProcP;
|
||||
|
||||
|
||||
LUMIERA_INTERFACE_INSTANCE (lumieraorg_DummyPlayer, 0
|
||||
,lumieraorg_DummyPlayerService
|
||||
, LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_DummyPlayerFacade_descriptor)
|
||||
, NULL /* on open */
|
||||
, NULL /* on close */
|
||||
, LUMIERA_INTERFACE_INLINE (startPlay, "\143\323\102\155\051\006\235\004\037\310\354\121\176\142\342\210",
|
||||
LumieraPlayProcess, (LumieraDisplaySlot viewerHandle),
|
||||
{
|
||||
if (!_instance)
|
||||
{
|
||||
lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return static_cast<LumieraPlayProcess> (_instance->start(viewerHandle));
|
||||
}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (togglePlay, "\275\157\316\220\210\053\226\134\057\016\273\265\240\053\112\307",
|
||||
void, (LumieraPlayProcess handle, bool doPlay),
|
||||
{
|
||||
if (!_instance)
|
||||
{
|
||||
lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
REQUIRE (handle);
|
||||
ProcP proc = static_cast<ProcP> (handle);
|
||||
|
||||
proc->doPlay(doPlay);
|
||||
}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (terminate, "\005\265\115\021\076\143\010\215\373\252\370\174\235\136\340\004",
|
||||
void, (LumieraPlayProcess handle),
|
||||
{
|
||||
if (!_instance)
|
||||
{
|
||||
lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
REQUIRE (handle);
|
||||
ProcP proc = static_cast<ProcP> (handle);
|
||||
|
||||
ProcessImpl::terminate (proc);
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
} // (End) hidden service impl details
|
||||
|
||||
|
||||
|
||||
|
||||
DummyPlayerService::DummyPlayerService (Subsys::SigTerm terminationHandle)
|
||||
: error_("")
|
||||
, notifyTermination_(terminationHandle)
|
||||
, implInstance_(this,_instance)
|
||||
, serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_DummyPlayer, 0, lumieraorg_DummyPlayerService))
|
||||
{
|
||||
INFO (progress, "DummyPlayer Facade opened.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** @par implementation note
|
||||
* A new process (implementation) is created, configured
|
||||
* and started here. This may include spawning a thread or
|
||||
* allocating a timer. The newly created process is self-contained
|
||||
* and will be just handed out, without caring for its lifecycle.
|
||||
* If client code accesses this function via the plain C interface,
|
||||
* the client is responsible for terminating this process, whereas
|
||||
* when using the C++ interface, you'll get a Handle object which
|
||||
* manages the lifecycle automatically.
|
||||
*/
|
||||
ProcessImpl*
|
||||
DummyPlayerService::start (LumieraDisplaySlot viewerHandle)
|
||||
{
|
||||
auto_ptr<ProcessImpl> newProcess (new ProcessImpl (viewerHandle));
|
||||
|
||||
REQUIRE (!newProcess->isActive());
|
||||
newProcess->setRate(25);
|
||||
|
||||
return newProcess.release();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* === Process Implementation === */
|
||||
|
||||
|
||||
ProcessImpl::ProcessImpl(LumieraDisplaySlot viewerHandle)
|
||||
: fps_(0)
|
||||
, play_(false)
|
||||
, display_(Display::facade().getHandle (viewerHandle))
|
||||
, imageGen_(0)
|
||||
, tick_(new TickService (bind (&ProcessImpl::doFrame, this)))
|
||||
{ }
|
||||
|
||||
|
||||
ProcessImpl::~ProcessImpl()
|
||||
{
|
||||
INFO (proc_dbg, "Playback process halted...");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ProcessImpl::terminate (ProcessImpl* process) ///< deleter function for lib::Handle
|
||||
{
|
||||
if (process)
|
||||
delete process;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DummyPlayer::Process
|
||||
ProcessImpl::createHandle()
|
||||
{
|
||||
DummyPlayer::Process handle;
|
||||
handle.activate(this, &terminate); // note the deleter function...
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ProcessImpl::setRate (uint fps)
|
||||
{
|
||||
REQUIRE (fps==0 || fps_==0 );
|
||||
REQUIRE (fps==0 || !play_ );
|
||||
REQUIRE (tick_);
|
||||
|
||||
fps_ = fps;
|
||||
play_ = (fps != 0);
|
||||
|
||||
if (play_)
|
||||
imageGen_.reset(new DummyImageGenerator(fps));
|
||||
|
||||
// callbacks with given frequency, starting now
|
||||
tick_->activate(fps);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ProcessImpl::doPlay(bool yes)
|
||||
{
|
||||
REQUIRE (isActive());
|
||||
tick_->activate (yes? fps_:0);
|
||||
play_ = yes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ProcessImpl::doFrame()
|
||||
{
|
||||
REQUIRE (isActive());
|
||||
ASSERT (imageGen_);
|
||||
|
||||
if (play_)
|
||||
display_(imageGen_->next());
|
||||
else
|
||||
display_(imageGen_->current());
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace play
|
||||
|
||||
} // namespace proc
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace lumiera { /* === Forwarding function(s) on the Process handle === */
|
||||
|
||||
void DummyPlayer::Process::play(bool yes) { impl().doPlay(yes); }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** @internal intended for use by main(). */
|
||||
lumiera::Subsys&
|
||||
DummyPlayer::getDescriptor()
|
||||
{
|
||||
return proc::play::theDummyPlayerDescriptor();
|
||||
}
|
||||
|
||||
// emit the vtable here into this translation unit within liblumieraproc.so ...
|
||||
DummyPlayer::~DummyPlayer() { }
|
||||
|
||||
|
||||
} // namespace lumiera
|
||||
161
src/proc/play/play-process.hpp
Normal file
161
src/proc/play/play-process.hpp
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
DUMMY-PLAYER-SERVICE.hpp - service implementing a dummy test player
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2009, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
/** @file dummy-player-service.hpp
|
||||
** A public service provided by the Proc-Layer, implementing a dummy/mockup playback process.
|
||||
** This is a design sketch; Lumiera isn't able to generate rendered output as of 2/2009. The
|
||||
** idea is, that for each ongoing calculation process, there is a ProcessImpl instance holding
|
||||
** the necessary handles and allocations and providing an uniform API to the client side.
|
||||
** Especially, this ProcessImpl holds a TickService, which generates periodic callbacks, and
|
||||
** it uses an output handle (functor) to push the generated frames up.
|
||||
**
|
||||
** This service is the implementation of a layer separation facade interface. Clients should use
|
||||
** proc::play::DummyPlayer#facade to access this service. This header defines the interface used
|
||||
** to \em provide this service, not to access it.
|
||||
**
|
||||
** @see lumiera::DummyPlayer
|
||||
** @see gui::PlaybackController usage example
|
||||
*/
|
||||
|
||||
|
||||
#ifndef PROC_DUMMYPLAYER_SERVICE_H
|
||||
#define PROC_DUMMYPLAYER_SERVICE_H
|
||||
|
||||
|
||||
#include "include/dummy-player-facade.h"
|
||||
#include "include/display-facade.h"
|
||||
#include "common/instancehandle.hpp"
|
||||
#include "lib/singleton-ref.hpp"
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace proc {
|
||||
namespace play {
|
||||
|
||||
using std::string;
|
||||
using lumiera::Subsys;
|
||||
using lumiera::Display;
|
||||
using lumiera::DummyPlayer;
|
||||
|
||||
|
||||
class DummyImageGenerator;
|
||||
class TickService;
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Actual implementation of a single (dummy) playback process.
|
||||
* The DummyPlayerService (see below) maintains a collection of such
|
||||
* actively running playback processes, while the client code gets
|
||||
* DummyPlayer::Process handles to track any ongoing use. Users of
|
||||
* the plain C interface get a direct bare pointer to the respective
|
||||
* ProcessImpl instance and have to manage the lifecycle manually.
|
||||
*/
|
||||
class ProcessImpl
|
||||
: public lumiera_playprocess,
|
||||
boost::noncopyable
|
||||
{
|
||||
uint fps_;
|
||||
bool play_;
|
||||
|
||||
Display::Sink display_;
|
||||
boost::scoped_ptr<DummyImageGenerator> imageGen_;
|
||||
boost::scoped_ptr<TickService> tick_;
|
||||
|
||||
|
||||
public:
|
||||
ProcessImpl(LumieraDisplaySlot) ;
|
||||
~ProcessImpl() ;
|
||||
|
||||
|
||||
/* Implementation-level API */
|
||||
|
||||
/** activate a playback process
|
||||
* with given specification */
|
||||
void setRate (uint fps);
|
||||
|
||||
bool isActive () { return fps_ != 0; }
|
||||
bool isPlaying() { return play_; }
|
||||
|
||||
void doPlay(bool yes);
|
||||
|
||||
|
||||
/* Lifecycle */
|
||||
|
||||
DummyPlayer::Process createHandle();
|
||||
static void terminate(ProcessImpl* process);
|
||||
|
||||
private:
|
||||
void doFrame (); ///< periodically invoked while playing
|
||||
};
|
||||
|
||||
|
||||
|
||||
/******************************************************
|
||||
* Actual implementation of the DummyPlayer service.
|
||||
* Creating an instance of this class automatically
|
||||
* registers the interface lumieraorg_DummyPlayer with
|
||||
* the Lumiera Interface/Plugin system and creates
|
||||
* a forwarding proxy within the application core to
|
||||
* route calls through this interface.
|
||||
*/
|
||||
class DummyPlayerService
|
||||
: boost::noncopyable
|
||||
{
|
||||
|
||||
string error_;
|
||||
Subsys::SigTerm notifyTermination_;
|
||||
|
||||
|
||||
/* === Interface Lifecycle === */
|
||||
|
||||
typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_DummyPlayer, 0)
|
||||
, DummyPlayer
|
||||
> ServiceInstanceHandle;
|
||||
|
||||
lib::SingletonRef<DummyPlayerService> implInstance_;
|
||||
ServiceInstanceHandle serviceInstance_;
|
||||
|
||||
public:
|
||||
DummyPlayerService(Subsys::SigTerm terminationHandle);
|
||||
|
||||
~DummyPlayerService() { notifyTermination_(&error_); }
|
||||
|
||||
|
||||
|
||||
/** conceptually, this serves as implementation
|
||||
* of the DummyPlayer#start() function. But because
|
||||
* this function sits \em behind the interface, it
|
||||
* just returns an impl pointer. */
|
||||
ProcessImpl* start (LumieraDisplaySlot viewerHandle);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace play
|
||||
|
||||
} // namespace proc
|
||||
#endif
|
||||
382
src/proc/play/play-service.cpp
Normal file
382
src/proc/play/play-service.cpp
Normal file
|
|
@ -0,0 +1,382 @@
|
|||
/*
|
||||
DummyPlayerService - access point and service implementing a dummy test player
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2009, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
* *****************************************************/
|
||||
|
||||
|
||||
#include "proc/play/dummy-player-service.hpp"
|
||||
#include "proc/play/dummy-image-generator.hpp"
|
||||
#include "proc/play/tick-service.hpp"
|
||||
#include "lib/singleton.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "common/interfacedescriptor.h"
|
||||
}
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <tr1/functional>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
|
||||
|
||||
namespace proc {
|
||||
namespace play{
|
||||
|
||||
using std::string;
|
||||
using lumiera::Subsys;
|
||||
using std::auto_ptr;
|
||||
using boost::scoped_ptr;
|
||||
using std::tr1::bind;
|
||||
|
||||
|
||||
namespace { // hidden local details of the service implementation....
|
||||
|
||||
/** details of how the DummyPlayer service can be started
|
||||
* and used as independent "subsystem" within main() */
|
||||
class DummyPlayerSubsysDescriptor
|
||||
: public Subsys
|
||||
{
|
||||
operator string () const { return "Dummy-Player"; }
|
||||
|
||||
|
||||
bool
|
||||
shouldStart (lumiera::Option&)
|
||||
{
|
||||
return false; // for now the DummyPlayerService only comes "up" as dependency,
|
||||
} // but doesn't start as a subsystem on it's own.
|
||||
|
||||
bool
|
||||
start (lumiera::Option&, Subsys::SigTerm terminationHandle)
|
||||
{
|
||||
ASSERT (!thePlayer_);
|
||||
|
||||
thePlayer_.reset (new DummyPlayerService (terminationHandle));
|
||||
return true;
|
||||
}
|
||||
|
||||
/** manages the actual (single) instance of the player service impl */
|
||||
scoped_ptr<DummyPlayerService> thePlayer_;
|
||||
|
||||
|
||||
void
|
||||
triggerShutdown () throw()
|
||||
{
|
||||
thePlayer_.reset(0);
|
||||
// note: shutdown of the DummyPlayerService instance may block
|
||||
// for a short period, until termination of all tick services
|
||||
}
|
||||
|
||||
bool
|
||||
checkRunningState () throw()
|
||||
{
|
||||
return (thePlayer_);
|
||||
}
|
||||
};
|
||||
|
||||
lib::Singleton<DummyPlayerSubsysDescriptor> theDummyPlayerDescriptor;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* ================== define an lumieraorg_DummyPlayer instance ======================= */
|
||||
|
||||
LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0
|
||||
,lumieraorg_DummyPlayerFacade_descriptor
|
||||
, NULL, NULL, NULL
|
||||
, LUMIERA_INTERFACE_INLINE (name, "\305\162\202\240\075\316\146\100\314\152\075\343\372\065\226\307",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "DummyPlayer"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (brief, "\317\045\366\076\064\072\156\274\220\346\262\207\062\367\057\232",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "Proc Interface: dummy player to test integration with the GUI"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (homepage, "\136\225\033\362\161\251\300\256\117\072\171\102\235\004\235\200",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "http://www.lumiera.org/develompent.html" ;}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (version, "\212\146\344\127\124\116\101\205\211\174\322\241\162\122\023\165",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "0.1~pre"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (author, "\064\226\072\300\054\345\042\357\337\226\155\025\306\051\117\105",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "Hermann Vosseler"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (email, "\041\075\220\112\246\304\261\135\003\135\060\202\230\327\303\206",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "Ichthyostega@web.de"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (copyright, "\232\305\163\271\174\025\270\075\012\201\331\256\327\375\066\210",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{
|
||||
(void)ifa;
|
||||
return
|
||||
"Copyright (C) Lumiera.org\n"
|
||||
" 2009 Hermann Vosseler <Ichthyostega@web.de>";
|
||||
}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (license, "\136\136\073\173\145\357\151\062\040\013\323\272\051\352\305\060",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{
|
||||
(void)ifa;
|
||||
return
|
||||
"This program is free software; you can redistribute it and/or modify\n"
|
||||
"it under the terms of the GNU General Public License as published by\n"
|
||||
"the Free Software Foundation; either version 2 of the License, or\n"
|
||||
"(at your option) any later version.\n"
|
||||
"\n"
|
||||
"This program is distributed in the hope that it will be useful,\n"
|
||||
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
|
||||
"GNU General Public License for more details.\n"
|
||||
"\n"
|
||||
"You should have received a copy of the GNU General Public License\n"
|
||||
"along with this program; if not, write to the Free Software\n"
|
||||
"Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA";
|
||||
}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (state, "\224\251\004\001\165\140\116\246\126\311\115\234\023\026\331\350",
|
||||
int, (LumieraInterface ifa),
|
||||
{(void)ifa; return LUMIERA_INTERFACE_EXPERIMENTAL; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (versioncmp, "\267\155\303\046\353\222\323\014\145\027\043\100\370\311\257\126",
|
||||
int, (const char* a, const char* b),
|
||||
{return 0;} ////////////////////////////////////////////TODO define version ordering
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
using lumiera::facade::LUMIERA_ERROR_FACADE_LIFECYCLE;
|
||||
typedef lib::SingletonRef<DummyPlayerService>::Accessor InstanceRef;
|
||||
|
||||
InstanceRef _instance; ///< a backdoor for the C Language impl to access the actual DummyPlayer implementation...
|
||||
|
||||
typedef ProcessImpl* ProcP;
|
||||
|
||||
|
||||
LUMIERA_INTERFACE_INSTANCE (lumieraorg_DummyPlayer, 0
|
||||
,lumieraorg_DummyPlayerService
|
||||
, LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_DummyPlayerFacade_descriptor)
|
||||
, NULL /* on open */
|
||||
, NULL /* on close */
|
||||
, LUMIERA_INTERFACE_INLINE (startPlay, "\143\323\102\155\051\006\235\004\037\310\354\121\176\142\342\210",
|
||||
LumieraPlayProcess, (LumieraDisplaySlot viewerHandle),
|
||||
{
|
||||
if (!_instance)
|
||||
{
|
||||
lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return static_cast<LumieraPlayProcess> (_instance->start(viewerHandle));
|
||||
}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (togglePlay, "\275\157\316\220\210\053\226\134\057\016\273\265\240\053\112\307",
|
||||
void, (LumieraPlayProcess handle, bool doPlay),
|
||||
{
|
||||
if (!_instance)
|
||||
{
|
||||
lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
REQUIRE (handle);
|
||||
ProcP proc = static_cast<ProcP> (handle);
|
||||
|
||||
proc->doPlay(doPlay);
|
||||
}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (terminate, "\005\265\115\021\076\143\010\215\373\252\370\174\235\136\340\004",
|
||||
void, (LumieraPlayProcess handle),
|
||||
{
|
||||
if (!_instance)
|
||||
{
|
||||
lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
REQUIRE (handle);
|
||||
ProcP proc = static_cast<ProcP> (handle);
|
||||
|
||||
ProcessImpl::terminate (proc);
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
} // (End) hidden service impl details
|
||||
|
||||
|
||||
|
||||
|
||||
DummyPlayerService::DummyPlayerService (Subsys::SigTerm terminationHandle)
|
||||
: error_("")
|
||||
, notifyTermination_(terminationHandle)
|
||||
, implInstance_(this,_instance)
|
||||
, serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_DummyPlayer, 0, lumieraorg_DummyPlayerService))
|
||||
{
|
||||
INFO (progress, "DummyPlayer Facade opened.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** @par implementation note
|
||||
* A new process (implementation) is created, configured
|
||||
* and started here. This may include spawning a thread or
|
||||
* allocating a timer. The newly created process is self-contained
|
||||
* and will be just handed out, without caring for its lifecycle.
|
||||
* If client code accesses this function via the plain C interface,
|
||||
* the client is responsible for terminating this process, whereas
|
||||
* when using the C++ interface, you'll get a Handle object which
|
||||
* manages the lifecycle automatically.
|
||||
*/
|
||||
ProcessImpl*
|
||||
DummyPlayerService::start (LumieraDisplaySlot viewerHandle)
|
||||
{
|
||||
auto_ptr<ProcessImpl> newProcess (new ProcessImpl (viewerHandle));
|
||||
|
||||
REQUIRE (!newProcess->isActive());
|
||||
newProcess->setRate(25);
|
||||
|
||||
return newProcess.release();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* === Process Implementation === */
|
||||
|
||||
|
||||
ProcessImpl::ProcessImpl(LumieraDisplaySlot viewerHandle)
|
||||
: fps_(0)
|
||||
, play_(false)
|
||||
, display_(Display::facade().getHandle (viewerHandle))
|
||||
, imageGen_(0)
|
||||
, tick_(new TickService (bind (&ProcessImpl::doFrame, this)))
|
||||
{ }
|
||||
|
||||
|
||||
ProcessImpl::~ProcessImpl()
|
||||
{
|
||||
INFO (proc_dbg, "Playback process halted...");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ProcessImpl::terminate (ProcessImpl* process) ///< deleter function for lib::Handle
|
||||
{
|
||||
if (process)
|
||||
delete process;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DummyPlayer::Process
|
||||
ProcessImpl::createHandle()
|
||||
{
|
||||
DummyPlayer::Process handle;
|
||||
handle.activate(this, &terminate); // note the deleter function...
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ProcessImpl::setRate (uint fps)
|
||||
{
|
||||
REQUIRE (fps==0 || fps_==0 );
|
||||
REQUIRE (fps==0 || !play_ );
|
||||
REQUIRE (tick_);
|
||||
|
||||
fps_ = fps;
|
||||
play_ = (fps != 0);
|
||||
|
||||
if (play_)
|
||||
imageGen_.reset(new DummyImageGenerator(fps));
|
||||
|
||||
// callbacks with given frequency, starting now
|
||||
tick_->activate(fps);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ProcessImpl::doPlay(bool yes)
|
||||
{
|
||||
REQUIRE (isActive());
|
||||
tick_->activate (yes? fps_:0);
|
||||
play_ = yes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ProcessImpl::doFrame()
|
||||
{
|
||||
REQUIRE (isActive());
|
||||
ASSERT (imageGen_);
|
||||
|
||||
if (play_)
|
||||
display_(imageGen_->next());
|
||||
else
|
||||
display_(imageGen_->current());
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace play
|
||||
|
||||
} // namespace proc
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace lumiera { /* === Forwarding function(s) on the Process handle === */
|
||||
|
||||
void DummyPlayer::Process::play(bool yes) { impl().doPlay(yes); }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** @internal intended for use by main(). */
|
||||
lumiera::Subsys&
|
||||
DummyPlayer::getDescriptor()
|
||||
{
|
||||
return proc::play::theDummyPlayerDescriptor();
|
||||
}
|
||||
|
||||
// emit the vtable here into this translation unit within liblumieraproc.so ...
|
||||
DummyPlayer::~DummyPlayer() { }
|
||||
|
||||
|
||||
} // namespace lumiera
|
||||
161
src/proc/play/play-service.hpp
Normal file
161
src/proc/play/play-service.hpp
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
DUMMY-PLAYER-SERVICE.hpp - service implementing a dummy test player
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2009, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
/** @file dummy-player-service.hpp
|
||||
** A public service provided by the Proc-Layer, implementing a dummy/mockup playback process.
|
||||
** This is a design sketch; Lumiera isn't able to generate rendered output as of 2/2009. The
|
||||
** idea is, that for each ongoing calculation process, there is a ProcessImpl instance holding
|
||||
** the necessary handles and allocations and providing an uniform API to the client side.
|
||||
** Especially, this ProcessImpl holds a TickService, which generates periodic callbacks, and
|
||||
** it uses an output handle (functor) to push the generated frames up.
|
||||
**
|
||||
** This service is the implementation of a layer separation facade interface. Clients should use
|
||||
** proc::play::DummyPlayer#facade to access this service. This header defines the interface used
|
||||
** to \em provide this service, not to access it.
|
||||
**
|
||||
** @see lumiera::DummyPlayer
|
||||
** @see gui::PlaybackController usage example
|
||||
*/
|
||||
|
||||
|
||||
#ifndef PROC_DUMMYPLAYER_SERVICE_H
|
||||
#define PROC_DUMMYPLAYER_SERVICE_H
|
||||
|
||||
|
||||
#include "include/dummy-player-facade.h"
|
||||
#include "include/display-facade.h"
|
||||
#include "common/instancehandle.hpp"
|
||||
#include "lib/singleton-ref.hpp"
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace proc {
|
||||
namespace play {
|
||||
|
||||
using std::string;
|
||||
using lumiera::Subsys;
|
||||
using lumiera::Display;
|
||||
using lumiera::DummyPlayer;
|
||||
|
||||
|
||||
class DummyImageGenerator;
|
||||
class TickService;
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Actual implementation of a single (dummy) playback process.
|
||||
* The DummyPlayerService (see below) maintains a collection of such
|
||||
* actively running playback processes, while the client code gets
|
||||
* DummyPlayer::Process handles to track any ongoing use. Users of
|
||||
* the plain C interface get a direct bare pointer to the respective
|
||||
* ProcessImpl instance and have to manage the lifecycle manually.
|
||||
*/
|
||||
class ProcessImpl
|
||||
: public lumiera_playprocess,
|
||||
boost::noncopyable
|
||||
{
|
||||
uint fps_;
|
||||
bool play_;
|
||||
|
||||
Display::Sink display_;
|
||||
boost::scoped_ptr<DummyImageGenerator> imageGen_;
|
||||
boost::scoped_ptr<TickService> tick_;
|
||||
|
||||
|
||||
public:
|
||||
ProcessImpl(LumieraDisplaySlot) ;
|
||||
~ProcessImpl() ;
|
||||
|
||||
|
||||
/* Implementation-level API */
|
||||
|
||||
/** activate a playback process
|
||||
* with given specification */
|
||||
void setRate (uint fps);
|
||||
|
||||
bool isActive () { return fps_ != 0; }
|
||||
bool isPlaying() { return play_; }
|
||||
|
||||
void doPlay(bool yes);
|
||||
|
||||
|
||||
/* Lifecycle */
|
||||
|
||||
DummyPlayer::Process createHandle();
|
||||
static void terminate(ProcessImpl* process);
|
||||
|
||||
private:
|
||||
void doFrame (); ///< periodically invoked while playing
|
||||
};
|
||||
|
||||
|
||||
|
||||
/******************************************************
|
||||
* Actual implementation of the DummyPlayer service.
|
||||
* Creating an instance of this class automatically
|
||||
* registers the interface lumieraorg_DummyPlayer with
|
||||
* the Lumiera Interface/Plugin system and creates
|
||||
* a forwarding proxy within the application core to
|
||||
* route calls through this interface.
|
||||
*/
|
||||
class DummyPlayerService
|
||||
: boost::noncopyable
|
||||
{
|
||||
|
||||
string error_;
|
||||
Subsys::SigTerm notifyTermination_;
|
||||
|
||||
|
||||
/* === Interface Lifecycle === */
|
||||
|
||||
typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_DummyPlayer, 0)
|
||||
, DummyPlayer
|
||||
> ServiceInstanceHandle;
|
||||
|
||||
lib::SingletonRef<DummyPlayerService> implInstance_;
|
||||
ServiceInstanceHandle serviceInstance_;
|
||||
|
||||
public:
|
||||
DummyPlayerService(Subsys::SigTerm terminationHandle);
|
||||
|
||||
~DummyPlayerService() { notifyTermination_(&error_); }
|
||||
|
||||
|
||||
|
||||
/** conceptually, this serves as implementation
|
||||
* of the DummyPlayer#start() function. But because
|
||||
* this function sits \em behind the interface, it
|
||||
* just returns an impl pointer. */
|
||||
ProcessImpl* start (LumieraDisplaySlot viewerHandle);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace play
|
||||
|
||||
} // namespace proc
|
||||
#endif
|
||||
252
src/proc/play/sound/jack-output.cpp
Normal file
252
src/proc/play/sound/jack-output.cpp
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
DisplayService - service providing access to a display for outputting frames
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2009, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
* *****************************************************/
|
||||
|
||||
|
||||
#include "gui/display-service.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "common/interfacedescriptor.h"
|
||||
}
|
||||
|
||||
|
||||
namespace gui {
|
||||
|
||||
|
||||
|
||||
namespace { // hidden local details of the service implementation....
|
||||
|
||||
|
||||
|
||||
/* ================== define an lumieraorg_Display instance ======================= */
|
||||
|
||||
LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0
|
||||
,lumieraorg_DisplayFacade_descriptor
|
||||
, NULL, NULL, NULL
|
||||
, LUMIERA_INTERFACE_INLINE (name, "\323\343\324\023\064\216\120\201\073\056\366\020\110\263\060\023",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "Display"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (brief, "\305\026\070\133\033\357\014\202\203\270\174\072\341\256\226\235",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "UI Interface: service for outputting frames to a viewer or display"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (homepage, "\170\104\246\175\123\144\332\312\315\263\071\170\164\213\024\275",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "http://www.lumiera.org/develompent.html" ;}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (version, "\265\343\045\346\110\241\276\111\217\120\155\246\230\341\344\124",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "0.1~pre"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (author, "\302\027\122\045\301\166\046\236\257\253\144\035\105\166\070\103",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "Hermann Vosseler"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (email, "\074\013\020\161\075\135\302\265\260\000\301\147\116\355\035\261",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{ (void)ifa; return "Ichthyostega@web.de"; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (copyright, "\037\232\153\100\114\103\074\342\164\132\370\210\372\164\115\275",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{
|
||||
(void)ifa;
|
||||
return
|
||||
"Copyright (C) Lumiera.org\n"
|
||||
" 2009 Hermann Vosseler <Ichthyostega@web.de>";
|
||||
}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (license, "\026\243\334\056\125\245\315\311\155\375\262\344\007\076\341\254",
|
||||
const char*, (LumieraInterface ifa),
|
||||
{
|
||||
(void)ifa;
|
||||
return
|
||||
"This program is free software; you can redistribute it and/or modify\n"
|
||||
"it under the terms of the GNU General Public License as published by\n"
|
||||
"the Free Software Foundation; either version 2 of the License, or\n"
|
||||
"(at your option) any later version.\n"
|
||||
"\n"
|
||||
"This program is distributed in the hope that it will be useful,\n"
|
||||
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
|
||||
"GNU General Public License for more details.\n"
|
||||
"\n"
|
||||
"You should have received a copy of the GNU General Public License\n"
|
||||
"along with this program; if not, write to the Free Software\n"
|
||||
"Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA";
|
||||
}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (state, "\243\302\332\160\060\272\155\334\212\256\303\141\160\063\164\154",
|
||||
int, (LumieraInterface ifa),
|
||||
{(void)ifa; return LUMIERA_INTERFACE_EXPERIMENTAL; }
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (versioncmp, "\363\125\123\060\231\147\053\017\131\341\105\157\231\273\334\136",
|
||||
int, (const char* a, const char* b),
|
||||
{return 0;} ////////////////////////////////////////////TODO define version ordering
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
using lumiera::facade::LUMIERA_ERROR_FACADE_LIFECYCLE;
|
||||
typedef lib::SingletonRef<DisplayService>::Accessor InstanceRef;
|
||||
|
||||
InstanceRef _instance; ///< a backdoor for the C Language impl to access the actual DisplayService implementation...
|
||||
|
||||
|
||||
|
||||
LUMIERA_INTERFACE_INSTANCE (lumieraorg_Display, 0
|
||||
,lumieraorg_DisplayService
|
||||
, LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_DisplayFacade_descriptor)
|
||||
, NULL /* on open */
|
||||
, NULL /* on close */
|
||||
, LUMIERA_INTERFACE_INLINE (allocate, "\177\221\146\253\255\161\160\137\015\005\263\362\307\022\243\365",
|
||||
void, (LumieraDisplaySlot slotHandle),
|
||||
{
|
||||
if (!_instance)
|
||||
{
|
||||
lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
REQUIRE (slotHandle);
|
||||
try
|
||||
{
|
||||
_instance->allocate (slotHandle,true);
|
||||
}
|
||||
catch (lumiera::Error&){ /* error state remains set */ }
|
||||
}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (release, "\166\374\106\313\011\142\115\161\111\110\376\016\346\115\240\364",
|
||||
void, (LumieraDisplaySlot slotHandle),
|
||||
{
|
||||
if (!_instance)
|
||||
{
|
||||
lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
REQUIRE (slotHandle);
|
||||
_instance->allocate (slotHandle,false);
|
||||
}
|
||||
)
|
||||
, LUMIERA_INTERFACE_INLINE (put, "\340\062\234\227\152\131\370\272\146\207\224\015\361\070\252\135",
|
||||
void, (LumieraDisplaySlot slotHandle, LumieraDisplayFrame frame),
|
||||
{
|
||||
//skipping full checks for performance reasons
|
||||
REQUIRE (_instance && !lumiera_error_peek());
|
||||
|
||||
REQUIRE (slotHandle);
|
||||
DisplayerSlot& slot = _instance->resolve (slotHandle);
|
||||
slot.put (frame);
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
} // (End) hidden service impl details
|
||||
|
||||
|
||||
|
||||
|
||||
DisplayService::DisplayService()
|
||||
: error_("")
|
||||
, implInstance_(this,_instance)
|
||||
, serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_Display, 0, lumieraorg_DisplayService))
|
||||
{
|
||||
INFO (progress, "Display Facade opened.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
LumieraDisplaySlot
|
||||
DisplayService::setUp (FrameDestination const& outputDestination)
|
||||
{
|
||||
DisplayerTab& slots (_instance->slots_);
|
||||
return &slots.manage (new DisplayerSlot (outputDestination));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
DisplayService::allocate (LumieraDisplaySlot handle, bool doAllocate)
|
||||
{
|
||||
REQUIRE (handle);
|
||||
if (doAllocate)
|
||||
{
|
||||
if (handle->put_)
|
||||
throw lumiera::error::Logic("slot already allocated for output");
|
||||
else
|
||||
// Mark the handle as "allocated" and ready for output:
|
||||
// Place the function pointer from the C interface into the handle struct.
|
||||
// calling it will invoke the implementing instance's "put" function
|
||||
// (see the LUMIERA_INTERFACE_INLINE above in this file!)
|
||||
handle->put_ = serviceInstance_.get().put;
|
||||
}
|
||||
else
|
||||
handle->put_ = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DisplayerSlot&
|
||||
DisplayService::resolve (LumieraDisplaySlot handle)
|
||||
{
|
||||
REQUIRE (handle);
|
||||
REQUIRE (handle->put_, "accessing a DisplayerSlot, which hasn't been locked for output");
|
||||
|
||||
return *static_cast<DisplayerSlot*> (handle);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* === DisplayerSlot Implementation === */
|
||||
|
||||
|
||||
DisplayerSlot::DisplayerSlot (FrameDestination const& outputDestination)
|
||||
: currBuffer_(0)
|
||||
{
|
||||
put_ = 0; // mark as not allocated
|
||||
hasFrame_.connect (outputDestination);
|
||||
dispatcher_.connect (sigc::mem_fun (this, &DisplayerSlot::displayCurrentFrame));
|
||||
}
|
||||
|
||||
|
||||
DisplayerSlot::~DisplayerSlot()
|
||||
{
|
||||
TRACE (gui_dbg, "Displayer Slot closing...");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DisplayerSlot::displayCurrentFrame()
|
||||
{
|
||||
hasFrame_.emit (currBuffer_);
|
||||
}
|
||||
|
||||
|
||||
} // namespace proc
|
||||
190
src/proc/play/sound/jack-output.hpp
Normal file
190
src/proc/play/sound/jack-output.hpp
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
DISPLAY-SERVICE.hpp - service providing access to a display for outputting frames
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2009, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
/** @file display-service.hpp
|
||||
** A public service provided by the GUI, implementing the lumiera::Display facade interface.
|
||||
** It serves two purposes:
|
||||
** - It maintains a collection of DisplayerSlot objects, which are the actual connection points
|
||||
** and allow to receive frames and dispatch them to the GTK main event loop thread.
|
||||
** Conceptually, creating such a slot means providing a possible display for output.
|
||||
** - It provides the actual implementation of the Display facade interface, i.e. the function
|
||||
** which is to invoked periodically by the playback processes to dispose a new frame into
|
||||
** the display.
|
||||
**
|
||||
** This service is the implementation of a layer separation facade interface. This header defines
|
||||
** the interface used to \em provide this service, not to access it. Clients get a specific
|
||||
** LumieraDisplaySlot passed as parameter when initiating a playback process from the GUI. Using
|
||||
** this LumieraDisplaySlot handle, clients should then use lumiera::DummyPlayer#facade to access
|
||||
** an implementation instance of this service in order to push actual frames up.
|
||||
**
|
||||
** @see lumiera::Display
|
||||
** @see lumiera::DummyPlayer
|
||||
** @see gui::PlaybackController usage example
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GUI_DISPLAY_SERVICE_H
|
||||
#define GUI_DISPLAY_SERVICE_H
|
||||
|
||||
|
||||
#include "include/display-facade.h"
|
||||
#include "common/instancehandle.hpp"
|
||||
#include "lib/singleton-ref.hpp"
|
||||
#include "lib/scoped-ptrvect.hpp"
|
||||
|
||||
#include <glibmm.h>
|
||||
#include <sigc++/sigc++.h>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace gui {
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using lumiera::Display;
|
||||
using Glib::Dispatcher;
|
||||
|
||||
|
||||
typedef sigc::slot<void, void*> FrameDestination;
|
||||
typedef sigc::signal<void, void*> FrameSignal;
|
||||
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Actual implementation of a single displayer slot. Internally,
|
||||
* it is connected via the Glib::Dispatcher for outputting frames
|
||||
* to a viewer widget, which executes within the GTK event thread.
|
||||
* @note must be created from the GTK event thread.
|
||||
*/
|
||||
class DisplayerSlot
|
||||
: public lumiera_displaySlot,
|
||||
boost::noncopyable
|
||||
{
|
||||
Dispatcher dispatcher_;
|
||||
FrameSignal hasFrame_;
|
||||
|
||||
LumieraDisplayFrame currBuffer_;
|
||||
|
||||
|
||||
public:
|
||||
DisplayerSlot (FrameDestination const&) ;
|
||||
~DisplayerSlot () ;
|
||||
|
||||
/* Implementation-level API to be used by DisplayService */
|
||||
|
||||
/** receive a frame to be displayed */
|
||||
inline void put (LumieraDisplayFrame);
|
||||
|
||||
|
||||
private:
|
||||
/** internal: activated via Dispatcher
|
||||
* and running in GTK main thread */
|
||||
void displayCurrentFrame();
|
||||
|
||||
};
|
||||
|
||||
typedef lib::ScopedPtrVect<DisplayerSlot> DisplayerTab;
|
||||
|
||||
|
||||
|
||||
/******************************************************
|
||||
* Actual implementation of the DisplayService.
|
||||
* Creating an instance of this class automatically
|
||||
* registers the interface lumieraorg_Display with
|
||||
* the Lumiera Interface/Plugin system and creates
|
||||
* a forwarding proxy within the application core to
|
||||
* route calls through this interface.
|
||||
* \par
|
||||
* In addition to the Display interface, this class
|
||||
* implements an additional service for the GUI,
|
||||
* allowing actually to set up display slots, which
|
||||
* then can be handed out to client code in the
|
||||
* course of the play process for outputting frames.
|
||||
*/
|
||||
class DisplayService
|
||||
: boost::noncopyable
|
||||
{
|
||||
|
||||
string error_;
|
||||
DisplayerTab slots_;
|
||||
|
||||
|
||||
/* === Interface Lifecycle === */
|
||||
|
||||
typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_Display, 0)
|
||||
, lumiera::Display
|
||||
> ServiceInstanceHandle;
|
||||
|
||||
lib::SingletonRef<DisplayService> implInstance_;
|
||||
ServiceInstanceHandle serviceInstance_;
|
||||
|
||||
|
||||
public:
|
||||
DisplayService();
|
||||
~DisplayService() {
|
||||
INFO (proc_dbg, "Display service dying...");
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** open a new display, sending frames to the given output destination
|
||||
* @return handle for this slot, can be used to start a play process.
|
||||
* NULL handle in case of any error. */
|
||||
static LumieraDisplaySlot setUp (FrameDestination const&);
|
||||
|
||||
|
||||
/** prepare and the given slot for output
|
||||
* @param doAllocate allocate when true, else release it
|
||||
* @throw lumiera::error::Logic when already in use */
|
||||
void allocate (LumieraDisplaySlot, bool doAllocate);
|
||||
|
||||
|
||||
/** resolve the given display slot handle to yield a ref
|
||||
* to an actual implementation object. In order to be resolvable,
|
||||
* the DisplayerSlot needs to be locked (=allocated) for output use. */
|
||||
DisplayerSlot& resolve (LumieraDisplaySlot);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
DisplayerSlot::put(LumieraDisplayFrame newFrame)
|
||||
{
|
||||
if (newFrame != currBuffer_)
|
||||
{
|
||||
currBuffer_ = newFrame;
|
||||
dispatcher_.emit();
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE (render, "frame dropped?");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace gui
|
||||
#endif
|
||||
Loading…
Reference in a new issue