WIP create (planned) new entities for the player subsystem

This commit is contained in:
Fischlurch 2011-05-23 04:43:56 +02:00
parent ebd6cfca82
commit 899ffa60ca
23 changed files with 3636 additions and 0 deletions

View 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

View 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
View 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
View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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