diff --git a/src/backend/engine/scheduler-frontend.cpp b/src/backend/engine/scheduler-frontend.cpp new file mode 100644 index 000000000..588d1276b --- /dev/null +++ b/src/backend/engine/scheduler-frontend.cpp @@ -0,0 +1,33 @@ +/* + RenderEngine - a complete network of processing nodes usable for rendering + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "proc/engine/renderengine.hpp" + +namespace engine { + + + /** */ + + + +} // namespace engine diff --git a/src/backend/engine/scheduler-frontend.hpp b/src/backend/engine/scheduler-frontend.hpp new file mode 100644 index 000000000..c3030271f --- /dev/null +++ b/src/backend/engine/scheduler-frontend.hpp @@ -0,0 +1,58 @@ +/* + RENDERENGINE.hpp - a complete network of processing nodes usable for rendering + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +#ifndef ENGINE_RENDERENGINE_H +#define ENGINE_RENDERENGINE_H + +#include + +#include "proc/engine/rendergraph.hpp" + + +using std::list; + + +namespace engine { + + + /** + * @todo this is planned to become the frontend + * to the render node network, which can be considered + * at the lower end of the middle layer; the actual + * render operations are mostly implemented by the backend + * ////////TODO WIP as of 12/2010 + */ + class RenderEngine : public RenderGraph + { + public: + ///// TODO: find out about the public operations + // note: the play controller lives in the proc-layer, + // but is a subsystem separate of the sesison. + + private: + list renderSegments; + + }; + +} // namespace engine +#endif diff --git a/src/proc/asset/viewer.cpp b/src/proc/asset/viewer.cpp new file mode 100644 index 000000000..bb2f9e36e --- /dev/null +++ b/src/proc/asset/viewer.cpp @@ -0,0 +1,72 @@ +/* + Timeline - independent top-level element of the Session + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "proc/asset/timeline.hpp" +//#include "proc/mobject/session/track.hpp" +//#include "proc/mobject/placement.hpp" +//#include "proc/mobject/session/mobjectfactory.hpp" +#include "proc/mobject/session/binding.hpp" +#include "proc/assetmanager.hpp" + + +namespace asset { + + using lib::AutoRegistered; + + + + /** @todo anything significant to do here??? */ + Timeline::Timeline (const Asset::Ident& idi, RBinding const& sequenceBinding) + : Struct (idi) + , boundSequence_(sequenceBinding) + { + REQUIRE (boundSequence_); + } + + + PTimeline + Timeline::create (Asset::Ident const& idi, RBinding const& sequenceBinding) + { + REQUIRE (getRegistry, "can't create a Timeline prior to session initialisation"); + + PTimeline newElement (AssetManager::instance().wrap (*new Timeline(idi, sequenceBinding))); + getRegistry().append (newElement); + + ENSURE (newElement); + ENSURE (getRegistry().isRegistered (*newElement)); + return newElement; + } + + + void + Timeline::unlink () + { + AutoRegistered::detach(); + boundSequence_.purge(); + Struct::unlink(); + } + + + + +} // namespace asset diff --git a/src/proc/asset/viewer.hpp b/src/proc/asset/viewer.hpp new file mode 100644 index 000000000..7bf168e1e --- /dev/null +++ b/src/proc/asset/viewer.hpp @@ -0,0 +1,115 @@ +/* + TIMELINE.hpp - independent top-level element of the Session + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +/** @file timeline.hpp + ** Top level structural element within the session. + ** Each Lumiera session may contain multiple top level timeline containers, + ** which at the same time act as structural asset and as part of the public + ** session API exposed to clients for discovering the session contents. + ** Actually, Timelines are facade objects, delegating the implementation to + ** the BindingMO, the Axis and the Sequences/Tracks. + ** + ** Contrary to usual habits in video/sound editing software, in Lumiera the + ** tracks are \em not part of the timeline, but rather attached directly to + ** the sequence container. To be usable, a timeline needs a binding to refer + ** to such a sequence, but this sequence may be bound into multiple timelines + ** or even virtual clips simultaneously. + ** + ** Like every structural asset, the creation of timelines happens automatically + ** on referral; Timelines can be queried from the StructFactory, providing additional + ** requested capabilities. Commonly clients will retrieve a given timeline by query + ** on the name-ID of the timeline: \c Struct::retrieve(Query("id(theName).")) + ** Additionally, the binding to a specific sequence may be established alongside: + ** \c "timeline(theTimelineName),bindSequence(theTimelineName,sequenceID)." + ** + ** @see Session + ** @see Sequence + ** @see StructFactory + ** + */ + + +#ifndef ASSET_TIMELINE_H +#define ASSET_TIMELINE_H + +#include "proc/asset/struct.hpp" +//#include "proc/mobject/mobject.hpp" +//#include "proc/mobject/placement.hpp" +#include "proc/mobject/mobject-ref.hpp" +//#include "proc/mobject/session/binding.hpp" ////TODO avoidable?? +#include "lib/p.hpp" +#include "lib/element-tracker.hpp" + + +//#include +//#include + +//using std::vector; +//using std::string; + +namespace mobject { +namespace session { + + class Binding; + typedef MORef RBinding; +}} + + +namespace asset { + + +// using lumiera::P; + class Timeline; + typedef lumiera::P PTimeline; + + + /** + * TODO type comment + */ + class Timeline + : public Struct + , public lib::AutoRegistered + { + typedef mobject::session::RBinding RBinding; + + RBinding boundSequence_; + + Timeline (Ident const&, RBinding const&); + + public: + /** create and register a new Timeline instance */ + static PTimeline create (Asset::Ident const& idi, RBinding const& sequenceBinding); + + protected: + virtual void unlink (); + + }; + + + + +///////////////////////////TODO currently just fleshing the API + + +} // namespace asset +#endif diff --git a/src/proc/engine/dispatcher.cpp b/src/proc/engine/dispatcher.cpp new file mode 100644 index 000000000..fefaf7c63 --- /dev/null +++ b/src/proc/engine/dispatcher.cpp @@ -0,0 +1,42 @@ +/* + RenderGraph - render network corresponding to one segment of the timeline + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "proc/engine/rendergraph.hpp" +#include "lib/frameid.hpp" +#include "proc/state.hpp" + +namespace lumiera { + + /** storage for the unique node-ID counter */ + ulong NodeID::currID (0); +} + + +namespace engine { + + /** */ + + + + +} // namespace engine diff --git a/src/proc/engine/dispatcher.hpp b/src/proc/engine/dispatcher.hpp new file mode 100644 index 000000000..a77eac68b --- /dev/null +++ b/src/proc/engine/dispatcher.hpp @@ -0,0 +1,64 @@ +/* + RENDERGRAPH.hpp - render network corresponding to one segment of the timeline + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +#ifndef ENGINE_RENDERGRAPH_H +#define ENGINE_RENDERGRAPH_H + +#include "proc/common.hpp" +#include "proc/state.hpp" +#include "lib/time/timevalue.hpp" + + + +namespace engine { + + using lib::time::TimeSpan; + using lib::time::FSecs; + using lib::time::Time; + + class ExitNode; + + /** + * @todo likely to be reworked into the engine backbone /////////////TODO WIP as of 12/2010 + */ + class RenderGraph + { + protected: + ExitNode * output; + + /** timerange covered by this RenderGraph */ + TimeSpan segment_; + + public: + RenderGraph() + : segment_(Time::ZERO, FSecs(5)) + { + UNIMPLEMENTED ("anything regarding the Fixture datastructure"); + } + + }; + + + +} // namespace engine +#endif diff --git a/src/proc/engine/engine-service.cpp b/src/proc/engine/engine-service.cpp new file mode 100644 index 000000000..ea443f709 --- /dev/null +++ b/src/proc/engine/engine-service.cpp @@ -0,0 +1,382 @@ +/* + DummyPlayerService - access point and service implementing a dummy test player + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "proc/play/dummy-player-service.hpp" +#include "proc/play/dummy-image-generator.hpp" +#include "proc/play/tick-service.hpp" +#include "lib/singleton.hpp" + +extern "C" { +#include "common/interfacedescriptor.h" +} + +#include +#include +#include +#include + + + +namespace proc { + namespace play{ + + using std::string; + using lumiera::Subsys; + using std::auto_ptr; + using boost::scoped_ptr; + using std::tr1::bind; + + + namespace { // hidden local details of the service implementation.... + + /** details of how the DummyPlayer service can be started + * and used as independent "subsystem" within main() */ + class DummyPlayerSubsysDescriptor + : public Subsys + { + operator string () const { return "Dummy-Player"; } + + + bool + shouldStart (lumiera::Option&) + { + return false; // for now the DummyPlayerService only comes "up" as dependency, + } // but doesn't start as a subsystem on it's own. + + bool + start (lumiera::Option&, Subsys::SigTerm terminationHandle) + { + ASSERT (!thePlayer_); + + thePlayer_.reset (new DummyPlayerService (terminationHandle)); + return true; + } + + /** manages the actual (single) instance of the player service impl */ + scoped_ptr 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 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 "; + } + ) + , 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::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 (_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 (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 (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 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 diff --git a/src/proc/engine/engine-service.hpp b/src/proc/engine/engine-service.hpp new file mode 100644 index 000000000..75e0f3d78 --- /dev/null +++ b/src/proc/engine/engine-service.hpp @@ -0,0 +1,161 @@ +/* + DUMMY-PLAYER-SERVICE.hpp - service implementing a dummy test player + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/** @file dummy-player-service.hpp + ** A public service provided by the Proc-Layer, implementing a dummy/mockup playback process. + ** This is a design sketch; Lumiera isn't able to generate rendered output as of 2/2009. The + ** idea is, that for each ongoing calculation process, there is a ProcessImpl instance holding + ** the necessary handles and allocations and providing an uniform API to the client side. + ** Especially, this ProcessImpl holds a TickService, which generates periodic callbacks, and + ** it uses an output handle (functor) to push the generated frames up. + ** + ** This service is the implementation of a layer separation facade interface. Clients should use + ** proc::play::DummyPlayer#facade to access this service. This header defines the interface used + ** to \em provide this service, not to access it. + ** + ** @see lumiera::DummyPlayer + ** @see gui::PlaybackController usage example + */ + + +#ifndef PROC_DUMMYPLAYER_SERVICE_H +#define PROC_DUMMYPLAYER_SERVICE_H + + +#include "include/dummy-player-facade.h" +#include "include/display-facade.h" +#include "common/instancehandle.hpp" +#include "lib/singleton-ref.hpp" + +#include +#include +#include + + +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 imageGen_; + boost::scoped_ptr 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 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 diff --git a/src/proc/play/dummy-image-generator.cpp b/src/proc/engine/worker/dummy-image-generator.cpp similarity index 100% rename from src/proc/play/dummy-image-generator.cpp rename to src/proc/engine/worker/dummy-image-generator.cpp diff --git a/src/proc/play/dummy-image-generator.hpp b/src/proc/engine/worker/dummy-image-generator.hpp similarity index 100% rename from src/proc/play/dummy-image-generator.hpp rename to src/proc/engine/worker/dummy-image-generator.hpp diff --git a/src/proc/play/tick-service.hpp b/src/proc/engine/worker/tick-service.hpp similarity index 100% rename from src/proc/play/tick-service.hpp rename to src/proc/engine/worker/tick-service.hpp diff --git a/src/proc/mobject/session/generator-mo.cpp b/src/proc/mobject/session/generator-mo.cpp new file mode 100644 index 000000000..426cd8e57 --- /dev/null +++ b/src/proc/mobject/session/generator-mo.cpp @@ -0,0 +1,86 @@ +/* + Clip - a Media Clip + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "proc/mobject/session/clip.hpp" +#include "proc/assetmanager.hpp" +#include "proc/asset/media.hpp" +#include "proc/asset/clip.hpp" +#include "lib/time/mutation.hpp" +#include "lib/util.hpp" + +using lib::time::Mutation; +using util::isnil; + +namespace mobject { +namespace session { + + /** new clip-MO linked with the given asset::Clip. + * Initially, this clip will cover the whole source media length. + */ + Clip::Clip (const asset::Clip& clipDef, const Media& mediaDef) + : mediaDef_(mediaDef) + , clipDef_(clipDef) + { + setupLength(); + throwIfInvalid(); + } + + + + /** implementing the common MObject self test. + * Length definition is consitent, underlying + * media def is accessible etc. */ + bool + Clip::isValid () const + { + TODO ("check consistency of clip length def, implies accessing the underlying media def"); + return !isnil(length_); + } + + + void + Clip::setupLength() + { + TODO ("really calculate the length of a clip and set length field"); + this->length_.accept (Mutation::changeDuration(mediaDef_.getLength())); + } + + + PMedia + Clip::getMedia () const + { + return asset::AssetManager::wrap (mediaDef_); + } + + + PClipAsset + Clip::findClipAsset () const + { + return asset::AssetManager::wrap (clipDef_); + } + + + + +}} // namespace mobject::session + diff --git a/src/proc/mobject/session/generator-mo.hpp b/src/proc/mobject/session/generator-mo.hpp new file mode 100644 index 000000000..52e134926 --- /dev/null +++ b/src/proc/mobject/session/generator-mo.hpp @@ -0,0 +1,110 @@ +/* + CLIP.hpp - a Media Clip + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +#ifndef MOBJECT_SESSION_CLIP_H +#define MOBJECT_SESSION_CLIP_H + +#include "proc/mobject/session/abstractmo.hpp" +#include "lib/time/timevalue.hpp" + + +namespace asset { + class Media; + class Clip; +} + +namespace mobject { +namespace session { + + using asset::Media; + using lib::time::TimeVar; + + typedef P PMedia; + typedef P PClipAsset; + + + /** + * A user visible/editable Clip is a reference to a contiguous + * sequence of media data loaded as Asset into the current Session. + * As such, it is a virtual (non destructive) cut or edit of the + * source material and can be placed into the Session to be rendered + * into the output. The actual media type of a clip will be derived + * at runtime by resolving this reference to the underlying Asset. + * + * @todo define how to denote Time positions /lengths. This is tricky, + * because it depends on the actual media type, and we want to encapsulate + * all these details as much as possible. + */ + class Clip + : public AbstractMO + { + string + initShortID() const + { + return buildShortID("Clip"); + } + + void setupLength(); + + + + protected: + /** start position in source */ + TimeVar start_; + + /** @todo using a mere ref here is against the scheme and only + done as temporal solution, until we work out how to handle + multichannel clips. It should be a smart pointer of some kind + and the unlink() function of the asset should take it into + account when breaking circular references. + */ + + const Media & mediaDef_; + const asset::Clip & clipDef_; + + Clip (const asset::Clip&, const Media&); + friend class MObjectFactory; + + + public: + bool isValid() const; + + /** access the underlying media asset */ + PMedia getMedia () const; + + /** locate the corresponding asset + * representing this clip or the whole + * compound in case of a multichannel clip + */ + PClipAsset findClipAsset () const; + + DEFINE_PROCESSABLE_BY (builder::BuilderTool); + + }; + + typedef Placement PClipMO; + + + +}} // namespace mobject::session +#endif diff --git a/src/proc/play/dummy-play-connection.cpp b/src/proc/play/dummy-play-connection.cpp new file mode 100644 index 000000000..ea443f709 --- /dev/null +++ b/src/proc/play/dummy-play-connection.cpp @@ -0,0 +1,382 @@ +/* + DummyPlayerService - access point and service implementing a dummy test player + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "proc/play/dummy-player-service.hpp" +#include "proc/play/dummy-image-generator.hpp" +#include "proc/play/tick-service.hpp" +#include "lib/singleton.hpp" + +extern "C" { +#include "common/interfacedescriptor.h" +} + +#include +#include +#include +#include + + + +namespace proc { + namespace play{ + + using std::string; + using lumiera::Subsys; + using std::auto_ptr; + using boost::scoped_ptr; + using std::tr1::bind; + + + namespace { // hidden local details of the service implementation.... + + /** details of how the DummyPlayer service can be started + * and used as independent "subsystem" within main() */ + class DummyPlayerSubsysDescriptor + : public Subsys + { + operator string () const { return "Dummy-Player"; } + + + bool + shouldStart (lumiera::Option&) + { + return false; // for now the DummyPlayerService only comes "up" as dependency, + } // but doesn't start as a subsystem on it's own. + + bool + start (lumiera::Option&, Subsys::SigTerm terminationHandle) + { + ASSERT (!thePlayer_); + + thePlayer_.reset (new DummyPlayerService (terminationHandle)); + return true; + } + + /** manages the actual (single) instance of the player service impl */ + scoped_ptr 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 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 "; + } + ) + , 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::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 (_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 (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 (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 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 diff --git a/src/proc/play/output-manager.cpp b/src/proc/play/output-manager.cpp new file mode 100644 index 000000000..96600bf3b --- /dev/null +++ b/src/proc/play/output-manager.cpp @@ -0,0 +1,252 @@ +/* + DisplayService - service providing access to a display for outputting frames + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "gui/display-service.hpp" + +extern "C" { +#include "common/interfacedescriptor.h" +} + + +namespace gui { + + + + namespace { // hidden local details of the service implementation.... + + + + /* ================== define an lumieraorg_Display instance ======================= */ + + LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0 + ,lumieraorg_DisplayFacade_descriptor + , NULL, NULL, NULL + , LUMIERA_INTERFACE_INLINE (name, "\323\343\324\023\064\216\120\201\073\056\366\020\110\263\060\023", + const char*, (LumieraInterface ifa), + { (void)ifa; return "Display"; } + ) + , LUMIERA_INTERFACE_INLINE (brief, "\305\026\070\133\033\357\014\202\203\270\174\072\341\256\226\235", + const char*, (LumieraInterface ifa), + { (void)ifa; return "UI Interface: service for outputting frames to a viewer or display"; } + ) + , LUMIERA_INTERFACE_INLINE (homepage, "\170\104\246\175\123\144\332\312\315\263\071\170\164\213\024\275", + const char*, (LumieraInterface ifa), + { (void)ifa; return "http://www.lumiera.org/develompent.html" ;} + ) + , LUMIERA_INTERFACE_INLINE (version, "\265\343\045\346\110\241\276\111\217\120\155\246\230\341\344\124", + const char*, (LumieraInterface ifa), + { (void)ifa; return "0.1~pre"; } + ) + , LUMIERA_INTERFACE_INLINE (author, "\302\027\122\045\301\166\046\236\257\253\144\035\105\166\070\103", + const char*, (LumieraInterface ifa), + { (void)ifa; return "Hermann Vosseler"; } + ) + , LUMIERA_INTERFACE_INLINE (email, "\074\013\020\161\075\135\302\265\260\000\301\147\116\355\035\261", + const char*, (LumieraInterface ifa), + { (void)ifa; return "Ichthyostega@web.de"; } + ) + , LUMIERA_INTERFACE_INLINE (copyright, "\037\232\153\100\114\103\074\342\164\132\370\210\372\164\115\275", + const char*, (LumieraInterface ifa), + { + (void)ifa; + return + "Copyright (C) Lumiera.org\n" + " 2009 Hermann Vosseler "; + } + ) + , 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::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 (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 diff --git a/src/proc/play/output-manager.hpp b/src/proc/play/output-manager.hpp new file mode 100644 index 000000000..1dec2c192 --- /dev/null +++ b/src/proc/play/output-manager.hpp @@ -0,0 +1,190 @@ +/* + DISPLAY-SERVICE.hpp - service providing access to a display for outputting frames + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/** @file display-service.hpp + ** A public service provided by the GUI, implementing the lumiera::Display facade interface. + ** It serves two purposes: + ** - It maintains a collection of DisplayerSlot objects, which are the actual connection points + ** and allow to receive frames and dispatch them to the GTK main event loop thread. + ** Conceptually, creating such a slot means providing a possible display for output. + ** - It provides the actual implementation of the Display facade interface, i.e. the function + ** which is to invoked periodically by the playback processes to dispose a new frame into + ** the display. + ** + ** This service is the implementation of a layer separation facade interface. This header defines + ** the interface used to \em provide this service, not to access it. Clients get a specific + ** LumieraDisplaySlot passed as parameter when initiating a playback process from the GUI. Using + ** this LumieraDisplaySlot handle, clients should then use lumiera::DummyPlayer#facade to access + ** an implementation instance of this service in order to push actual frames up. + ** + ** @see lumiera::Display + ** @see lumiera::DummyPlayer + ** @see gui::PlaybackController usage example + */ + + +#ifndef GUI_DISPLAY_SERVICE_H +#define GUI_DISPLAY_SERVICE_H + + +#include "include/display-facade.h" +#include "common/instancehandle.hpp" +#include "lib/singleton-ref.hpp" +#include "lib/scoped-ptrvect.hpp" + +#include +#include +#include +#include +#include + + +namespace gui { + + using std::string; + using std::vector; + using lumiera::Display; + using Glib::Dispatcher; + + + typedef sigc::slot FrameDestination; + typedef sigc::signal 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 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 implInstance_; + ServiceInstanceHandle serviceInstance_; + + + public: + DisplayService(); + ~DisplayService() { + INFO (proc_dbg, "Display service dying..."); + + } + + + /** open a new display, sending frames to the given output destination + * @return handle for this slot, can be used to start a play process. + * NULL handle in case of any error. */ + static LumieraDisplaySlot setUp (FrameDestination const&); + + + /** prepare and the given slot for output + * @param doAllocate allocate when true, else release it + * @throw lumiera::error::Logic when already in use */ + void allocate (LumieraDisplaySlot, bool doAllocate); + + + /** resolve the given display slot handle to yield a ref + * to an actual implementation object. In order to be resolvable, + * the DisplayerSlot needs to be locked (=allocated) for output use. */ + DisplayerSlot& resolve (LumieraDisplaySlot); + + }; + + + + + void + DisplayerSlot::put(LumieraDisplayFrame newFrame) + { + if (newFrame != currBuffer_) + { + currBuffer_ = newFrame; + dispatcher_.emit(); + } + else + { + TRACE (render, "frame dropped?"); + } + } + + + +} // namespace gui +#endif diff --git a/src/proc/play/play-controller.hpp b/src/proc/play/play-controller.hpp new file mode 100644 index 000000000..75e0f3d78 --- /dev/null +++ b/src/proc/play/play-controller.hpp @@ -0,0 +1,161 @@ +/* + DUMMY-PLAYER-SERVICE.hpp - service implementing a dummy test player + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/** @file dummy-player-service.hpp + ** A public service provided by the Proc-Layer, implementing a dummy/mockup playback process. + ** This is a design sketch; Lumiera isn't able to generate rendered output as of 2/2009. The + ** idea is, that for each ongoing calculation process, there is a ProcessImpl instance holding + ** the necessary handles and allocations and providing an uniform API to the client side. + ** Especially, this ProcessImpl holds a TickService, which generates periodic callbacks, and + ** it uses an output handle (functor) to push the generated frames up. + ** + ** This service is the implementation of a layer separation facade interface. Clients should use + ** proc::play::DummyPlayer#facade to access this service. This header defines the interface used + ** to \em provide this service, not to access it. + ** + ** @see lumiera::DummyPlayer + ** @see gui::PlaybackController usage example + */ + + +#ifndef PROC_DUMMYPLAYER_SERVICE_H +#define PROC_DUMMYPLAYER_SERVICE_H + + +#include "include/dummy-player-facade.h" +#include "include/display-facade.h" +#include "common/instancehandle.hpp" +#include "lib/singleton-ref.hpp" + +#include +#include +#include + + +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 imageGen_; + boost::scoped_ptr 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 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 diff --git a/src/proc/play/play-process.cpp b/src/proc/play/play-process.cpp new file mode 100644 index 000000000..ea443f709 --- /dev/null +++ b/src/proc/play/play-process.cpp @@ -0,0 +1,382 @@ +/* + DummyPlayerService - access point and service implementing a dummy test player + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "proc/play/dummy-player-service.hpp" +#include "proc/play/dummy-image-generator.hpp" +#include "proc/play/tick-service.hpp" +#include "lib/singleton.hpp" + +extern "C" { +#include "common/interfacedescriptor.h" +} + +#include +#include +#include +#include + + + +namespace proc { + namespace play{ + + using std::string; + using lumiera::Subsys; + using std::auto_ptr; + using boost::scoped_ptr; + using std::tr1::bind; + + + namespace { // hidden local details of the service implementation.... + + /** details of how the DummyPlayer service can be started + * and used as independent "subsystem" within main() */ + class DummyPlayerSubsysDescriptor + : public Subsys + { + operator string () const { return "Dummy-Player"; } + + + bool + shouldStart (lumiera::Option&) + { + return false; // for now the DummyPlayerService only comes "up" as dependency, + } // but doesn't start as a subsystem on it's own. + + bool + start (lumiera::Option&, Subsys::SigTerm terminationHandle) + { + ASSERT (!thePlayer_); + + thePlayer_.reset (new DummyPlayerService (terminationHandle)); + return true; + } + + /** manages the actual (single) instance of the player service impl */ + scoped_ptr 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 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 "; + } + ) + , 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::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 (_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 (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 (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 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 diff --git a/src/proc/play/play-process.hpp b/src/proc/play/play-process.hpp new file mode 100644 index 000000000..75e0f3d78 --- /dev/null +++ b/src/proc/play/play-process.hpp @@ -0,0 +1,161 @@ +/* + DUMMY-PLAYER-SERVICE.hpp - service implementing a dummy test player + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/** @file dummy-player-service.hpp + ** A public service provided by the Proc-Layer, implementing a dummy/mockup playback process. + ** This is a design sketch; Lumiera isn't able to generate rendered output as of 2/2009. The + ** idea is, that for each ongoing calculation process, there is a ProcessImpl instance holding + ** the necessary handles and allocations and providing an uniform API to the client side. + ** Especially, this ProcessImpl holds a TickService, which generates periodic callbacks, and + ** it uses an output handle (functor) to push the generated frames up. + ** + ** This service is the implementation of a layer separation facade interface. Clients should use + ** proc::play::DummyPlayer#facade to access this service. This header defines the interface used + ** to \em provide this service, not to access it. + ** + ** @see lumiera::DummyPlayer + ** @see gui::PlaybackController usage example + */ + + +#ifndef PROC_DUMMYPLAYER_SERVICE_H +#define PROC_DUMMYPLAYER_SERVICE_H + + +#include "include/dummy-player-facade.h" +#include "include/display-facade.h" +#include "common/instancehandle.hpp" +#include "lib/singleton-ref.hpp" + +#include +#include +#include + + +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 imageGen_; + boost::scoped_ptr 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 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 diff --git a/src/proc/play/play-service.cpp b/src/proc/play/play-service.cpp new file mode 100644 index 000000000..ea443f709 --- /dev/null +++ b/src/proc/play/play-service.cpp @@ -0,0 +1,382 @@ +/* + DummyPlayerService - access point and service implementing a dummy test player + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "proc/play/dummy-player-service.hpp" +#include "proc/play/dummy-image-generator.hpp" +#include "proc/play/tick-service.hpp" +#include "lib/singleton.hpp" + +extern "C" { +#include "common/interfacedescriptor.h" +} + +#include +#include +#include +#include + + + +namespace proc { + namespace play{ + + using std::string; + using lumiera::Subsys; + using std::auto_ptr; + using boost::scoped_ptr; + using std::tr1::bind; + + + namespace { // hidden local details of the service implementation.... + + /** details of how the DummyPlayer service can be started + * and used as independent "subsystem" within main() */ + class DummyPlayerSubsysDescriptor + : public Subsys + { + operator string () const { return "Dummy-Player"; } + + + bool + shouldStart (lumiera::Option&) + { + return false; // for now the DummyPlayerService only comes "up" as dependency, + } // but doesn't start as a subsystem on it's own. + + bool + start (lumiera::Option&, Subsys::SigTerm terminationHandle) + { + ASSERT (!thePlayer_); + + thePlayer_.reset (new DummyPlayerService (terminationHandle)); + return true; + } + + /** manages the actual (single) instance of the player service impl */ + scoped_ptr 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 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 "; + } + ) + , 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::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 (_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 (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 (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 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 diff --git a/src/proc/play/play-service.hpp b/src/proc/play/play-service.hpp new file mode 100644 index 000000000..75e0f3d78 --- /dev/null +++ b/src/proc/play/play-service.hpp @@ -0,0 +1,161 @@ +/* + DUMMY-PLAYER-SERVICE.hpp - service implementing a dummy test player + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/** @file dummy-player-service.hpp + ** A public service provided by the Proc-Layer, implementing a dummy/mockup playback process. + ** This is a design sketch; Lumiera isn't able to generate rendered output as of 2/2009. The + ** idea is, that for each ongoing calculation process, there is a ProcessImpl instance holding + ** the necessary handles and allocations and providing an uniform API to the client side. + ** Especially, this ProcessImpl holds a TickService, which generates periodic callbacks, and + ** it uses an output handle (functor) to push the generated frames up. + ** + ** This service is the implementation of a layer separation facade interface. Clients should use + ** proc::play::DummyPlayer#facade to access this service. This header defines the interface used + ** to \em provide this service, not to access it. + ** + ** @see lumiera::DummyPlayer + ** @see gui::PlaybackController usage example + */ + + +#ifndef PROC_DUMMYPLAYER_SERVICE_H +#define PROC_DUMMYPLAYER_SERVICE_H + + +#include "include/dummy-player-facade.h" +#include "include/display-facade.h" +#include "common/instancehandle.hpp" +#include "lib/singleton-ref.hpp" + +#include +#include +#include + + +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 imageGen_; + boost::scoped_ptr 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 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 diff --git a/src/proc/play/sound/jack-output.cpp b/src/proc/play/sound/jack-output.cpp new file mode 100644 index 000000000..96600bf3b --- /dev/null +++ b/src/proc/play/sound/jack-output.cpp @@ -0,0 +1,252 @@ +/* + DisplayService - service providing access to a display for outputting frames + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "gui/display-service.hpp" + +extern "C" { +#include "common/interfacedescriptor.h" +} + + +namespace gui { + + + + namespace { // hidden local details of the service implementation.... + + + + /* ================== define an lumieraorg_Display instance ======================= */ + + LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0 + ,lumieraorg_DisplayFacade_descriptor + , NULL, NULL, NULL + , LUMIERA_INTERFACE_INLINE (name, "\323\343\324\023\064\216\120\201\073\056\366\020\110\263\060\023", + const char*, (LumieraInterface ifa), + { (void)ifa; return "Display"; } + ) + , LUMIERA_INTERFACE_INLINE (brief, "\305\026\070\133\033\357\014\202\203\270\174\072\341\256\226\235", + const char*, (LumieraInterface ifa), + { (void)ifa; return "UI Interface: service for outputting frames to a viewer or display"; } + ) + , LUMIERA_INTERFACE_INLINE (homepage, "\170\104\246\175\123\144\332\312\315\263\071\170\164\213\024\275", + const char*, (LumieraInterface ifa), + { (void)ifa; return "http://www.lumiera.org/develompent.html" ;} + ) + , LUMIERA_INTERFACE_INLINE (version, "\265\343\045\346\110\241\276\111\217\120\155\246\230\341\344\124", + const char*, (LumieraInterface ifa), + { (void)ifa; return "0.1~pre"; } + ) + , LUMIERA_INTERFACE_INLINE (author, "\302\027\122\045\301\166\046\236\257\253\144\035\105\166\070\103", + const char*, (LumieraInterface ifa), + { (void)ifa; return "Hermann Vosseler"; } + ) + , LUMIERA_INTERFACE_INLINE (email, "\074\013\020\161\075\135\302\265\260\000\301\147\116\355\035\261", + const char*, (LumieraInterface ifa), + { (void)ifa; return "Ichthyostega@web.de"; } + ) + , LUMIERA_INTERFACE_INLINE (copyright, "\037\232\153\100\114\103\074\342\164\132\370\210\372\164\115\275", + const char*, (LumieraInterface ifa), + { + (void)ifa; + return + "Copyright (C) Lumiera.org\n" + " 2009 Hermann Vosseler "; + } + ) + , 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::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 (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 diff --git a/src/proc/play/sound/jack-output.hpp b/src/proc/play/sound/jack-output.hpp new file mode 100644 index 000000000..1dec2c192 --- /dev/null +++ b/src/proc/play/sound/jack-output.hpp @@ -0,0 +1,190 @@ +/* + DISPLAY-SERVICE.hpp - service providing access to a display for outputting frames + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/** @file display-service.hpp + ** A public service provided by the GUI, implementing the lumiera::Display facade interface. + ** It serves two purposes: + ** - It maintains a collection of DisplayerSlot objects, which are the actual connection points + ** and allow to receive frames and dispatch them to the GTK main event loop thread. + ** Conceptually, creating such a slot means providing a possible display for output. + ** - It provides the actual implementation of the Display facade interface, i.e. the function + ** which is to invoked periodically by the playback processes to dispose a new frame into + ** the display. + ** + ** This service is the implementation of a layer separation facade interface. This header defines + ** the interface used to \em provide this service, not to access it. Clients get a specific + ** LumieraDisplaySlot passed as parameter when initiating a playback process from the GUI. Using + ** this LumieraDisplaySlot handle, clients should then use lumiera::DummyPlayer#facade to access + ** an implementation instance of this service in order to push actual frames up. + ** + ** @see lumiera::Display + ** @see lumiera::DummyPlayer + ** @see gui::PlaybackController usage example + */ + + +#ifndef GUI_DISPLAY_SERVICE_H +#define GUI_DISPLAY_SERVICE_H + + +#include "include/display-facade.h" +#include "common/instancehandle.hpp" +#include "lib/singleton-ref.hpp" +#include "lib/scoped-ptrvect.hpp" + +#include +#include +#include +#include +#include + + +namespace gui { + + using std::string; + using std::vector; + using lumiera::Display; + using Glib::Dispatcher; + + + typedef sigc::slot FrameDestination; + typedef sigc::signal 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 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 implInstance_; + ServiceInstanceHandle serviceInstance_; + + + public: + DisplayService(); + ~DisplayService() { + INFO (proc_dbg, "Display service dying..."); + + } + + + /** open a new display, sending frames to the given output destination + * @return handle for this slot, can be used to start a play process. + * NULL handle in case of any error. */ + static LumieraDisplaySlot setUp (FrameDestination const&); + + + /** prepare and the given slot for output + * @param doAllocate allocate when true, else release it + * @throw lumiera::error::Logic when already in use */ + void allocate (LumieraDisplaySlot, bool doAllocate); + + + /** resolve the given display slot handle to yield a ref + * to an actual implementation object. In order to be resolvable, + * the DisplayerSlot needs to be locked (=allocated) for output use. */ + DisplayerSlot& resolve (LumieraDisplaySlot); + + }; + + + + + void + DisplayerSlot::put(LumieraDisplayFrame newFrame) + { + if (newFrame != currBuffer_) + { + currBuffer_ = newFrame; + dispatcher_.emit(); + } + else + { + TRACE (render, "frame dropped?"); + } + } + + + +} // namespace gui +#endif