]> git.sesse.net Git - casparcg/commitdiff
2.0.0.2:
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Sun, 16 Jan 2011 15:42:56 +0000 (15:42 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Sun, 16 Jan 2011 15:42:56 +0000 (15:42 +0000)
   - Pause and play works properly.
   - Logging command name.
   - Added new commands for adding and removing consumers at run-time.

git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@372 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

29 files changed:
core/channel.cpp
core/channel.h
core/consumer/bluefish/bluefish_consumer.cpp
core/consumer/bluefish/bluefish_consumer.h
core/consumer/bluefish/memory.h
core/consumer/bluefish/util.h
core/consumer/decklink/decklink_consumer.cpp
core/consumer/decklink/decklink_consumer.h
core/consumer/decklink/util.h
core/consumer/ffmpeg/ffmpeg_consumer.cpp
core/consumer/ffmpeg/ffmpeg_consumer.h
core/consumer/frame_consumer.h
core/consumer/frame_consumer_device.cpp
core/consumer/frame_consumer_device.h
core/consumer/oal/oal_consumer.cpp
core/consumer/oal/oal_consumer.h
core/consumer/ogl/ogl_consumer.cpp
core/consumer/ogl/ogl_consumer.h
core/producer/decklink/decklink_producer.cpp
core/producer/layer.cpp
protocol/amcp/AMCPCommand.h
protocol/amcp/AMCPCommandQueue.cpp
protocol/amcp/AMCPCommandsImpl.cpp
protocol/amcp/AMCPCommandsImpl.h
protocol/amcp/AMCPProtocolStrategy.cpp
protocol/cii/CIIProtocolStrategy.cpp
protocol/media.cpp
protocol/media.h
shell/boostrapper.cpp

index 837bd8e3b369560b57a2f56e00388ce47c1a6073..9d6a469a9e43026aea6afb4c752656995667ffb5 100644 (file)
@@ -21,9 +21,7 @@
 namespace caspar { namespace core {\r
 \r
 struct channel::implementation : boost::noncopyable\r
-{      \r
-       mutable executor executor_;\r
-                               \r
+{                                      \r
        const safe_ptr<frame_processor_device> processor_device_;\r
        frame_consumer_device consumer_device_;\r
                                                \r
@@ -31,11 +29,13 @@ struct channel::implementation : boost::noncopyable
 \r
        const video_format_desc format_desc_;\r
 \r
+       mutable executor executor_;\r
+\r
 public:\r
-       implementation(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers)  \r
+       implementation(const video_format_desc& format_desc)  \r
                : format_desc_(format_desc)\r
                , processor_device_(frame_processor_device(format_desc))\r
-               , consumer_device_(format_desc, consumers)\r
+               , consumer_device_(format_desc)\r
        {\r
                executor_.start();\r
                executor_.begin_invoke([=]{tick();});\r
@@ -66,8 +66,19 @@ public:
                return draw_frame(frames);\r
        }\r
 \r
+       void add(int index, const safe_ptr<frame_consumer>& consumer)\r
+       {\r
+               consumer_device_.add(index, consumer);\r
+       }\r
+       \r
+       void remove(int index)\r
+       {\r
+               consumer_device_.remove(index);\r
+       }\r
+\r
        void load(int index, const safe_ptr<frame_producer>& producer, bool play_on_load)\r
        {\r
+               CASPAR_LOG(trace) << executor_.size();\r
                producer->initialize(processor_device_);\r
                executor_.begin_invoke([=]\r
                {\r
@@ -161,7 +172,9 @@ public:
 };\r
 \r
 channel::channel(channel&& other) : impl_(std::move(other.impl_)){}\r
-channel::channel(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers) : impl_(new implementation(format_desc, consumers)){}\r
+channel::channel(const video_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
+void channel::add(int index, const safe_ptr<frame_consumer>& consumer){impl_->add(index, consumer);}\r
+void channel::remove(int index){impl_->remove(index);}\r
 void channel::load(int index, const safe_ptr<frame_producer>& producer, bool play_on_load){impl_->load(index, producer, play_on_load);}\r
 void channel::preview(int index, const safe_ptr<frame_producer>& producer){impl_->preview(index, producer);}\r
 void channel::pause(int index){impl_->pause(index);}\r
index 397f78c5b47e25e4edaefa181fe913df1b34303a..5c69f05ecda062b1e0cbf37069f2b99f663b1174 100644 (file)
@@ -23,9 +23,12 @@ namespace caspar { namespace core {
 class channel : boost::noncopyable\r
 {\r
 public:\r
-       explicit channel(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers);\r
+       explicit channel(const video_format_desc& format_desc);\r
        channel(channel&& other);\r
        \r
+       void add(int index, const safe_ptr<frame_consumer>& consumer);\r
+       void remove(int index);\r
+\r
        void load(int index, const safe_ptr<frame_producer>& producer, bool play_on_load = false);\r
        void preview(int index, const safe_ptr<frame_producer>& producer);\r
        void pause(int index);\r
index acfe21db8dc4dc6c9191a0a38ee2a3e69f4af267..b6c88293327e905508c10ba9bb806e553f4b0653 100644 (file)
@@ -39,7 +39,7 @@
 \r
 #include <memory>\r
 \r
-namespace caspar { namespace core { namespace bluefish {\r
+namespace caspar { namespace core {\r
        \r
 CBlueVelvet4* (*BlueVelvetFactory4)();\r
 BLUE_UINT32 (*encode_hanc_frame)(struct hanc_stream_info_struct * hanc_stream_ptr, void * audio_pcm_ptr,BLUE_UINT32 no_audio_ch,BLUE_UINT32 no_audio_samples,BLUE_UINT32 nTypeOfSample,BLUE_UINT32 emb_audio_flag);\r
@@ -78,7 +78,7 @@ void blue_initialize()
        blue_hanc_initialize();\r
 }\r
                \r
-struct consumer::implementation : boost::noncopyable\r
+struct bluefish_consumer::implementation : boost::noncopyable\r
 {\r
        boost::unique_future<void> active_;\r
        executor executor_;\r
@@ -319,8 +319,29 @@ public:
        }\r
 };\r
 \r
-consumer::consumer(consumer&& other) : impl_(std::move(other.impl_)){}\r
-consumer::consumer(const video_format_desc& format_desc, unsigned int device_index, bool embed_audio) : impl_(new implementation(format_desc, device_index, embed_audio)){}    \r
-void consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
-size_t consumer::buffer_depth() const{return impl_->buffer_depth();}\r
-}}}
\ No newline at end of file
+bluefish_consumer::bluefish_consumer(bluefish_consumer&& other) : impl_(std::move(other.impl_)){}\r
+bluefish_consumer::bluefish_consumer(const video_format_desc& format_desc, unsigned int device_index, bool embed_audio) : impl_(new implementation(format_desc, device_index, embed_audio)){}  \r
+void bluefish_consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
+size_t bluefish_consumer::buffer_depth() const{return impl_->buffer_depth();}\r
+       \r
+safe_ptr<frame_consumer> create_bluefish_consumer(const std::vector<std::wstring>& params)\r
+{\r
+       if(params.size() < 2 || params[0] != L"BLUEFISH")\r
+               return frame_consumer::empty();\r
+\r
+       auto format_desc = video_format_desc::get(params[1]);\r
+       if(format_desc.format == video_format::invalid)\r
+               return frame_consumer::empty();\r
+       \r
+       int device_index = 1;\r
+       bool embed_audio = false;\r
+\r
+       try{device_index = boost::lexical_cast<int>(params[2]);}\r
+       catch(boost::bad_lexical_cast&){}\r
+       try{embed_audio = boost::lexical_cast<bool>(params[3]);}\r
+       catch(boost::bad_lexical_cast&){}\r
+\r
+       return make_safe<bluefish_consumer>(format_desc, device_index, embed_audio);\r
+}\r
+\r
+}}
\ No newline at end of file
index f234c4ac70abfde07e74e49d844436cae70a2ffa..becce912f7eeef3c1dc6afb22af27eb76bb45ef4 100644 (file)
 #include "../../video_format.h"\r
 #include "../../consumer/frame_consumer.h"\r
 \r
-namespace caspar { namespace core { namespace bluefish {\r
+namespace caspar { namespace core {\r
        \r
 struct bluefish_exception : public caspar_exception{};\r
 \r
-class consumer : public frame_consumer\r
+class bluefish_consumer : public frame_consumer\r
 {\r
 public:\r
-       explicit consumer(const video_format_desc& format_desc, unsigned int device_index, bool embed_audio = false);\r
-       consumer(consumer&& other);\r
+       explicit bluefish_consumer(const video_format_desc& format_desc, unsigned int device_index, bool embed_audio = false);\r
+       bluefish_consumer(bluefish_consumer&& other);\r
        \r
        virtual void send(const safe_ptr<const read_frame>&);\r
        virtual size_t buffer_depth() const;\r
@@ -38,6 +38,7 @@ private:
        struct implementation;\r
        std::shared_ptr<implementation> impl_;\r
 };\r
-typedef std::tr1::shared_ptr<consumer> BlueFishFrameConsumerPtr;\r
+       \r
+safe_ptr<frame_consumer> create_bluefish_consumer(const std::vector<std::wstring>& params);\r
 \r
-}}}\r
+}}\r
index 57555b2904ba8d61202f20703c21db57f62be60c..234b2bfdf8a5cbe2e261520b20c5a33b40906cb7 100644 (file)
@@ -9,7 +9,7 @@
 \r
 #include <vector>\r
 \r
-namespace caspar { namespace core { namespace bluefish {\r
+namespace caspar { namespace core {\r
        \r
 static const size_t MAX_HANC_BUFFER_SIZE = 256*1024;\r
 static const size_t MAX_VBI_BUFFER_SIZE = 36*1920*4;\r
@@ -41,4 +41,4 @@ private:
 };\r
 typedef std::shared_ptr<blue_dma_buffer> blue_dma_buffer_ptr;\r
 \r
-}}}
\ No newline at end of file
+}}
\ No newline at end of file
index cad5c6fc0c4434b9f7577fdb546ec6c2a2f2e3a7..97171313b1d06e423a05d888c4b36ed900b2e3b8 100644 (file)
@@ -3,7 +3,7 @@
 #include <BlueVelvet4.h>\r
 #include "../../video_format.h"\r
 \r
-namespace caspar { namespace core { namespace bluefish {\r
+namespace caspar { namespace core {\r
        \r
 inline bool is_epoch_card(int card_type)\r
 {\r
@@ -92,4 +92,4 @@ inline int set_card_property(const std::shared_ptr<CBlueVelvet4> pSdk, ULONG pro
        return set_card_property(pSdk.get(), prop, value);\r
 }\r
 \r
-}}}
\ No newline at end of file
+}}
\ No newline at end of file
index b7759834d4c4731612f09ac48c4d85e2c87c879a..4313b984af97c6cc9f1b331dda4ab5afaa6f1da8 100644 (file)
@@ -46,7 +46,7 @@
 \r
 #pragma warning(push)\r
 \r
-namespace caspar { namespace core { namespace decklink{\r
+namespace caspar { namespace core {\r
        \r
 struct decklink_consumer::implementation : public IDeckLinkVideoOutputCallback, public IDeckLinkAudioOutputCallback, boost::noncopyable\r
 {              \r
@@ -256,4 +256,27 @@ decklink_consumer::decklink_consumer(decklink_consumer&& other) : impl_(std::mov
 void decklink_consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
 size_t decklink_consumer::buffer_depth() const{return impl_->buffer_depth();}\r
        \r
-}}}    
\ No newline at end of file
+safe_ptr<frame_consumer> create_decklink_consumer(const std::vector<std::wstring>& params)\r
+{\r
+       if(params.size() < 2 || params[0] != L"DECKLINK")\r
+               return frame_consumer::empty();\r
+\r
+       auto format_desc = video_format_desc::get(params[1]);\r
+       if(format_desc.format == video_format::invalid)\r
+               return frame_consumer::empty();\r
+\r
+       int device_index = 1;\r
+       bool embed_audio = false;\r
+       bool internal_key = false;\r
+\r
+       try{device_index = boost::lexical_cast<int>(params[2]);}\r
+       catch(boost::bad_lexical_cast&){}\r
+       try{embed_audio = boost::lexical_cast<bool>(params[3]);}\r
+       catch(boost::bad_lexical_cast&){}\r
+       try{internal_key = boost::lexical_cast<bool>(params[4]);}\r
+       catch(boost::bad_lexical_cast&){}\r
+\r
+       return make_safe<decklink_consumer>(format_desc, device_index, embed_audio, internal_key);\r
+}\r
+\r
+}}
\ No newline at end of file
index 783d51d1ac70fa5e606649fa04eebb91088595c3..3e0d252c05b2a8b09cd3ef4e2703def56860f164 100644 (file)
@@ -23,7 +23,7 @@
 \r
 #include "../../video_format.h"\r
 \r
-namespace caspar { namespace core { namespace decklink {\r
+namespace caspar { namespace core {\r
 \r
 class decklink_consumer : public frame_consumer\r
 {\r
@@ -38,4 +38,7 @@ private:
        std::tr1::shared_ptr<implementation> impl_;\r
 };\r
 \r
-}}}
\ No newline at end of file
+safe_ptr<frame_consumer> create_decklink_consumer(const std::vector<std::wstring>& params);\r
+\r
+\r
+}}
\ No newline at end of file
index 0f11201e621f0808fb8de9ac6420b5a474da281b..c1a8ed05fd446d9ae42bdd722b6b5e14ff3dbdd9 100644 (file)
@@ -4,7 +4,7 @@
 \r
 #include "DeckLinkAPI_h.h"\r
 \r
-namespace caspar { namespace core { namespace decklink {\r
+namespace caspar { namespace core {\r
        \r
 static BMDDisplayMode GetDecklinkVideoFormat(video_format::type fmt) \r
 {\r
@@ -51,4 +51,4 @@ static IDeckLinkDisplayMode* get_display_mode(IDeckLinkOutput* output, video_for
        return get_display_mode(output, GetDecklinkVideoFormat(fmt));\r
 }\r
 \r
-}}}
\ No newline at end of file
+}}
\ No newline at end of file
index 4fb8a9e0cd76d1969b96e0d587c1659c368e9608..11abde4255d9cbadcbcca6aa08435501d4c9a2ff 100644 (file)
@@ -26,6 +26,7 @@
 \r
 #include <common/concurrency/executor.h>\r
 #include <common/utility/string_convert.h>\r
+#include <common/env.h>\r
 \r
 #include <boost/thread/once.hpp>\r
 \r
@@ -49,9 +50,9 @@ extern "C"
 #pragma warning (pop)\r
 #endif\r
 \r
-namespace caspar { namespace core { namespace ffmpeg {\r
+namespace caspar { namespace core {\r
        \r
-struct consumer::implementation : boost::noncopyable\r
+struct ffmpeg_consumer::implementation : boost::noncopyable\r
 {              \r
        executor executor_;\r
        const std::string filename_;\r
@@ -76,10 +77,10 @@ struct consumer::implementation : boost::noncopyable
        implementation(const video_format_desc& format_desc, const std::string& filename)\r
                : filename_(filename)\r
                , format_desc_(format_desc)\r
-               , audio_st_(0)\r
-               , video_st_(0)\r
-               , fmt_(0)\r
-               , img_convert_ctx_(0)\r
+               , audio_st_(nullptr)\r
+               , video_st_(nullptr)\r
+               , fmt_(nullptr)\r
+               , img_convert_ctx_(nullptr)\r
                , video_outbuf_(format_desc.size)\r
                , audio_outbuf_(48000)\r
        {\r
@@ -118,8 +119,7 @@ struct consumer::implementation : boost::noncopyable
                if (fmt_->audio_codec != CODEC_ID_NONE) \r
                        audio_st_ = add_audio_stream(fmt_->audio_codec);        \r
 \r
-               // Set the output parameters (must be done even if no parameters).\r
-               \r
+               // Set the output parameters (must be done even if no parameters).              \r
                int errn = 0;\r
                if ((errn = -av_set_parameters(oc_.get(), nullptr)) > 0)\r
                        BOOST_THROW_EXCEPTION(\r
@@ -165,6 +165,8 @@ struct consumer::implementation : boost::noncopyable
 \r
        ~implementation()\r
        {    \r
+               executor_.stop();\r
+\r
                av_write_trailer(oc_.get());\r
 \r
                // Close each codec.\r
@@ -383,9 +385,21 @@ struct consumer::implementation : boost::noncopyable
        size_t buffer_depth() const { return 1; }\r
 };\r
 \r
-consumer::consumer(const video_format_desc& format_desc, const std::wstring& filename) : impl_(new implementation(format_desc, narrow(filename))){}\r
-consumer::consumer(consumer&& other) : impl_(std::move(other.impl_)){}\r
-void consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
-size_t consumer::buffer_depth() const{return impl_->buffer_depth();}\r
+ffmpeg_consumer::ffmpeg_consumer(const video_format_desc& format_desc, const std::wstring& filename) : impl_(new implementation(format_desc, narrow(filename))){}\r
+ffmpeg_consumer::ffmpeg_consumer(ffmpeg_consumer&& other) : impl_(std::move(other.impl_)){}\r
+void ffmpeg_consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
+size_t ffmpeg_consumer::buffer_depth() const{return impl_->buffer_depth();}\r
+\r
+safe_ptr<frame_consumer> create_ffmpeg_consumer(const std::vector<std::wstring>& params)\r
+{\r
+       if(params.size() < 3 || params[0] != L"FILE")\r
+               return frame_consumer::empty();\r
+\r
+       auto format_desc = video_format_desc::get(params[1]);\r
+       if(format_desc.format == video_format::invalid)\r
+               return frame_consumer::empty();\r
+\r
+       return make_safe<ffmpeg_consumer>(format_desc, env::media_folder() + params[2]);\r
+}\r
 \r
-}}}\r
+}}\r
index 3dc70c3d326ec09c1af8d4d8c36045a7e6ac03ef..c9430dd409e82e93f5654fcd1f981956f8b53b48 100644 (file)
 #include "../../video_format.h"\r
 #include "../../consumer/frame_consumer.h"\r
 \r
-namespace caspar { namespace core { namespace ffmpeg {\r
+namespace caspar { namespace core {\r
        \r
-class consumer : public frame_consumer\r
+class ffmpeg_consumer : public frame_consumer\r
 {\r
 public:        \r
-       explicit consumer(const video_format_desc& format_desc, const std::wstring& filename);\r
-       consumer(consumer&& other);\r
+       explicit ffmpeg_consumer(const video_format_desc& format_desc, const std::wstring& filename);\r
+       ffmpeg_consumer(ffmpeg_consumer&& other);\r
        \r
        virtual void send(const safe_ptr<const read_frame>&);\r
        virtual size_t buffer_depth() const;\r
@@ -37,4 +37,6 @@ private:
        std::shared_ptr<implementation> impl_;\r
 };\r
 \r
-}}}
\ No newline at end of file
+safe_ptr<frame_consumer> create_ffmpeg_consumer(const std::vector<std::wstring>& params);\r
+\r
+}}
\ No newline at end of file
index 48b7de41170837582e8d6ec35657c605c5ed38ae..14a68c909db07bb46b7aadfb6bb185d2a790316a 100644 (file)
@@ -30,9 +30,20 @@ class read_frame;
 struct frame_consumer : boost::noncopyable\r
 {\r
        virtual ~frame_consumer() {}\r
-\r
+       \r
        virtual void send(const safe_ptr<const read_frame>& frame) = 0;\r
        virtual size_t buffer_depth() const = 0;\r
+\r
+       static safe_ptr<frame_consumer> empty()\r
+       {\r
+               struct empty_frame_consumer : public frame_consumer\r
+               {\r
+                       virtual void send(const safe_ptr<const read_frame>&){}\r
+                       virtual size_t buffer_depth() const{return 0;}\r
+               };\r
+               static safe_ptr<frame_consumer> consumer = make_safe<empty_frame_consumer>();\r
+               return consumer;\r
+       }\r
 };\r
 \r
 }}
\ No newline at end of file
index 56050d008d0a794ad1563b3f3a0c07d3933bcef7..832df0b07e0445f60778aa1f2437a45bf7945e10 100644 (file)
@@ -19,34 +19,50 @@ namespace caspar { namespace core {
        \r
 struct frame_consumer_device::implementation\r
 {\r
+       static int const MAX_DEPTH = 3;\r
+\r
        timer clock_;\r
        executor executor_;     \r
 \r
        boost::circular_buffer<safe_ptr<const read_frame>> buffer_;\r
 \r
-       std::list<safe_ptr<frame_consumer>> consumers_; // Valid iterators after erase\r
+       std::map<int, std::shared_ptr<frame_consumer>> consumers_; // Valid iterators after erase\r
        \r
        const video_format_desc fmt_;\r
 \r
 public:\r
-       implementation(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers) \r
-               : consumers_(consumers.begin(), consumers.end())\r
-               , fmt_(format_desc)\r
+       implementation(const video_format_desc& format_desc) : fmt_(format_desc)\r
        {               \r
-               if(consumers_.empty())\r
-                       BOOST_THROW_EXCEPTION(invalid_argument() << msg_info("No consumer."));\r
-\r
-               std::vector<size_t> depths;\r
-               boost::range::transform(consumers_, std::back_inserter(depths), std::mem_fn(&frame_consumer::buffer_depth));\r
-               buffer_.set_capacity(*boost::range::max_element(depths));\r
                executor_.set_capacity(3);\r
                executor_.start();\r
        }\r
+\r
+       void add(int index, const safe_ptr<frame_consumer>& consumer)\r
+       {               \r
+               executor_.invoke([&]\r
+               {\r
+                       if(buffer_.capacity() < consumer->buffer_depth())\r
+                               buffer_.set_capacity(consumer->buffer_depth());\r
+                       consumers_[index] = consumer;\r
+               });\r
+       }\r
+\r
+       void remove(int index)\r
+       {\r
+               executor_.invoke([&]\r
+               {\r
+                       auto it = consumers_.find(index);\r
+                       if(it != consumers_.end())\r
+                               consumers_.erase(it);\r
+               });\r
+       }\r
                        \r
        void consume(safe_ptr<const read_frame>&& frame)\r
        {               \r
                executor_.begin_invoke([=]\r
-               {\r
+               {       \r
+                       clock_.tick(1.0/fmt_.fps);\r
+\r
                        buffer_.push_back(std::move(frame));\r
 \r
                        if(!buffer_.full())\r
@@ -57,7 +73,7 @@ public:
                        {\r
                                try\r
                                {\r
-                                       (*it)->send(buffer_[(*it)->buffer_depth()-1]);\r
+                                       it->second->send(buffer_[it->second->buffer_depth()-1]);\r
                                        ++it;\r
                                }\r
                                catch(...)\r
@@ -67,13 +83,13 @@ public:
                                        CASPAR_LOG(warning) << "Removed consumer from frame_consumer_device.";\r
                                }\r
                        }\r
-       \r
-                       clock_.tick(1.0/fmt_.fps);\r
                });\r
        }\r
 };\r
 \r
 frame_consumer_device::frame_consumer_device(frame_consumer_device&& other) : impl_(std::move(other.impl_)){}\r
-frame_consumer_device::frame_consumer_device(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers) : impl_(new implementation(format_desc, consumers)){}\r
+frame_consumer_device::frame_consumer_device(const video_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
+void frame_consumer_device::add(int index, const safe_ptr<frame_consumer>& consumer){impl_->add(index, consumer);}\r
+void frame_consumer_device::remove(int index){impl_->remove(index);}\r
 void frame_consumer_device::consume(safe_ptr<const read_frame>&& future_frame) { impl_->consume(std::move(future_frame)); }\r
 }}
\ No newline at end of file
index c978c505d36a89ded2692c0da344c39de0ac3492..6d372e6045a525d567f6749dbb3c0139ad165f8d 100644 (file)
@@ -16,8 +16,11 @@ struct video_format_desc;
 class frame_consumer_device : boost::noncopyable\r
 {\r
 public:\r
-       explicit frame_consumer_device(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers);\r
+       explicit frame_consumer_device(const video_format_desc& format_desc);\r
        frame_consumer_device(frame_consumer_device&& other);\r
+\r
+       void add(int index, const safe_ptr<frame_consumer>& consumer);\r
+       void remove(int index);\r
        void consume(safe_ptr<const read_frame>&& future_frame); // nothrow\r
 private:\r
        struct implementation;\r
index a5852fc745cc2df41b5dcfef21ea7ffc03da3b8f..ad4fe2ac41e197104cdd618d7e4998282fba6075 100644 (file)
 \r
 #include <boost/circular_buffer.hpp>\r
 \r
-namespace caspar { namespace core { namespace oal {    \r
+namespace caspar { namespace core {\r
 \r
-struct consumer::implementation : public sf::SoundStream, boost::noncopyable\r
+struct oal_consumer::implementation : public sf::SoundStream, boost::noncopyable\r
 {\r
        tbb::concurrent_bounded_queue<std::vector<short>> input_;\r
        boost::circular_buffer<std::vector<short>> container_;\r
-\r
+       tbb::atomic<bool> is_running_;\r
 public:\r
        implementation() \r
                : container_(5)\r
        {\r
+               is_running_ = true;\r
                sf::SoundStream::Initialize(2, 48000);\r
                Play();         \r
+               CASPAR_LOG(info) << "Sucessfully started oal_consumer";\r
+       }\r
+\r
+       ~implementation()\r
+       {\r
+               is_running_ = false;\r
+               input_.try_push(std::vector<short>());\r
+               input_.try_push(std::vector<short>());\r
+               CASPAR_LOG(info) << "Sucessfully ended oal_consumer";\r
        }\r
        \r
        virtual void send(const safe_ptr<const read_frame>& frame)\r
@@ -64,12 +74,24 @@ public:
                data.Samples = container_.back().data();\r
                data.NbSamples = container_.back().size();              \r
 \r
-               return true;\r
+               return is_running_;\r
        }\r
 };\r
 \r
-consumer::consumer(consumer&& other) : impl_(std::move(other.impl_)){}\r
-consumer::consumer(const video_format_desc&) : impl_(new implementation()){}\r
-void consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
-size_t consumer::buffer_depth() const{return impl_->buffer_depth();}\r
-}}}\r
+oal_consumer::oal_consumer(oal_consumer&& other) : impl_(std::move(other.impl_)){}\r
+oal_consumer::oal_consumer(const video_format_desc&) : impl_(new implementation()){}\r
+void oal_consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
+size_t oal_consumer::buffer_depth() const{return impl_->buffer_depth();}\r
+\r
+safe_ptr<frame_consumer> create_oal_consumer(const std::vector<std::wstring>& params)\r
+{\r
+       if(params.size() < 2 || params[0] != L"OAL")\r
+               return frame_consumer::empty();\r
+\r
+       auto format_desc = video_format_desc::get(params[1]);\r
+       if(format_desc.format == video_format::invalid)\r
+               return frame_consumer::empty();\r
+\r
+       return make_safe<oal_consumer>(format_desc);\r
+}\r
+}}\r
index f4a7fb31695105171a5c82782846fd5cf5885185..2d3468bc29b337d039438d3e80110178ae0a3972 100644 (file)
 #include "../../video_format.h"\r
 #include "../../consumer/frame_consumer.h"\r
 \r
-namespace caspar { namespace core { namespace oal {\r
+namespace caspar { namespace core {\r
        \r
-class consumer : public frame_consumer\r
+class oal_consumer : public frame_consumer\r
 {\r
 public:        \r
-       explicit consumer(const video_format_desc& format_desc);\r
-       consumer(consumer&& other);\r
+       explicit oal_consumer(const video_format_desc& format_desc);\r
+       oal_consumer(oal_consumer&& other);\r
        \r
        virtual void send(const safe_ptr<const read_frame>&);\r
        virtual size_t buffer_depth() const;\r
@@ -37,4 +37,6 @@ private:
        std::shared_ptr<implementation> impl_;\r
 };\r
 \r
-}}}
\ No newline at end of file
+safe_ptr<frame_consumer> create_oal_consumer(const std::vector<std::wstring>& params);\r
+\r
+}}
\ No newline at end of file
index 6aa464851d10ae8809feeb9292f569a56354ac9b..ad243773a10db6d84a442b916388b2e419e6729e 100644 (file)
@@ -38,9 +38,9 @@
 \r
 #include <algorithm>\r
 \r
-namespace caspar { namespace core { namespace ogl{     \r
+namespace caspar { namespace core {\r
 \r
-struct consumer::implementation : boost::noncopyable\r
+struct ogl_consumer::implementation : boost::noncopyable\r
 {                      \r
        boost::unique_future<void> active_;\r
        executor executor_;\r
@@ -128,11 +128,11 @@ public:
                        hratio_ = static_cast<float>(format_desc_.height)/static_cast<float>(format_desc_.height);\r
 \r
                        std::pair<float, float> target_ratio = None();\r
-                       if(stretch_ == ogl::fill)\r
+                       if(stretch_ == fill)\r
                                target_ratio = Fill();\r
-                       else if(stretch_ == ogl::uniform)\r
+                       else if(stretch_ == uniform)\r
                                target_ratio = Uniform();\r
-                       else if(stretch_ == ogl::uniform_to_fill)\r
+                       else if(stretch_ == uniform_to_fill)\r
                                target_ratio = UniformToFill();\r
 \r
                        wSize_ = target_ratio.first;\r
@@ -156,6 +156,13 @@ public:
                        glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);\r
                });\r
                active_ = executor_.begin_invoke([]{});\r
+\r
+               CASPAR_LOG(info) << "Sucessfully started ogl_consumer";\r
+       }\r
+\r
+       ~implementation()\r
+       {\r
+               CASPAR_LOG(info) << "Sucessfully ended ogl_consumer";\r
        }\r
        \r
        std::pair<float, float> None()\r
@@ -240,8 +247,30 @@ public:
        virtual size_t buffer_depth() const{return 2;}\r
 };\r
 \r
-consumer::consumer(consumer&& other) : impl_(std::move(other.impl_)){}\r
-consumer::consumer(const video_format_desc& format_desc, unsigned int screen_index, stretch stretch, bool windowed) : impl_(new implementation(format_desc, screen_index, stretch, windowed)){}\r
-void consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
-size_t consumer::buffer_depth() const{return impl_->buffer_depth();}\r
-}}}\r
+ogl_consumer::ogl_consumer(ogl_consumer&& other) : impl_(std::move(other.impl_)){}\r
+ogl_consumer::ogl_consumer(const video_format_desc& format_desc, unsigned int screen_index, stretch stretch, bool windowed) : impl_(new implementation(format_desc, screen_index, stretch, windowed)){}\r
+void ogl_consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
+size_t ogl_consumer::buffer_depth() const{return impl_->buffer_depth();}\r
+\r
+safe_ptr<frame_consumer> create_ogl_consumer(const std::vector<std::wstring>& params)\r
+{\r
+       if(params.size() < 2 || params[0] != L"OGL")\r
+               return frame_consumer::empty();\r
+\r
+       auto format_desc = video_format_desc::get(params[1]);\r
+       if(format_desc.format == video_format::invalid)\r
+               return frame_consumer::empty();\r
+\r
+       unsigned int screen_index = 0;\r
+       stretch stretch = stretch::fill;\r
+       bool windowed = true;\r
+       \r
+       try{screen_index = boost::lexical_cast<int>(params[2]);}\r
+       catch(boost::bad_lexical_cast&){}\r
+       try{windowed = boost::lexical_cast<bool>(params[3]);}\r
+       catch(boost::bad_lexical_cast&){}\r
+\r
+       return make_safe<ogl_consumer>(format_desc, screen_index, stretch, windowed);\r
+}\r
+\r
+}}\r
index 7ba0f8243fbca71e9dd4dacc461cb61805b27fa6..3d0c6042fd066fbf795818d29bb8755eb9aa93f2 100644 (file)
@@ -22,7 +22,7 @@
 #include "../../consumer/frame_consumer.h"\r
 #include "../../video_format.h"\r
 \r
-namespace caspar { namespace core { namespace ogl {\r
+namespace caspar { namespace core {\r
 \r
 struct ogl_error : virtual caspar_exception{};\r
 \r
@@ -34,11 +34,11 @@ enum stretch
        uniform_to_fill\r
 };\r
 \r
-class consumer : public frame_consumer\r
+class ogl_consumer : public frame_consumer\r
 {\r
 public:        \r
-       explicit consumer(const video_format_desc& format_desc, unsigned int screen_index = 0, stretch stretch = stretch::fill, bool windowed = false);\r
-       consumer(consumer&& other);\r
+       explicit ogl_consumer(const video_format_desc& format_desc, unsigned int screen_index = 0, stretch stretch = stretch::fill, bool windowed = false);\r
+       ogl_consumer(ogl_consumer&& other);\r
        \r
        virtual void send(const safe_ptr<const read_frame>&);\r
        virtual size_t buffer_depth() const;\r
@@ -47,4 +47,6 @@ private:
        std::shared_ptr<implementation> impl_;\r
 };\r
 \r
-}}}
\ No newline at end of file
+safe_ptr<frame_consumer> create_ogl_consumer(const std::vector<std::wstring>& params);\r
+\r
+}}
\ No newline at end of file
index 279ebea14a47307ce859f61bbc57fe4e5937ec83..1cf2d4fa0a15fea4604b74aada6193d4d83eaca8 100644 (file)
@@ -94,7 +94,7 @@ public:
                if(pModelName != nullptr)\r
                        CASPAR_LOG(info) << "decklink_producer: Modelname: " << pModelName;\r
                \r
-               unsigned long decklinkVideoFormat = decklink::GetDecklinkVideoFormat(format_desc_.format);\r
+               unsigned long decklinkVideoFormat = GetDecklinkVideoFormat(format_desc_.format);\r
                if(decklinkVideoFormat == ULONG_MAX) \r
                        BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("decklink_producer: Card does not support requested videoformat."));\r
 \r
index 22dfc521849537f73676828d2d9ae665e29612e2..b86519cd3375d46939c6b4bdcc6f71ca0098349a 100644 (file)
@@ -50,11 +50,15 @@ public:
        \r
        void play()\r
        {                       \r
-               background_->set_leading_producer(foreground_);\r
-               foreground_ = background_;\r
-               background_ = frame_producer::empty();\r
-               is_paused_ = false;\r
-               CASPAR_LOG(info) << print() << L" background => foreground";\r
+               if(is_paused_)                  \r
+                       is_paused_ = false;\r
+               else\r
+               {\r
+                       background_->set_leading_producer(foreground_);\r
+                       foreground_ = background_;\r
+                       background_ = frame_producer::empty();\r
+                       CASPAR_LOG(info) << print() << L" background => foreground";\r
+               }\r
        }\r
 \r
        void pause()\r
index b5119b3d66eff9bdaa0a2caede449a29353256f6..a2d384f331acf6b2da2701b7fd70e18aef259a68 100644 (file)
@@ -72,6 +72,8 @@ namespace amcp {
                        return scheduling_ == Default ? GetDefaultScheduling() : scheduling_;\r
                }\r
 \r
+               virtual std::wstring print() const = 0;\r
+\r
                void SetScheduling(AMCPCommandScheduling s){scheduling_ = s;}\r
 \r
        protected:\r
index 7de056b99abcf9046a3f9517add4fbda1e0922cb..2b25b38a71d6db09e2c96fd9b7f20a73051dd1ec 100644 (file)
@@ -95,10 +95,18 @@ void AMCPCommandQueue::Run(HANDLE stopEvent)
 \r
                if(pCurrentCommand != 0) \r
                {\r
-                       if(pCurrentCommand->Execute()) \r
-                               CASPAR_LOG(info) << "Executed command";\r
-                       else \r
-                               CASPAR_LOG(info) << "Failed to executed command";\r
+                       try\r
+                       {\r
+                               if(pCurrentCommand->Execute()) \r
+                                       CASPAR_LOG(info) << "Executed command: " << pCurrentCommand->print();\r
+                               else \r
+                                       CASPAR_LOG(info) << "Failed to executed command: " << pCurrentCommand->print();\r
+                       }\r
+                       catch(...)\r
+                       {\r
+                               CASPAR_LOG_CURRENT_EXCEPTION();\r
+                               CASPAR_LOG(info) << "Failed to executed command:" << pCurrentCommand->print();\r
+                       }\r
                                \r
                        pCurrentCommand->SendReply();\r
                        pCurrentCommand.reset();\r
index c4db295c1e9c829be2ebecfa88f3562583e0229d..f0d6468536d6fe2035913daaf71b771aad1fb18e 100644 (file)
@@ -166,13 +166,68 @@ void AMCPCommand::Clear()
        _parameters.clear();\r
 }\r
 \r
+bool AddCommand::DoExecute()\r
+{      \r
+       //Perform loading of the clip\r
+       try\r
+       {\r
+               auto consumer = create_consumer(_parameters);           \r
+               GetChannel()->add(GetLayerIndex(), consumer);\r
+       \r
+               CASPAR_LOG(info) << "Added " <<  _parameters[0] << TEXT(" successfully");\r
+\r
+               SetReplyString(TEXT("202 ADD OK\r\n"));\r
+\r
+               return true;\r
+       }\r
+       catch(file_not_found&)\r
+       {\r
+               CASPAR_LOG_CURRENT_EXCEPTION();\r
+               SetReplyString(TEXT("404 ADD ERROR\r\n"));\r
+               return false;\r
+       }\r
+       catch(...)\r
+       {\r
+               CASPAR_LOG_CURRENT_EXCEPTION();\r
+               SetReplyString(TEXT("502 ADD FAILED\r\n"));\r
+               return false;\r
+       }\r
+}\r
+\r
+bool RemoveCommand::DoExecute()\r
+{      \r
+       //Perform loading of the clip\r
+       try\r
+       {\r
+               GetChannel()->remove(GetLayerIndex());\r
+       \r
+               CASPAR_LOG(info) << "Removed " << TEXT(" successfully");\r
+\r
+               SetReplyString(TEXT("202 REMOVE OK\r\n"));\r
+\r
+               return true;\r
+       }\r
+       catch(file_not_found&)\r
+       {\r
+               CASPAR_LOG_CURRENT_EXCEPTION();\r
+               SetReplyString(TEXT("404 REMOVE ERROR\r\n"));\r
+               return false;\r
+       }\r
+       catch(...)\r
+       {\r
+               CASPAR_LOG_CURRENT_EXCEPTION();\r
+               SetReplyString(TEXT("502 REMOVE FAILED\r\n"));\r
+               return false;\r
+       }\r
+}\r
+\r
 bool LoadCommand::DoExecute()\r
 {      \r
        //Perform loading of the clip\r
        try\r
        {\r
                _parameters[0] = _parameters[0];\r
-               auto pFP = load_media(_parameters);             \r
+               auto pFP = create_producer(_parameters);                \r
                GetChannel()->preview(GetLayerIndex(), pFP);\r
        \r
                CASPAR_LOG(info) << "Loaded " <<  _parameters[0] << TEXT(" successfully");\r
@@ -247,7 +302,7 @@ bool LoadbgCommand::DoExecute()
        try\r
        {\r
                _parameters[0] = _parameters[0];\r
-               auto pFP = load_media(_parameters);\r
+               auto pFP = create_producer(_parameters);\r
                if(pFP == frame_producer::empty())\r
                        BOOST_THROW_EXCEPTION(file_not_found() << msg_info(_parameters.size() > 0 ? narrow(_parameters[0]) : ""));\r
 \r
index 21382c74fd0fc040b3140d83a48dc265d30fedc4..53d6d31403c5e3992d4f4265222b2c8e226c8582 100644 (file)
@@ -29,39 +29,58 @@ std::wstring ListMedia();
 std::wstring ListTemplates();\r
 \r
 namespace amcp {\r
+       \r
+class AddCommand : public AMCPCommandBase<true, AddToQueue, 1>\r
+{\r
+       std::wstring print() const { return L"AddCommand";}\r
+       bool DoExecute();\r
+};\r
+\r
+class RemoveCommand : public AMCPCommandBase<true, AddToQueue, 0>\r
+{\r
+       std::wstring print() const { return L"RemoveCommand";}\r
+       bool DoExecute();\r
+};\r
 \r
-class LoadCommand : public AMCPCommandBase<true, ImmediatelyAndClear, 1>\r
+class LoadCommand : public AMCPCommandBase<true, AddToQueue, 1>\r
 {\r
+       std::wstring print() const { return L"LoadCommand";}\r
        bool DoExecute();\r
 };\r
 \r
 class LoadbgCommand : public AMCPCommandBase<true, AddToQueue, 1>\r
 {\r
+       std::wstring print() const { return L"LoadbgCommand";}\r
        bool DoExecute();\r
 };\r
 \r
 class PlayCommand: public AMCPCommandBase<true, AddToQueue, 0>\r
 {\r
+       std::wstring print() const { return L"PlayCommand";}\r
        bool DoExecute();\r
 };\r
 \r
 class PauseCommand: public AMCPCommandBase<true, AddToQueue, 0>\r
 {\r
+       std::wstring print() const { return L"PauseCommand";}\r
        bool DoExecute();\r
 };\r
 \r
-class StopCommand : public AMCPCommandBase<true, ImmediatelyAndClear, 0>\r
+class StopCommand : public AMCPCommandBase<true, AddToQueue, 0>\r
 {\r
+       std::wstring print() const { return L"StopCommand";}\r
        bool DoExecute();\r
 };\r
 \r
-class ClearCommand : public AMCPCommandBase<true, ImmediatelyAndClear, 0>\r
+class ClearCommand : public AMCPCommandBase<true, AddToQueue, 0>\r
 {\r
+       std::wstring print() const { return L"ClearCommand";}\r
        bool DoExecute();\r
 };\r
 \r
 class CGCommand : public AMCPCommandBase<true, AddToQueue, 1>\r
 {\r
+       std::wstring print() const { return L"CGCommand";}\r
        bool DoExecute();\r
        bool ValidateLayer(const std::wstring& layerstring);\r
 \r
@@ -78,6 +97,7 @@ class CGCommand : public AMCPCommandBase<true, AddToQueue, 1>
 \r
 class DataCommand : public AMCPCommandBase<false, AddToQueue, 1>\r
 {\r
+       std::wstring print() const { return L"DataCommand";}\r
        bool DoExecute();\r
        bool DoExecuteStore();\r
        bool DoExecuteRetrieve();\r
@@ -86,22 +106,26 @@ class DataCommand : public AMCPCommandBase<false, AddToQueue, 1>
 \r
 class ClsCommand : public AMCPCommandBase<false, AddToQueue, 0>\r
 {\r
+       std::wstring print() const { return L"ClsCommand";}\r
        bool DoExecute();\r
 };\r
 \r
 class TlsCommand : public AMCPCommandBase<false, AddToQueue, 0>\r
 {\r
+       std::wstring print() const { return L"TlsCommand";}\r
        bool DoExecute();\r
 };\r
 \r
 class CinfCommand : public AMCPCommandBase<false, AddToQueue, 1>\r
 {\r
+       std::wstring print() const { return L"CinfCommand";}\r
        bool DoExecute();\r
 };\r
 \r
 class InfoCommand : public AMCPCommandBase<false, AddToQueue, 0>\r
 {\r
 public:\r
+       std::wstring print() const { return L"InfoCommand";}\r
        InfoCommand(const std::vector<safe_ptr<core::channel>>& channels) : channels_(channels){}\r
        bool DoExecute();\r
 private:\r
@@ -110,16 +134,19 @@ private:
 \r
 class VersionCommand : public AMCPCommandBase<false, AddToQueue, 0>\r
 {\r
+       std::wstring print() const { return L"VersionCommand";}\r
        bool DoExecute();\r
 };\r
 \r
 class ByeCommand : public AMCPCommandBase<false, AddToQueue, 0>\r
 {\r
+       std::wstring print() const { return L"ByeCommand";}\r
        bool DoExecute();\r
 };\r
 \r
 class SetCommand : public AMCPCommandBase<true, AddToQueue, 2>\r
 {\r
+       std::wstring print() const { return L"SetCommand";}\r
        bool DoExecute();\r
 };\r
 \r
index 0cf8fa02a918ade7bf60d572396951f2f104ecf7..dc9b6b9b707f31501717c6f057a6991587f91d51 100644 (file)
@@ -311,6 +311,8 @@ AMCPCommandPtr AMCPProtocolStrategy::CommandFactory(const std::wstring& str)
        \r
        if         (s == TEXT("LOAD"))          return std::make_shared<LoadCommand>();\r
        else if(s == TEXT("LOADBG"))    return std::make_shared<LoadbgCommand>();\r
+       else if(s == TEXT("ADD"))               return std::make_shared<AddCommand>();\r
+       else if(s == TEXT("REMOVE"))    return std::make_shared<RemoveCommand>();\r
        else if(s == TEXT("PAUSE"))             return std::make_shared<PauseCommand>();\r
        else if(s == TEXT("PLAY"))              return std::make_shared<PlayCommand>();\r
        else if(s == TEXT("STOP"))              return std::make_shared<StopCommand>();\r
index 6f8fd9a36ae057790b376dfa418c51c58688fe09..39bb5ec784d040470177382aad12f5df99c1c211 100644 (file)
@@ -215,7 +215,7 @@ void CIIProtocolStrategy::DisplayMediaFile(const std::wstring& filename)
        transition.type = transition::mix;\r
        transition.duration = 12;\r
 \r
-       auto pFP = load_media(boost::assign::list_of(filename));\r
+       auto pFP = create_producer(boost::assign::list_of(filename));\r
        auto pTransition = safe_ptr<core::frame_producer>(transition_producer(pFP, transition));\r
 \r
        try\r
index cd738f7a317c44477c68e5fc5f9d0043f80e9b4b..a700209e9fe8abfbcbdc33648e2725a96775a126 100644 (file)
@@ -7,6 +7,12 @@
 #include <core/producer/flash/cg_producer.h>\r
 #include <core/producer/image/image_producer.h>\r
 #include <core/producer/decklink/decklink_producer.h>\r
+\r
+#include <core/consumer/bluefish/bluefish_consumer.h>\r
+#include <core/consumer/decklink/decklink_consumer.h>\r
+#include <core/consumer/ogl/ogl_consumer.h>\r
+#include <core/consumer/oal/oal_consumer.h>\r
+#include <core/consumer/ffmpeg/ffmpeg_consumer.h>\r
 //#include "../producer/image/image_scroll_producer.h"\r
 \r
 #include <common/exception/exceptions.h>\r
@@ -20,11 +26,11 @@ namespace caspar { namespace protocol {
        \r
 using namespace core;\r
 \r
-safe_ptr<core::frame_producer> load_media(const std::vector<std::wstring>& params)\r
+safe_ptr<core::frame_producer> create_producer(const std::vector<std::wstring>& params)\r
 {              \r
-       typedef std::function<safe_ptr<core::frame_producer>(const std::vector<std::wstring>&)> producer_factory;\r
+       typedef std::function<safe_ptr<core::frame_producer>(const std::vector<std::wstring>&)> factory_t;\r
 \r
-       const auto producer_factories = list_of<producer_factory>\r
+       const auto factories = list_of<factory_t>\r
                (&core::flash::create_ct_producer)\r
                (&core::image::create_image_producer)\r
        //      (&image::create_image_scroll_producer)\r
@@ -35,8 +41,8 @@ safe_ptr<core::frame_producer> load_media(const std::vector<std::wstring>& param
        if(params.empty())\r
                BOOST_THROW_EXCEPTION(invalid_argument() << arg_name_info("params") << arg_value_info(""));\r
 \r
-       safe_ptr<core::frame_producer> producer(frame_producer::empty());\r
-       std::any_of(producer_factories.begin(), producer_factories.end(), [&](const producer_factory& factory) -> bool\r
+       auto producer = frame_producer::empty();\r
+       std::any_of(factories.begin(), factories.end(), [&](const factory_t& factory) -> bool\r
                {\r
                        try\r
                        {\r
@@ -52,4 +58,35 @@ safe_ptr<core::frame_producer> load_media(const std::vector<std::wstring>& param
        return producer;\r
 }\r
 \r
+safe_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)\r
+{              \r
+       typedef std::function<safe_ptr<core::frame_consumer>(const std::vector<std::wstring>&)> factory_t;\r
+\r
+       const auto factories = list_of<factory_t>\r
+               (&core::create_bluefish_consumer)\r
+               (&core::create_decklink_consumer)\r
+               (&core::create_oal_consumer)\r
+               (&core::create_ogl_consumer)\r
+               (&core::create_ffmpeg_consumer);\r
+\r
+       if(params.empty())\r
+               BOOST_THROW_EXCEPTION(invalid_argument() << arg_name_info("params") << arg_value_info(""));\r
+\r
+       auto consumer = frame_consumer::empty();\r
+       std::any_of(factories.begin(), factories.end(), [&](const factory_t& factory) -> bool\r
+               {\r
+                       try\r
+                       {\r
+                               consumer = factory(params);\r
+                       }\r
+                       catch(...)\r
+                       {\r
+                               CASPAR_LOG_CURRENT_EXCEPTION();\r
+                       }\r
+                       return consumer != frame_consumer::empty();\r
+               });\r
+\r
+       return consumer;\r
+}\r
+\r
 }}\r
index ad3b0b23be4e648c604f84b20baba505d8b89643..f605f4aa87b416388cc1941a46d70774ff913fc6 100644 (file)
@@ -1,12 +1,14 @@
 #pragma once\r
 \r
 #include <core/producer/frame_producer.h>\r
+#include <core/consumer/frame_consumer.h>\r
 \r
 #include <string>\r
 #include <vector>\r
 \r
 namespace caspar { namespace protocol { \r
        \r
-safe_ptr<core::frame_producer> load_media(const std::vector<std::wstring>& params);\r
+safe_ptr<core::frame_producer> create_producer(const std::vector<std::wstring>& params);\r
+safe_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);\r
 \r
 }}\r
index 1c8a4824f9744201c220f19fc861968931204c09..76cb2246bba9bcdf51b9f1cc706a7b5031d7a959 100644 (file)
@@ -59,8 +59,10 @@ struct bootstrapper::implementation : boost::noncopyable
                        auto format_desc = video_format_desc::get(widen(xml_channel.second.get("videomode", "PAL")));           \r
                        if(format_desc.format == video_format::invalid)\r
                                BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("Invalid videomode."));\r
-                       std::vector<safe_ptr<frame_consumer>> consumers;\r
-\r
+                       \r
+                       channels_.push_back(channel(format_desc));\r
+                       \r
+                       int index = 0;\r
                        BOOST_FOREACH(auto& xml_consumer, xml_channel.second.get_child("consumers"))\r
                        {\r
                                try\r
@@ -70,41 +72,30 @@ struct bootstrapper::implementation : boost::noncopyable
                                        {                       \r
                                                int device = xml_consumer.second.get("device", 0);\r
                        \r
-                                               ogl::stretch stretch = ogl::stretch::fill;\r
+                                               stretch stretch = stretch::fill;\r
                                                std::string stretchStr = xml_consumer.second.get("stretch", "");\r
                                                if(stretchStr == "none")\r
-                                                       stretch = ogl::stretch::none;\r
+                                                       stretch = stretch::none;\r
                                                else if(stretchStr == "uniform")\r
-                                                       stretch = ogl::stretch::uniform;\r
+                                                       stretch = stretch::uniform;\r
                                                else if(stretchStr == "uniformtofill")\r
-                                                       stretch = ogl::stretch::uniform_to_fill;\r
+                                                       stretch = stretch::uniform_to_fill;\r
 \r
                                                bool windowed = xml_consumer.second.get("windowed", false);\r
-                                               consumers.push_back(ogl::consumer(format_desc, device, stretch, windowed));\r
+                                               channels_.back()->add(index++, ogl_consumer(format_desc, device, stretch, windowed));\r
                                        }\r
                                        else if(name == "bluefish")                                     \r
-                                               consumers.push_back(bluefish::consumer(format_desc, xml_consumer.second.get("device", 0), xml_consumer.second.get("embedded-audio", false)));                                   \r
+                                               channels_.back()->add(index++, bluefish_consumer(format_desc, xml_consumer.second.get("device", 0), xml_consumer.second.get("embedded-audio", false)));                                 \r
                                        else if(name == "decklink")\r
-                                               consumers.push_back(make_safe<decklink::decklink_consumer>(format_desc, xml_consumer.second.get("device", 0), xml_consumer.second.get("internalkey", false)));\r
+                                               channels_.back()->add(index++, decklink_consumer(format_desc, xml_consumer.second.get("device", 0), xml_consumer.second.get("internalkey", false)));\r
                                        else if(name == "audio")\r
-                                               consumers.push_back(oal::consumer(format_desc));                        \r
+                                               channels_.back()->add(index++, oal_consumer(format_desc));                      \r
                                }\r
                                catch(...)\r
                                {\r
                                        CASPAR_LOG_CURRENT_EXCEPTION();\r
                                }\r
-                       }\r
-\r
-                       try\r
-                       {\r
-                               consumers.push_back(ffmpeg::consumer(format_desc, env::media_folder() + L"test.mpeg")); \r
-                       }\r
-                       catch(...)\r
-                       {\r
-                               CASPAR_LOG_CURRENT_EXCEPTION();\r
-                       }\r
-                                                       \r
-                       channels_.push_back(channel(format_desc, consumers));\r
+                       }                                                       \r
                }\r
        }\r
                \r