detailed planning how to build the player subsystem

key idea is to grow and rework the design of the
DummyPlayer to yield the full featured Player
This commit is contained in:
Fischlurch 2011-05-23 05:46:40 +02:00
parent 899ffa60ca
commit cb6453afe1
24 changed files with 472 additions and 2665 deletions

View file

@ -1,8 +1,8 @@
/*
RenderEngine - a complete network of processing nodes usable for rendering
SchedulerFrontend - access point to the scheduler within the renderengine
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
2011, 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
@ -21,8 +21,9 @@
* *****************************************************/
#include "proc/engine/renderengine.hpp"
#include "backend/engine/scheduler-frontend.hpp"
namespace backend{
namespace engine {
@ -30,4 +31,4 @@ namespace engine {
} // namespace engine
}} // namespace backend::engine

View file

@ -1,8 +1,8 @@
/*
RENDERENGINE.hpp - a complete network of processing nodes usable for rendering
SCHEDULER-FRONTEND.hpp - access point to the scheduler within the renderengine
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
2011, 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
@ -21,17 +21,15 @@
*/
#ifndef ENGINE_RENDERENGINE_H
#define ENGINE_RENDERENGINE_H
#include <list>
#include "proc/engine/rendergraph.hpp"
#ifndef BACKEND_ENGINE_SCHEDULER_FRONTEND_H
#define BACKEND_ENGINE_SCHEDULER_FRONTEND_H
using std::list;
//using std::list;
namespace backend{
namespace engine {
@ -42,7 +40,7 @@ namespace engine {
* render operations are mostly implemented by the backend
* ////////TODO WIP as of 12/2010
*/
class RenderEngine : public RenderGraph
class SchedulerFrontend
{
public:
///// TODO: find out about the public operations
@ -50,9 +48,8 @@ namespace engine {
// but is a subsystem separate of the sesison.
private:
list<RenderGraph> renderSegments;
};
} // namespace engine
}} // namespace backend::engine
#endif

View file

@ -1,8 +1,8 @@
/*
Timeline - independent top-level element of the Session
Viewer - asset corresponding to a viewer element in the GUI
Copyright (C) Lumiera.org
2009, Hermann Vosseler <Ichthyostega@web.de>
2011, 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
@ -21,17 +21,17 @@
* *****************************************************/
#include "proc/asset/timeline.hpp"
#include "proc/asset/viewer.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"
//#include "proc/mobject/session/binding.hpp"
//#include "proc/assetmanager.hpp"
namespace asset {
using lib::AutoRegistered;
// using lib::AutoRegistered;

View file

@ -1,8 +1,8 @@
/*
TIMELINE.hpp - independent top-level element of the Session
VIEWER.hpp - asset corresponding to a viewer element in the GUI
Copyright (C) Lumiera.org
2009, Hermann Vosseler <Ichthyostega@web.de>
2011, 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
@ -21,25 +21,8 @@
*/
/** @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:
/** @file viewer.hpp
** structural element within the session.
** \c "timeline(theTimelineName),bindSequence(theTimelineName,sequenceID)."
**
** @see Session
@ -49,8 +32,8 @@
*/
#ifndef ASSET_TIMELINE_H
#define ASSET_TIMELINE_H
#ifndef ASSET_VIEWER_H
#define ASSET_VIEWER_H
#include "proc/asset/struct.hpp"
//#include "proc/mobject/mobject.hpp"

View file

@ -1,8 +1,8 @@
/*
RenderGraph - render network corresponding to one segment of the timeline
Dispatcher - translating calculation streams into frame jobs
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
2011, 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
@ -21,15 +21,10 @@
* *****************************************************/
#include "proc/engine/rendergraph.hpp"
#include "lib/frameid.hpp"
#include "proc/state.hpp"
#include "proc/engine/dispatcher.hpp"
//#include "lib/frameid.hpp"
//#include "proc/state.hpp"
namespace lumiera {
/** storage for the unique node-ID counter */
ulong NodeID::currID (0);
}
namespace engine {

View file

@ -1,8 +1,8 @@
/*
RENDERGRAPH.hpp - render network corresponding to one segment of the timeline
DISPATCHER.hpp - translating calculation streams into frame jobs
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
2011, 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
@ -21,8 +21,8 @@
*/
#ifndef ENGINE_RENDERGRAPH_H
#define ENGINE_RENDERGRAPH_H
#ifndef PROC_ENGINE_DISPATCHER_H
#define PROC_ENGINE_DISPATCHER_H
#include "proc/common.hpp"
#include "proc/state.hpp"
@ -32,28 +32,26 @@
namespace engine {
using lib::time::TimeSpan;
using lib::time::FSecs;
using lib::time::Time;
class ExitNode;
// 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
* @todo
*/
class RenderGraph
class Dispatcher
{
protected:
ExitNode * output;
/** timerange covered by this RenderGraph */
TimeSpan segment_;
public:
RenderGraph()
Dispatcher()
: segment_(Time::ZERO, FSecs(5))
{
UNIMPLEMENTED ("anything regarding the Fixture datastructure");
UNIMPLEMENTED ("anything regarding the Engine backbone");
}
};

View file

@ -1,8 +1,8 @@
/*
DummyPlayerService - access point and service implementing a dummy test player
EngineService - primary service access point for using the renderengine
Copyright (C) Lumiera.org
2009, Hermann Vosseler <Ichthyostega@web.de>
2011, 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
@ -21,362 +21,33 @@
* *****************************************************/
#include "proc/play/dummy-player-service.hpp"
#include "proc/play/dummy-image-generator.hpp"
#include "proc/play/tick-service.hpp"
#include "lib/singleton.hpp"
#include "proc/engine/engine-service.hpp"
extern "C" {
#include "common/interfacedescriptor.h"
}
#include <string>
#include <memory>
#include <tr1/functional>
#include <boost/scoped_ptr.hpp>
//#include <string>
//#include <memory>
//#include <tr1/functional>
//#include <boost/scoped_ptr.hpp>
namespace proc {
namespace play{
namespace engine{
using std::string;
using lumiera::Subsys;
using std::auto_ptr;
using boost::scoped_ptr;
using std::tr1::bind;
// 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
}} // namespace proc::engine

View file

@ -1,8 +1,8 @@
/*
DUMMY-PLAYER-SERVICE.hpp - service implementing a dummy test player
ENGINE-SERVICE.hpp - primary service access point for using the renderengine
Copyright (C) Lumiera.org
2009, Hermann Vosseler <Ichthyostega@web.de>
2011, 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
@ -20,142 +20,83 @@
*/
/** @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.
/** @file engine-service.hpp
** A public service provided by
**
** @see lumiera::DummyPlayer
** @see gui::PlaybackController usage example
*/
#ifndef PROC_DUMMYPLAYER_SERVICE_H
#define PROC_DUMMYPLAYER_SERVICE_H
#ifndef PROC_ENGINE_ENGINE_SERVICE_H
#define PROC_ENGINE_ENGINE_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>
//#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 play {
// using std::string;
// using lumiera::Subsys;
// using lumiera::Display;
// using lumiera::DummyPlayer;
/******************************************************
* 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 EngineService
: 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

@ -30,7 +30,7 @@
** and specific segments of the fixture.
** Together, these allow to identify those ongoing processes which need to be cancelled
** or restarted, because their results might be tainted by the changes induced by the
** build process. Typically, these detection process runs just before commiting the
** build process. Typically, these detection process runs just before committing the
** newly built fixture datastructure.
**
** @todo WIP-WIP-WIP as of 12/2010

View file

@ -46,7 +46,7 @@ namespace mobject {
/**
* Descriptor to denote the desired target of produced media data.
* OutputDesignation is always an internal and relative specification
* and boils down to referring an asset::Pipe by ID. In order to get
* and boils down to referring an asset::Pipe by ID. In order to become
* actually effective, some object within the model additionally
* needs to \em claim this pipe-ID, meaning that this object
* states to root and represent this pipe. When the builder
@ -54,7 +54,7 @@ namespace mobject {
* an actual stream connection will be wired in the
* processing node network.
*
* @todo couldn't the inline buffer be "downgraded" to InPlaceBuffer ??
* @todo couldn't the inline buffer be "downgraded" to InPlaceBuffer or PolymorphicValue??
* Seemingly we never-ever need to re-discover the erased type of the embedded spec.
* Thus for this to work, we'd just need to add an "empty" spec ///////////////////TICKET #723
*/

View file

@ -1,8 +1,8 @@
/*
Clip - a Media Clip
GeneratorMO - a (Test)data generator
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
2011, 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
@ -21,15 +21,15 @@
* *****************************************************/
#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"
#include "proc/mobject/session/generator-mo.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;
//using lib::time::Mutation;
//using util::isnil;
namespace mobject {
namespace session {
@ -37,47 +37,6 @@ 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_);
}

View file

@ -1,8 +1,8 @@
/*
CLIP.hpp - a Media Clip
GENERATOR-MO.hpp - a (Test)data generator
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
2011, 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
@ -21,8 +21,8 @@
*/
#ifndef MOBJECT_SESSION_CLIP_H
#define MOBJECT_SESSION_CLIP_H
#ifndef MOBJECT_SESSION_GENERATOR_MO_H
#define MOBJECT_SESSION_GENERATOR_MO_H
#include "proc/mobject/session/abstractmo.hpp"
#include "lib/time/timevalue.hpp"
@ -44,24 +44,15 @@ namespace session {
/**
* 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.
* A lksjaf
*/
class Clip
class GeneratorMO
: public AbstractMO
{
string
initShortID() const
{
return buildShortID("Clip");
return buildShortID("Generator");
}
void setupLength();
@ -79,24 +70,14 @@ namespace session {
account when breaking circular references.
*/
const Media & mediaDef_;
const asset::Clip & clipDef_;
Clip (const asset::Clip&, const Media&);
GeneratorMO ();
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);

View file

@ -1,8 +1,8 @@
/*
DummyPlayerService - access point and service implementing a dummy test player
DummyPlayConnection.hpp - simplified test setup for playback
Copyright (C) Lumiera.org
2009, Hermann Vosseler <Ichthyostega@web.de>
2011, 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
@ -21,362 +21,38 @@
* *****************************************************/
#include "proc/play/dummy-player-service.hpp"
#include "proc/play/dummy-image-generator.hpp"
#include "proc/play/tick-service.hpp"
#include "lib/singleton.hpp"
#include "proc/play/dummy-play-connection.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>
//#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;
// 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,69 @@
/*
DUMMY-PLAY-CONNECTION.hpp - simplified test setup for playback
Copyright (C) Lumiera.org
2011, 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-play-connection.hpp
** to \em provide this service, not to access it.
**
** @see lumiera::DummyPlayer
** @see gui::PlaybackController usage example
*/
#ifndef PROC_PLAY_DUMMY_PLAY_CONNECTION_H
#define PROC_PLAY_DUMMY_PLAY_CONNECTION_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 DummyPlayConnection
: boost::noncopyable
{
};
} // namespace play
} // namespace proc
#endif

View file

@ -1,8 +1,8 @@
/*
DisplayService - service providing access to a display for outputting frames
OutputManager - handling all the real external output connections
Copyright (C) Lumiera.org
2009, Hermann Vosseler <Ichthyostega@web.de>
2011, 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
@ -21,232 +21,23 @@
* *****************************************************/
#include "gui/display-service.hpp"
extern "C" {
#include "common/interfacedescriptor.h"
}
#include "play/output-manager.hpp"
namespace gui {
namespace play {
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.");
}
OutputSlot::~OutputSlot() { }
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
} // namespace play

View file

@ -1,8 +1,8 @@
/*
DISPLAY-SERVICE.hpp - service providing access to a display for outputting frames
OUTPUT-MANAGER.hpp - handling all the real external output connections
Copyright (C) Lumiera.org
2009, Hermann Vosseler <Ichthyostega@web.de>
2011, 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
@ -20,171 +20,65 @@
*/
/** @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.
/** @file output-manager.hpp
** A global service to handle all external output connections.
**
** @see lumiera::Display
** @see lumiera::DummyPlayer
** @see gui::PlaybackController usage example
** @see output-manager-test.cpp ////TODO
*/
#ifndef GUI_DISPLAY_SERVICE_H
#define GUI_DISPLAY_SERVICE_H
#ifndef PROC_PLAY_OUTPUT_MANAGER_H
#define PROC_PLAY_OUTPUT_MANAGER_H
#include "include/display-facade.h"
#include "common/instancehandle.hpp"
#include "lib/singleton-ref.hpp"
#include "lib/scoped-ptrvect.hpp"
#include "lib/error.hpp"
#include <glibmm.h>
#include <sigc++/sigc++.h>
#include <boost/noncopyable.hpp>
#include <string>
#include <vector>
//#include <string>
//#include <vector>
namespace gui {
namespace play {
using std::string;
using std::vector;
using lumiera::Display;
using Glib::Dispatcher;
//using std::string;
//using std::vector;
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.
* Interface: Generic output sink.
*
* @todo write type comment
*/
class DisplayerSlot
: public lumiera_displaySlot,
boost::noncopyable
class OutputSlot
: 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);
virtual ~OutputSlot();
private:
/** internal: activated via Dispatcher
* and running in GTK main thread */
void displayCurrentFrame();
};
typedef lib::ScopedPtrVect<DisplayerSlot> DisplayerTab;
//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.
* Management of external Output connections.
*
* @todo write Type comment
*/
class DisplayService
class OutputManager
: 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);
OutputManager() {}
};
void
DisplayerSlot::put(LumieraDisplayFrame newFrame)
{
if (newFrame != currBuffer_)
{
currBuffer_ = newFrame;
dispatcher_.emit();
}
else
{
TRACE (render, "frame dropped?");
}
}
} // namespace gui
} // namespace play
#endif

View file

@ -1,8 +1,8 @@
/*
DUMMY-PLAYER-SERVICE.hpp - service implementing a dummy test player
PLAY-CONTROLLER.hpp - frontend handle to control an play process
Copyright (C) Lumiera.org
2009, Hermann Vosseler <Ichthyostega@web.de>
2011, 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
@ -20,141 +20,49 @@
*/
/** @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.
/** @file play-controller.hpp
**
** @see lumiera::DummyPlayer
** @see gui::PlaybackController usage example
*/
#ifndef PROC_DUMMYPLAYER_SERVICE_H
#define PROC_DUMMYPLAYER_SERVICE_H
#ifndef PROC_PLAY_PLAY_CONTROLLER_H
#define PROC_PLAY_PLAY_CONTROLLER_H
#include "include/dummy-player-facade.h"
#include "include/display-facade.h"
#include "common/instancehandle.hpp"
#include "lib/singleton-ref.hpp"
#include "proc/play/play-service.hpp"
//#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>
//#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
class PlayController
: 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);
private:
};
} // namespace play
} // namespace proc

View file

@ -1,8 +1,8 @@
/*
DummyPlayerService - access point and service implementing a dummy test player
PlayProcess.hpp - state frame for an ongoing play/render process
Copyright (C) Lumiera.org
2009, Hermann Vosseler <Ichthyostega@web.de>
2011, 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
@ -21,212 +21,27 @@
* *****************************************************/
#include "proc/play/dummy-player-service.hpp"
#include "proc/play/dummy-image-generator.hpp"
#include "proc/play/tick-service.hpp"
#include "lib/singleton.hpp"
#include "proc/play/play-process.hpp"
extern "C" {
#include "common/interfacedescriptor.h"
}
#include <string>
#include <memory>
#include <tr1/functional>
#include <boost/scoped_ptr.hpp>
//#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;
// 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
@ -234,149 +49,7 @@ namespace proc {
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
}} // namespace proc::play

View file

@ -1,8 +1,8 @@
/*
DUMMY-PLAYER-SERVICE.hpp - service implementing a dummy test player
PLAY-PROCESS.hpp - state frame for an ongoing play/render process
Copyright (C) Lumiera.org
2009, Hermann Vosseler <Ichthyostega@web.de>
2011, 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
@ -20,95 +20,34 @@
*/
/** @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.
**
/** @file play-process.hpp
*
** @see lumiera::DummyPlayer
** @see gui::PlaybackController usage example
*/
#ifndef PROC_DUMMYPLAYER_SERVICE_H
#define PROC_DUMMYPLAYER_SERVICE_H
#ifndef PROC_PLAY_PLAY_PROCESS_H
#define PROC_PLAY_PLAY_PROCESS_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>
//#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
};
// using std::string;
// using lumiera::Subsys;
// using lumiera::Display;
// using lumiera::DummyPlayer;
@ -120,35 +59,11 @@ namespace proc {
* a forwarding proxy within the application core to
* route calls through this interface.
*/
class DummyPlayerService
class PlayerProcess
: 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);
};

View file

@ -1,8 +1,8 @@
/*
DummyPlayerService - access point and service implementing a dummy test player
PlayService - interface: render- and playback control
Copyright (C) Lumiera.org
2009, Hermann Vosseler <Ichthyostega@web.de>
2011, 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
@ -21,19 +21,14 @@
* *****************************************************/
#include "proc/play/dummy-player-service.hpp"
#include "proc/play/dummy-image-generator.hpp"
#include "proc/play/tick-service.hpp"
#include "proc/play/play-service.hpp"
#include "lib/singleton.hpp"
extern "C" {
#include "common/interfacedescriptor.h"
}
#include <string>
#include <memory>
#include <tr1/functional>
#include <boost/scoped_ptr.hpp>
//#include <memory>
//#include <tr1/functional>
//#include <boost/scoped_ptr.hpp>
@ -99,284 +94,13 @@ namespace proc {
/* ================== 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
}} // namespace proc::play

View file

@ -1,8 +1,8 @@
/*
DUMMY-PLAYER-SERVICE.hpp - service implementing a dummy test player
PLAY-SERVICE.hpp - interface: render- and playback control
Copyright (C) Lumiera.org
2009, Hermann Vosseler <Ichthyostega@web.de>
2011, 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
@ -20,35 +20,23 @@
*/
/** @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.
/** @file play-service.hpp
** Player subsystem......
**
** @see lumiera::DummyPlayer
** @see gui::PlaybackController usage example
*/
#ifndef PROC_DUMMYPLAYER_SERVICE_H
#define PROC_DUMMYPLAYER_SERVICE_H
#ifndef PROC_PLAY_PLAY_SERVICE_H
#define PROC_PLAY_PLAY_SERVICE_H
#include "include/dummy-player-facade.h"
#include "include/display-facade.h"
#include "common/instancehandle.hpp"
#include "lib/singleton-ref.hpp"
#include "lib/error.hpp"
#include <boost/noncopyable.hpp>
#include <boost/scoped_ptr.hpp>
#include <string>
//#include <boost/scoped_ptr.hpp>
//#include <string>
namespace proc {
@ -60,95 +48,22 @@ namespace proc {
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
};
// class DummyImageGenerator;
// class TickService;
/******************************************************
* 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.
* Interface: Player subsystem.
*/
class DummyPlayerService
class PlayService
: 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);
PlayService(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);
~PlayService() { notifyTermination_(&error_); }
};

View file

@ -1,8 +1,8 @@
/*
DisplayService - service providing access to a display for outputting frames
JackOutput - Jack audio connection client
Copyright (C) Lumiera.org
2009, Hermann Vosseler <Ichthyostega@web.de>
2011, 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
@ -21,232 +21,11 @@
* *****************************************************/
#include "gui/display-service.hpp"
extern "C" {
#include "common/interfacedescriptor.h"
}
namespace gui {
#include "proc/play/sound/jack-output.hpp"
namespace proc {
namespace play {
namespace sound {
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
}}} // namespace proc::play::sound

View file

@ -1,8 +1,8 @@
/*
DISPLAY-SERVICE.hpp - service providing access to a display for outputting frames
JACK-OUTPUT.hpp - Jack audio connection client
Copyright (C) Lumiera.org
2009, Hermann Vosseler <Ichthyostega@web.de>
2011, 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
@ -20,21 +20,7 @@
*/
/** @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.
/** @file jack-output.hpp
**
** @see lumiera::Display
** @see lumiera::DummyPlayer
@ -42,149 +28,26 @@
*/
#ifndef GUI_DISPLAY_SERVICE_H
#define GUI_DISPLAY_SERVICE_H
#ifndef PROC_PLAY_SOUND_JACK_OUTPUT_H
#define PROC_PLAY_SOUND_JACK_OUTPUT_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>
//#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;
namespace proc {
namespace play {
namespace sound {
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
}}} // namespace proc::play::sound
#endif

View file

@ -1632,25 +1632,35 @@ The main tool used to implement this separation is the [[Builder Pattern|http://
Another pertinent theme is to make the basic building blocks simpler, while on the other hand gaining much more flexibility for combining these building blocks. For example we try to unfold any &quot;internal-multi&quot; effects into separate instances (e.g. the possibility of having an arbitrary number of single masks at any point of the pipeline instead of having one special masking facility encompassing multiple sub-masks. Similarly, we treat the Objects in the Session in a more uniform manner and gain the possibility to [[place|Placement]] them in various ways.
</pre>
</div>
<div title="DesignPlayerSubsystem" modifier="Ichthyostega" modified="201105220332" created="201105220216" tags="Player design draft" changecount="5">
<div title="DesignPlayerSubsystem" modifier="Ichthyostega" modified="201105230122" created="201105220216" tags="Player design draft" changecount="12">
<pre>//Currently (5/2011) this page is used to collect and build up a coherent design for the player subsystem of Lumiera..//
!Starting point
The idea is to start out with the design of the PlayerDummy and to //transform//&amp;nbsp; it into the full player subsystem.
The intention is to start out with the design of the PlayerDummy and to //transform//&amp;nbsp; it into the full player subsystem.
* the ~DisplayService in that dummy player design moves down into Proc-Layer and becomes the OutputManager
* likewise, the ~DisplayerSlot is transformed into the interface OutputSlot, with various implementations to be registered with the OutputManager
* the core idea of having a play controler act as the frontend and handle to an PlayProcess is retained.
!!Idea
Introduce a new kind of MObject, a GeneratorMO, to represent what the current dummy player does: generate some kind of test data. As a first step, we might retro-fit the existing dummy player to this structure, and then expand it to have a minimal render engine setup for tests and diagnostics. That is, there will be some kind of GeneratorNode to produce test data.
!!Stages of transition
Reworking the dummy player into the PlayerSubsystem is a larger undertaking, and best broken up into several //stages.//
Reworking the dummy player into the [[Player subsystem|PlayService]] is a larger undertaking, and best broken up into several //stages.//
# just moving the existing entities into the final location (typically down in the layer hierarchy)
# introduce a GeneratorMO and a GeneratorNode, while providing a shortcut to get the GeneratorNode without requiring the (not yet implemented) Builder.
# rework the ~ProcessImpl and the ~TickService to become the CalculationStream and use the real Engine Interface, but still with an mock implementation hooked up behind
# extend and elaborate the handling of output, build the foundation of the real OutputManager
# switch to the real Scheduler and Engine implementation
!!Idea
Introduce a new kind of MObject, a GeneratorMO, to represent what the current dummy player does: generate some kind of test data. As a first step, we might retro-fit the existing dummy player to this structure, and then expand it to have a minimal render engine setup for tests and diagnostics. That is, there will be some kind of GeneratorNode to produce test data.</pre>
!!!!new entities to build {{red{#805}}}
* the ~DisplayService needs to be generalised into an OutputManager interface
* we need to introduce a new kind of StructAsset, the ViewerAsset.
* then, of course, the PlayService interface needs to be created
* as a temporary soltion, a ''~DummyPlayConnection'' will be created hard-wired, within the ~DummyPlayer service. This dumy container is a test setup, explicitly creating a OutputManager implementation, a GeneratorMO, a GeneratorNode (thus omitting the not-yet-implemented Builder) and the corresponding ModelPort. This way, the ~DummyPlayer service can be changed to use the real PlayService for creating the dummy generated output data. It will then pass back the resulting PlayController to the existing GUI setup.
The Method of pushing frames to the Viewer widget is changed fundamentally during that transition: while previously, in the PlayerDummy design study, the GUI opened a Display-façade interface -- now rather the GUI has to register an OutputSlot implementation with the global OutputManager. Such a registration requires an explicit deregistration on shutdown, and this can be made to block, until no further data will be delivered. Using this approach tries to circumvent the problems with occasional crashes on shutdown, due to dispatching frame output signals in the event thread while already in shutdown.
</pre>
</div>
<div title="DisplayFacade" modifier="Ichthyostega" modified="200904302316" created="200902080703" tags="spec" changecount="2">
<pre>LayerSeparationInterface provided by the GUI.
@ -1713,6 +1723,15 @@ When building the low-level model, the actual processing code is resolved and a
Initially, only the parameter (descriptors) are present on the effect ~MObject, while the actual [[parameter providers|ParamProvider]] are created or wired (by the ConManager) on demand.
</pre>
</div>
<div title="EngineFaçade" modifier="Ichthyostega" modified="201105222330" created="201105222328" tags="Rendering overview spec" changecount="2">
<pre>The primary interface used by the upper application layers to interact with the render engine, to create and manage ongoing [[calculation streams|CalculationStream]].
Below this facade, there is a thin adaptadion and forwarding layer, mainly talking to
* the individual CalculationStream elements created for each PlayProcess.
* the FrameDispatcher, which translates such streams into a series of RenderJob entries
* the [[Scheduler]], which is responsible to perform these jobs in a timely fashion
</pre>
</div>
<div title="EntryID" modifier="Ichthyostega" modified="201012300036" created="201012300026" tags="def Types" changecount="5">
<pre>A general identification scheme, ombining a human readable symbolic name, unique within a //specifically typed context,// and machine readable hash ID (LUID). ~Entry-IDs allow for asset-like position accounting and for type safe binding between configuration rules and model obects. They allow for creating an entry with symbolic id and distinct type, combined with an derived hash value, without the overhead in storage and instance management imposed by using a full-fledged Asset.
@ -1854,19 +1873,19 @@ The fixture is like a grid, where one dimension is given by the [[model ports|Mo
:Thus the exit nodes are keyed by ~Pipe-ID as well (and consequently have a distinct [[stream type|StreamType]]) -- each model port coresponds to {{{&lt;number_of_segments&gt;}}} separate exit nodes, but of course an exit node may be //mute.//
</pre>
</div>
<div title="FixtureDatastructure" modifier="Ichthyostega" modified="201012162342" created="201012162304" tags="spec Builder" changecount="6">
<div title="FixtureDatastructure" modifier="Ichthyostega" modified="201105222242" created="201012162304" tags="spec Builder" changecount="9">
<pre>Generally speaking, the [[here|Fixture]] comprised of a ModelPortRegistry and a set of [[segmentations|Segmentation]] per Timeline.
This page focusses on the actual datastructure and usage details on that level. See also &amp;rarr; [[storage|FixtureStorage]] considerations.
This page focusses on the actual data structure and usage details on that level. See also &amp;rarr; [[storage|FixtureStorage]] considerations.
!transactional switch
A key point to note is the fact that the fixture is frequently [[re-built||BuildFixture]] by the [[Builder]], while render processes may be going in in parallel. Thus, when a build process is finished, a transactional ''commit'' happens to ''hot swap'' the new parts of the model. This is complemented by a cleanup of tainted render processes; finally, storage can be relaimed.
A key point to note is the fact that the fixture is frequently [[re-built||BuildFixture]] by the [[Builder]], while render processes may be going on in parallel. Thus, when a build process is finished, a transactional ''commit'' happens to ''hot swap'' the new parts of the model. This is complemented by a clean-up of tainted render processes; finally, storage can be reclaimed.
To support this usage pattern, the Fixture implementation makes use of the [[PImpl pattern|http://c2.com/cgi/wiki?PimplIdiom]]
!Collecting usage scenarios {{red{WIP 12/10}}}
* ModelPort access
** get the model port for a given ~Pipe-ID
** ennumerate the model ports for a Timeline
** enumerate the model ports for a Timeline
* rendering frame dispatch
** get or create the frame dispatcher table
** dispatch a single frame to yield the corresponding ExitNode
@ -1875,16 +1894,16 @@ To support this usage pattern, the Fixture implementation makes use of the [[PIm
** create a new segmentation
** establish what segments actually need to be rebuilt
** dispatch a newly built segment into the transaction
** schedule superseded segments and tainted process for cleanup
** schedule superseded segments and tainted process for clean-up
** commit a transaction
!Conclusions about the structure {{red{WIP 12/10}}}
* the ~PImpl needs to be a single (language) pointer. This necessitates having a monolithic Fixture implementation holder
* moreover, this necessitates a tight integration up to implementation level, both with the cleanup and the render processes themselves
* moreover, this necessitates a tight integration down to implementation level, both with the clean-up and the render processes themselves
</pre>
</div>
<div title="FixtureStorage" modifier="Ichthyostega" modified="201012162324" created="201012140231" tags="Builder impl operational draft" changecount="30">
<div title="FixtureStorage" modifier="Ichthyostega" modified="201105222258" created="201012140231" tags="Builder impl operational draft" changecount="33">
<pre>The Fixture &amp;rarr; [[data structure|FixtureDatastructure]] acts as umbrella to hook up the elements of the render engine's processing nodes network (LowLevelModel).
Each segment within the [[Segmentation]] of any timeline serves as ''extent'' or unit of memory management: it is built up completely during the corresponding build process and becomes immutable thereafter, finally to be discarded as a whole when superseded by a modified version of that segment (new build process) -- but only after all related render processes are known to be terminated.
@ -1922,7 +1941,7 @@ But the primary question here is to judge the impact of such an implementation.
!!!identifying tainted and disposable segments
Above estimation hints at the necessity of frequently finding some 30 to 100 segments to be disposed, out of thousands, assumed the original reason for triggering the build process was a typically local change in the high-level model. We can only discard when all related processes are finished, but there is a larger number of segments as candidate for eviction. These candidates are rather easy to pinpoint -- they will be uncovered during a linear comparison pass prior to commiting the changed Fixture. Usually, the number of candidates will be low (localised changes), but global manipulations might invalidate thousands of segments.
* if we frequently pick the segments actually to disposed, there is the danger of performance degeneration when the number if segments is high
* if we frequently pick the segments actually to be disposed, there is the danger of performance degeneration when the number of segments is high
* the other question is if we can afford just to keep all of those candidates around, as all of them are bound to get discardable eventually
* and of course there is also the question how to detect //when// they're due.
@ -1935,7 +1954,7 @@ Above estimation hints at the necessity of frequently finding some 30 to 100 seg
//currently {{red{12/10}}} I tend to prefer Model B...// while the priority queue remains to be investigated in more detail for organising the actual build process.
But actually I'm struck here, because of the yet limited knowledge about those render processes....
* how do we //join// an aborted/changed rendering process to his successor, without creating a jerk in the output?
* is it even possible to continue a process when parts of the covered timerange is affected by a build?
* is it even possible to continue a process when parts of the covered timerange are affected by a build?
If the latter question is answered with &quot;No!&quot;, then the problem gets simple in solution, but maybe memory consuming: In that case, //all//&amp;nbsp; processes linked to a timeline gets affected and thus tainted; we'd just dump them onto a pile and delay releasing all of the superseeded segments until all of them are known to be terminated.
</pre>
</div>
@ -1976,6 +1995,9 @@ Additionally, they may be used for resource management purposes by embedding a r
#* one OpenGL Dataframe could contain raw texture data (but I am lacking expertise for this topic)
</pre>
</div>
<div title="FrameDispatcher" modifier="Ichthyostega" modified="201105222346" created="201105222330" tags="def Rendering" changecount="2">
<pre>An implementation facility within the RenderEngine, responsible for translating a logical CalculationStream (corresponding to a PlayProcess) into a sequence of individual RenderJob entries, which can then be handed over to the [[Scheduler]]. Performing this operation involves a special application of [[time quantisation|TimeQuant]]: after establishing a suitable starting point, a typically contiguous series of frame numbers need to be generated, together with the time coordinates for each of those frames</pre>
</div>
<div title="FullScreenPlugin" modifier="CehTeh" modified="200706110313" created="200607241016" tags="systemConfig lewcidExtension" server.type="file" server.host="file:///home/ct/.homepage/home.html" server.page.revision="200706110313">
<pre>/***
|Name|FullScreenPlugin|
@ -2967,12 +2989,12 @@ These are used as token for dealing with other objects and have no identity of t
</pre>
</div>
<div title="ModelPort" modifier="Ichthyostega" modified="201012112233" created="201011100234" tags="def spec" changecount="8">
<div title="ModelPort" modifier="Ichthyostega" modified="201105222218" created="201011100234" tags="def spec Model" changecount="11">
<pre>Any point where output possibly might be produced. Model port entities are located within the [[Fixture]] &amp;mdash; model port as a concept spans the high-level and low-level view. A model port can be associated both to a pipe in the HighLevelModel but at the same time denotes a set of corresponding [[exit nodes|ExitNode]] within the [[segments|Segmentation]] of the render nodes network.
A model port is rather derived than configured; it emerges when a pipe [[claims|WiringClaim]] an output destination and some other entity actually uses this designation as a target, either directly or indirectly. This match of provision and usage is detected during the build process and produces an entry in the fixture's model port table. These model ports in the fixture are keyed by ~Pipe-ID, thus each model port has an associated StreamType.
A model port is rather derived than configured; it emerges when a pipe [[claims|WiringClaim]] an output destination, while some other entity at the same time actually //uses this designation as a target,// either directly or indirectly. This match of provision and usage is detected during the build process and produces an entry in the fixture's model port table. These model ports in the fixture are keyed by ~Pipe-ID, thus each model port has an associated StreamType.
Model ports are the effective, resulting outputs of each timeline; additional ports result from [[connecting a viewer|ViewerPlayConnection]]. Any render or display process happens at a model port.
Model ports are the effective, resulting outputs of each timeline; additional ports result from [[connecting a viewer|ViewConnection]]. Any render or display process happens at a model port.
!formal specification
Model port is a //conceptual entity,// denoting the possibility to pull generated data of a distinct (stream)type from a specific bus within the model -- any possible output produced or provided by Lumiera is bound to appear at a model port. The namespace of model ports is global, each being associated with a ~Pipe-ID.
@ -3224,7 +3246,7 @@ Any external output sink is managed as a [[slot|DisplayerSlot]] in the ~OutputMa
&amp;rarr; see also the PlayerDummy
</pre>
</div>
<div title="OutputMapping" modifier="Ichthyostega" modified="201011270311" created="201011080238" tags="Model spec draft" changecount="23">
<div title="OutputMapping" modifier="Ichthyostega" modified="201105221814" created="201011080238" tags="Model spec draft" changecount="25">
<pre>An output mapping serves to //resolve//&amp;nbsp; [[output designations|OutputDesignation]].
!Mapping situations
@ -3235,8 +3257,8 @@ Any external output sink is managed as a [[slot|DisplayerSlot]] in the ~OutputMa
:any Timeline produces a number of [[model ports|ModelPort]]. On the other hand, any viewer exposes a small number of output designations, representing the image and sound output(s).
:Thus, in this case we resolve similar to a bus connection, possibly overridden by already pre-existing or predefined connections.
;switch board
:a viewer might receive multiple outputs and overlays, necessitating a user operated control to select what's actually to displayed
:Thus, in this case we need a backwards resolution at the lower end of the output network, to connect to the model port as defined by the switchboard
:a viewer might receive multiple outputs and overlays, necessitating a user operated control to select what's actually to be displayed
:Thus, in this case we need a backwards resolution at the lower end of the output network, to connect to the model port as defined by this viewer SwitchBoard
;global pipes or virtual media
:when binding a Sequence as Timeline or VirtualClip, a mapping from output designations used within the Sequence to virtual channels or global pipes is required
:Thus, in this case we need to associate output designations with ~Pipe-IDs encountered in the context according to some rules &amp;mdash; again maybe overridden by pre-existing connections
@ -4114,15 +4136,38 @@ We need a way of addressing existing [[pipes|Pipe]]. Besides, as the Pipes and T
&lt;&lt;tasksum end&gt;&gt;
</pre>
</div>
<div title="PlayProcess" modifier="Ichthyostega" modified="201012181732" created="201012181714" tags="def spec Player" changecount="2">
<div title="PlayProcess" modifier="Ichthyostega" modified="201105222321" created="201012181714" tags="def spec Player" changecount="5">
<pre>With //play process//&amp;nbsp; we denote an ongoing effort to calculate a stream of frames for playback or rendering.
The play process is an conceptual entity linking together several activities in the [[Backend]] and the RenderEngine. Creating a play process is the central service provided by the [[player subsystem|Player]]: it maintains a registration entry for the process to keep track of associated entities, resources allocated and calls dispatched as a consequence, and it wires and exposes a PlayController to serve as an interface and information hub.
The play process is an conceptual entity linking together several activities in the [[Backend]] and the RenderEngine. Creating a play process is the central service provided by the [[player subsystem|Player]]: it maintains a registration entry for the process to keep track of associated entities, resources allocated and calls [[dispatched|FrameDispatcher]] as a consequence, and it wires and exposes a PlayController to serve as an interface and information hub.
''Note'': the player is in no way engaged in any of the actual calculation and management tasks necessary to make this stream of calculations happen. The play process code contained within the player subsystem is largely comprised of organisational concerns and not especially performance critical.
* the [[Backend]] is responsible for scheduling and dispatching the calculations
''Note'': the player is in no way engaged in any of the actual calculation and management tasks necessary to make this [[stream of calculations|CalculationStream]] happen. The play process code contained within the player subsystem is largely comprised of organisational concerns and not especially performance critical.
* the [[Backend]] is responsible for scheduling and [[dispatching|Dispatcher]] the CalculationStream
* the RenderEngine has the ability to cary out individual frame calculations
* the OutputSlot exposed by the [[output manager|OutputManagement]] is responsible for accepting timed frame delivery</pre>
</div>
<div title="PlayService" modifier="Ichthyostega" modified="201105221918" created="201105221900" tags="Player spec draft" changecount="9">
<pre>The [[Player]] is an independent [[Subsystem]] within Lumiera, located at Proc-Layer level. A more precise term would be &quot;rendering and playback coordination subsystem&quot;. It provides the capability to generate media data, based on a high-level model object, and send this generated data to an OutputDesignation, creating an continuous and timing controlled output stream. Clients may utilise these functionality through the ''play service'' interface.
!provided services
* creating a PlayProcess
* managing existing play processes
* convenience short-cuts for //performing//&amp;nbsp; several kinds of high-level model objects
!creating a play process
This is the core service provided by the player subsystem. The purpose is to create a collaboration between several entities, creating media output
;data producers
:a set of ModelPort elements to ''pull'' for generating output. They can either be handed in direcly, or resolved from a set of OutputDesignation elements
;data sinks
:to be able to create output, the PlayProcess needs to cooperate with OutputSlot.s
:physical outputs are never handled directly, rather, the playback or rendering needs an OutputManager to resolve the output designations into output slots
;controller
:when provided with these two prerequisites, the play service is able to build a PlayProcess.
:for clients, this process can be accessed and maintained through a PlayController, which acts as (copyable) handle and front-end.
;engine
:the actual processing is done by the RenderEngine, which in itself is a compound of several services within [[Backend]] and Proc-Layer
:any details of this processing remain opaque for the clients; even the player subsystem just accesses the EngineFaçade
</pre>
</div>
<div title="Player" modifier="Ichthyostega" modified="201105220214" created="201012181700" tags="def overview" changecount="9">
<pre>Within Lumiera, &amp;raquo;Player&amp;laquo; denotes the [[Subsystem]] responsible for organising and tracking //ongoing playback and render processes.// &amp;rarr; [[PlayProcess]]
The player subsystem does not perform or even manage any render operations, nor does it handle the outputs directly.
@ -4722,9 +4767,10 @@ The link between ~MObject and Asset should be {{{const}}}, so the clip can't cha
At first sight the link between asset and clip-MO is a simple logical relation between entities, but it is not strictly 1:1 because typical media are [[multichannel|MultichannelMedia]]. Even if the media is compound, there is //only one asset::Clip//, because in the logical view we have only one &quot;clip-thing&quot;. On the other hand, in the session, we have a compound clip ~MObject comprised of several elementary clip objects, each of which will refer to its own sub-media (channel) within the compound media (and don't forget, this structure can be tree-like)
{{red{open question:}}} do the clip-MO's of the individual channels refer directly to asset::Media? does this mean the relation is different from the top level, where we have a relation to a asset::Clip??</pre>
</div>
<div title="RenderEngine" modifier="Ichthyostega" modified="200802031835" created="200802031820" tags="def" changecount="2">
<div title="RenderEngine" modifier="Ichthyostega" modified="201105222323" created="200802031820" tags="def" changecount="3">
<pre>Conceptually, the Render Engine is the core of the application. But &amp;mdash; surprisingly &amp;mdash; we don't even have a distinct »~RenderEngine« component in our design. Rather, the engine is formed by the cooperation of several components spread over two layers (Backend and Proc-Layer): The [[Builder]] creates a network of [[render nodes|ProcNode]], which is used by the Backend to pull individual Frames.
&amp;rarr; OverviewRenderEngine
&amp;rarr; EngineFaçade
</pre>
</div>
<div title="RenderEntities" modifier="Ichthyostega" modified="200906071810" created="200706190715" tags="Rendering classes img" changecount="10">
@ -4910,7 +4956,7 @@ We need to detect attaching and detaching of
* root &amp;harr; [[Track]]
</pre>
</div>
<div title="Segmentation" modifier="Ichthyostega" modified="201012140222" created="201012121901" tags="def spec Builder" changecount="27">
<div title="Segmentation" modifier="Ichthyostega" modified="201105222236" created="201012121901" tags="def spec Builder" changecount="28">
<pre>//Segmentation of timeline// denotes a data structure and a step in the BuildProcess.
When [[building the fixture|BuildFixture]], ~MObjects -- as handled by their Placements -- are grouped below each timeline using them; Placements are then to be resolved into [[explicit Placements|ExplicitPlacement]], resulting in a single well defined time interval for each object. This allows to cut this effective timeline into slices of constant wiring structure, which are represented through the ''Segmentation Datastructure'', a time axis with segments holding object placements and [[exit nodes|ExitNode]]. &amp;nbsp;&amp;rarr; see [[structure of the Fixture|Fixture]]
* for each Timeline we get a Segmentation
@ -4940,7 +4986,7 @@ When [[building the fixture|BuildFixture]], ~MObjects -- as handled by their Pla
!!!conclusions
The Fixture is mostly comprised of the Segementation datastructure, but some other facilities are involved too
# at top level, access is structured by groups of model ports, actually grouped by timeline. This first access level handled by the Fixture
# at top level, access is structured by groups of model ports, actually grouped by timeline. This first access level is handled by the Fixture
# during the build process, there is a collection of placements; this can be discarded afterwards
# the backbone of the segmentation is closely linked to an ordering by time. Initially it should support sorting, access by time interval search later on.
# discarding a segment (or failing to do so) has an high impact on the whole application. We should employ a reliable mechanism for that.
@ -5725,6 +5771,14 @@ h1,h2,h3,h4,h5,h6 {
/*}}}*/
</pre>
</div>
<div title="SwitchBoard" modifier="Ichthyostega" modified="201105221902" created="201105221831" tags="def SessionLogic Player" changecount="2">
<pre>Viewers for displaying output are connected to the timelines or other elements to be displayed through a ViewConnection. This creates an additional mapping step (&amp;rarr; BindingMO), similar to the attachment of a sequence or virtual clip to the [[global busses|GlobalBus]]. Yet the viewers don't provide such an elaborate mixing desk like view as the timelines -- rather there is only a simplified version of the global busses, exposed to the user as ''switch board''.
The corresponding GUI control will allow to choose among possible data sources (esp. ProbePoint) for any given StreamType (more precisely, for every //prototype,// e.g. image, sound). Moreover, there are some (limited) overlay capabilities (split image, mix sound). By default, this additional control will likely be hidden, as there is a default 1:1 association between the master busses of the timeline and the usable output destinations.
!Model and Interfaces
Regarding the internal wiring of components, the Viewer with a switch board behaves similar as a timeline: At the output side, there are a small number of standard OutputDesignation elements for the selection of primary kinds of media handled within this session (typically Video and Audio). But contrary to a timeline, a Viewer element also exposes an OutputManager interface, which is backed by a specific OutputMapping element, which internally connects to the main OutputManager for the whole Application. This way, a Viewer has the capability to get a PlayController</pre>
</div>
<div title="TabTimeline" modifier="Ichthyostega" modified="200806030148" created="200706191949" changecount="4">
<pre>&lt;&lt;timeline better:true maxDays:55 maxEntries:45&gt;&gt;</pre>
</div>
@ -6874,7 +6928,7 @@ At the level of individual timecode formats, we're lacking a common denominator;
&amp;rarr; Quantiser [[implementation details|QuantiserImpl]]
</pre>
</div>
<div title="TimeUsage" modifier="Ichthyostega" modified="201105122348" created="201012230204" tags="design discuss" changecount="27">
<div title="TimeUsage" modifier="Ichthyostega" modified="201105222341" created="201012230204" tags="design discuss" changecount="30">
<pre>the following collection of usage situations helps to shape the details of the time values and time quantisation design. &amp;rarr; see also [[time quantisation|TimeQuant]]
;time position of an object
@ -6894,6 +6948,8 @@ At the level of individual timecode formats, we're lacking a common denominator;
:because this operation might be done both in the quantised or non-quantised domain, and also the result might be (un)quantised
;updating the playback position
:this can be seen as a practical application of the above; basically we can choose to show the wall clock time or we can advance the playback position in frame increments, thus denoting the frame currently in display. For video, these distinctions may look moot, but they are indeed relevant for precise audio editing, especially when combined with loop playback (recall that audio is processed block wise, but the individual sample frames and thus the possible loop positions are way finer than the processing block size)
;dispatching individual frames for calculation
:when a [[render or playback process|PlayProcess]] is created, at some point we need to translate this logical unit (&quot;calculation stream&quot;) into individual frame job entries. This requires to break continuous time into individual frames, and then ennumerating these frames.
;displaying time intervals
:for display, time intervals get //re-quantised// into display array coordinates.
:While evidently the display coordinates are themselves quantised and we obviously don't want to cancel out the effect of an quantisation of the values or intervals to be displayed (which means, we get two quantisations chained up after each other), there remains the question if the display array coordinates should be aligned to the grid of the //elements to be displayed,// and especially if the allowed zoom factors should be limited. This decision isn't an easy one, as it has an immediate and tangible effect on what can be showed, how reversible and reproducible a view is and (especially note this!) on the actual values which can be set and changed through the GUI.
@ -6915,6 +6971,8 @@ Another closely related problem is ''when to allow [[mutations|TimeMutation]]'',
The ''problem with playback position'' is -- that indeed it's an attempt to conceptualise a non-existing entity. There is no such thing like &quot;the&quot; playback position. Yet most applications I'm aware off //do// employ this concept. Likely they got trapped by the metaphor of the tape head, again. We should do away with that. On playback, we should show a //projection of wall-clock time onto the expected playback range// -- not more, not less. It should be acknowledged that there is //no direct link to the ongoing playback processes,// besides the fact that they're assumed to sync to wall-clock time as well. Recall, typically there are multiple playback processes going on in compound, and each might run on a different update rate. If we really want a //visual out-of-sync indicator,// we should treat that as a separate reporting facility and display it apart of the playback cursor.
An interesting point to note for the ''frame dispatch step'' is the fact, that in this case quantised values and quantisation are approached in the reverse direction, compared with the other uses. Here, after establishing a start point on the time scale, we proceed with ennumerating distinct frames and later on need to access the corresponding raw time, especially to find out about the [[timeline segment|Segmentation]] to address, or for retrieving parameter automation. &amp;rarr; FrameDispatcher.
Note that the ''display window might be treated as just an independent instance of quantisation''. This is similar to the approach taken above for modifying quantised time span values. We should provide a special kind of time grid, the display coordinates. The origin of these is always defined to the left (lower) side of the interval to be displayed, and they are gauged in screen units (pixels or similar, as used by the GUI toolkit set). The rest is handled by the general quantisation mechanisms. The problem of aligning the display should be transformed into a general facility to align grids, and solved for the general case. Doing so solves the remaining problems with quantised value changes and with ''specifying relative placements'' as well: If we choose to represent them as quantised values, we might (or might not) also choose to apply this //grid-alignment function.//
!the complete time value usage cycle
@ -6976,12 +7034,13 @@ Currently (1/11), the strategy is implemented according to (1) and (4) above, le
Implementation of this strategy is still broken: it doesn't work properly when actually the change passing over the zero point happens by propagation from lower digits. Because then -- given the way the mutators are implemented -- the //new value of the wrapping digit hasn't been stored.// It seems the only sensible solution is to change the definition of the functors, so that any value will be changed by side-effect {{red{Question 4/11 -- isn't this done and fixed by now??}}}
</pre>
</div>
<div title="Timeline" modifier="Ichthyostega" modified="201011220126" created="200706250721" tags="def" changecount="21">
<div title="Timeline" modifier="Ichthyostega" modified="201105221835" created="200706250721" tags="def" changecount="22">
<pre>Timeline is the top level element within the [[Session (Project)|Session]]. It is visible within a //timeline view// in the GUI and represents the effective (resulting) arrangement of media objects, to be rendered for output or viewed in a Monitor (viewer window). A timeline is comprised of:
* a time axis in abolute time ({{red{WIP 1/10}}}: not clear if this is an entity or just a conceptual definition)
* a PlayControler ({{red{WIP Summer 2010: see discussion on ML. It seems rather that the controller will be attached}}})
* a list of [[global Pipes|GlobalPipe]] representing the possible outputs (master busses)
* //exactly one// top-level [[Sequence]], which in turn may contain further nested Sequences.
* when used for Playback, a ViewConnection is necessary, allowing to get or connect to a PlayController
Please note especially that following this design //a timeline doesn't define tracks.// [[Tracks form a Tree|Track]] and are part of the individual sequences, together with the media objects placed to these tracks. Thus sequences are independent entities which may exist stand-alone within the model, while a timeline is //always bound to hold a sequence.// &amp;rarr; see ModelDependencies
[&gt;img[Fundamental object relations used in the session|uml/fig136453.png]]
@ -7202,14 +7261,29 @@ For now, as of 6/10, we use specialised QueryResolver instances explicitly and d
&amp;rarr; QueryRegistration
</pre>
</div>
<div title="ViewerPlayConnection" modifier="Ichthyostega" modified="201105110009" created="201007110305" tags="Model Player spec draft" changecount="7">
<div title="ViewConnection" modifier="Ichthyostega" modified="201105221902" created="201105221854" tags="def Model SessionLogic" changecount="4">
<pre>For any kind of playback to happen, timeline elements (or similar model objects) need to be attached to a Viewer element through a special kind of [[binding|BindingMO]], called a ''view connection''. In the most general case, this creates an additional OutputMapping (and in the typical standard case, this boils down to a 1:1 association, sending the master bus of each media kind to the standard OutputDesignation for that kind).
Establishing a ~ViewConnection is prerequisite for creating or attaching an PlayController through the PlayService. Multiple &quot;play control&quot; GUI elements can be associated with such a play controller, causing them to work as being linked together: if you e.g. push &quot;play&quot; on one of them, the button states of all linked GUI controls will reflect the state change of the underlying play controller.
View connections are part of the model and thus persistent. They can be created explicitly, or just derived by //allocating a viewer.// And a new view connection can push aside (and thus &quot;break&quot;) an existing one from another timeline or model element. When a view connection is //broken,// any associated PlayProcess needs to be terminated (this is a blocking operation). Thus, at any time, there can be only one active view connection to a given viewer; here &quot;active&quot; means, that a PlayController has been hooked up, and the connection is ready for playback or rendering. But on the other hand, nothing prevents a timeline (or similar model object) to maintain multiple view connections -- consequently the actual playback position behaves as if associated with the view connection.
</pre>
</div>
<div title="ViewerAsset" modifier="Ichthyostega" created="201105230116" tags="Model spec" changecount="1">
<pre>A [[structural Asset|StructAsset]] corresponding to a Viewer element in the GUI.
These Viewer (or Monitor) elements play an enabling role for any output generation. In order to [[initiate playback|PlayService]], we need a fulle resolved OutputDesignation, which typcially can be achieved by creating a ViewConnection, i.e. connecting a timeline or similarily suitable model element to such a viewer. Actually, this connection is modelled by attaching to a BindingMO which is linked to a ViewerAsset. This way, the model tracks and persists the available viewer windows and the current connection situation.
When the GUI is outfitted, based on the current Session or HighLevelModel, it is expected to retrieve the viewer assets and for each of them, after installing the necessary widgetes, registers an OutputSlot with the global OutputManager.</pre>
</div>
<div title="ViewerPlayConnection" modifier="Ichthyostega" modified="201105221838" created="201007110305" tags="Model Player spec draft" changecount="8">
<pre>for showing output, three entities are involved
* the [[Timeline]] holds the relevant part of the model, which gets rendered for playback
* by connecting to a viewer component, an actual output target is established
* the playback process itself is coordinated by a PlayController, which in turn creates a PlayProcess
!the viewer connection
A viewer element gets connected to a given timeline either by directly attaching it, or by //allocating an available free viewer.// Anyway, as a model element, the viewer is just like another set of global pipes chained up after the global pipes present in the timeline. The number and kind of pipes provided is a configurable property of the viewer element &amp;mdash; more specifically: the viewer's SwitchBoard. Thus, connecting a viewer activates the same internal logic employed when connecting a sequence into a timeline or meta-clip: a default channel association is established, which can be overridden persistently (&amp;rarr; OutputMapping). Each of the viewer's pipes in turn gets connected to a system output through an OutputManager slot &amp;mdash; again an output mapping step.
A viewer element gets connected to a given timeline either by directly attaching it, or by //allocating an available free viewer.// Anyway, as a model element, the viewer is just like another set of global pipes chained up after the global pipes present in the timeline. Connecting a timeline to a viewer creates a ViewConnection, which is a special [[binding|BindingMO]]. The number and kind of pipes provided is a configurable property of the viewer element &amp;mdash; more specifically: the viewer's SwitchBoard. Thus, connecting a viewer activates the same internal logic employed when connecting a sequence into a timeline or meta-clip: a default channel association is established, which can be overridden persistently (&amp;rarr; OutputMapping). Each of the viewer's pipes in turn gets connected to a system output through an OutputManager slot &amp;mdash; again an output mapping step.
</pre>
</div>
<div title="VirtualClip" modifier="Ichthyostega" modified="201011220152" created="200804110321" tags="def Model" changecount="17">