]> git.sesse.net Git - casparcg/commitdiff
Merge pull request #135 from cambell-prince/master_layer_producer
authorHelge Norberg <helge.norberg@gmail.com>
Mon, 17 Jun 2013 12:24:19 +0000 (14:24 +0200)
committerHelge Norberg <helge.norberg@gmail.com>
Mon, 17 Jun 2013 12:24:19 +0000 (14:24 +0200)
core/consumer/write_frame_consumer.h [new file with mode: 0644]
core/core.vcxproj
core/core.vcxproj.filters
core/producer/layer/layer_producer.cpp [new file with mode: 0644]
core/producer/layer/layer_producer.h [new file with mode: 0644]
core/producer/stage.cpp
core/producer/stage.h
protocol/amcp/AMCPCommandsImpl.cpp
protocol/amcp/AMCPCommandsImpl.h
protocol/amcp/AMCPProtocolStrategy.cpp

diff --git a/core/consumer/write_frame_consumer.h b/core/consumer/write_frame_consumer.h
new file mode 100644 (file)
index 0000000..a3cd1ed
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG 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 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG 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 CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Cambell Prince, cambell.prince@gmail.com
+*/
+
+#pragma once
+
+#include <common/memory/safe_ptr.h>
+
+#include <boost/noncopyable.hpp>
+#include <boost/property_tree/ptree_fwd.hpp>
+#include <boost/thread/future.hpp>
+
+#include <functional>
+#include <string>
+#include <vector>
+
+namespace caspar { namespace core {
+       
+class basic_frame;
+class parameters;
+struct video_format_desc;
+
+struct write_frame_consumer : boost::noncopyable
+{
+       virtual ~write_frame_consumer() {}
+       
+       virtual void send(const safe_ptr<basic_frame>& frame) = 0;
+       virtual std::wstring print() const = 0;
+       //virtual boost::property_tree::wptree info() const = 0;
+};
+
+}}
\ No newline at end of file
index a28e87e2ae047b5fc1e63a523a17f8e39b8bdcf5..9c5963e235a28c8b8eb9bf1079c6a63cffd00757 100644 (file)
     <Lib />\r
   </ItemDefinitionGroup>\r
   <ItemGroup>\r
+    <ClInclude Include="consumer\write_frame_consumer.h" />\r
     <ClInclude Include="mixer\audio\audio_util.h" />\r
     <ClInclude Include="mixer\gpu\fence.h" />\r
     <ClInclude Include="mixer\gpu\shader.h" />\r
     <ClInclude Include="monitor\monitor.h" />\r
     <ClInclude Include="producer\channel\channel_producer.h" />\r
     <ClInclude Include="thumbnail_generator.h" />\r
+    <ClInclude Include="producer\layer\layer_producer.h" />\r
     <ClInclude Include="video_channel.h" />\r
     <ClInclude Include="consumer\output.h" />\r
     <ClInclude Include="consumer\frame_consumer.h" />\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
     </ClCompile>\r
     <ClCompile Include="thumbnail_generator.cpp" />\r
-    <ClCompile Include="video_channel.cpp" />\r
+    <ClCompile Include="producer\layer\layer_producer.cpp">\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+    </ClCompile>\r
+    <ClCompile Include="video_channel.cpp">\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">StdAfx.h</PrecompiledHeaderFile>\r
+    </ClCompile>\r
     <ClCompile Include="consumer\frame_consumer.cpp">\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
index ab0981f716c297ecc11efed0beedea773a903555..e040b2aa2d2faeb07ee714b457253bc32b7812fc 100644 (file)
@@ -43,6 +43,9 @@
     <Filter Include="source\monitor">\r
       <UniqueIdentifier>{d8525088-072a-47d2-b6e1-ad662881f505}</UniqueIdentifier>\r
     </Filter>\r
+    <Filter Include="source\producer\layer">\r
+      <UniqueIdentifier>{4e098e4c-7467-446f-990d-d4486d179edb}</UniqueIdentifier>\r
+    </Filter>\r
     <Filter Include="source\parameters">\r
       <UniqueIdentifier>{d04737a6-96b2-40cd-b1e7-e90b69006cd1}</UniqueIdentifier>\r
     </Filter>\r
     <ClInclude Include="producer\channel\channel_producer.h">\r
       <Filter>source\producer\channel</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="producer\layer\layer_producer.h">\r
+      <Filter>source\producer\layer</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="consumer\write_frame_consumer.h">\r
+      <Filter>source\consumer</Filter>\r
+    </ClInclude>\r
     <ClInclude Include="thumbnail_generator.h">\r
       <Filter>source</Filter>\r
     </ClInclude>\r
     <ClCompile Include="thumbnail_generator.cpp">\r
       <Filter>source</Filter>\r
     </ClCompile>\r
+    <ClCompile Include="producer\layer\layer_producer.cpp">\r
+      <Filter>source\producer\layer</Filter>\r
+    </ClCompile>\r
     <ClCompile Include="monitor\monitor.cpp">\r
       <Filter>source\monitor</Filter>\r
     </ClCompile>\r
diff --git a/core/producer/layer/layer_producer.cpp b/core/producer/layer/layer_producer.cpp
new file mode 100644 (file)
index 0000000..b29e191
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG 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 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG 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 CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Cambell Prince, cambell.prince@gmail.com
+*/
+
+#include "../../stdafx.h"
+
+#include "layer_producer.h"
+
+#include "../../consumer/write_frame_consumer.h"
+#include "../../consumer/output.h"
+#include "../../video_channel.h"
+
+#include "../stage.h"
+#include "../frame/basic_frame.h"
+#include "../frame/frame_factory.h"
+#include "../../mixer/write_frame.h"
+#include "../../mixer/read_frame.h"
+
+#include <common/exception/exceptions.h>
+#include <common/memory/memcpy.h>
+#include <common/concurrency/future_util.h>
+
+#include <boost/format.hpp>
+
+#include <tbb/concurrent_queue.h>
+
+namespace caspar { namespace core {
+
+class layer_consumer : public write_frame_consumer
+{      
+       tbb::concurrent_bounded_queue<safe_ptr<basic_frame>>    frame_buffer_;
+
+public:
+       layer_consumer() 
+       {
+               frame_buffer_.set_capacity(2);
+       }
+
+       ~layer_consumer()
+       {
+       }
+
+       // write_frame_consumer
+
+       virtual void send(const safe_ptr<basic_frame>& src_frame) override
+       {
+               frame_buffer_.try_push(src_frame);
+       }
+
+       virtual std::wstring print() const override
+       {
+               return L"[layer_consumer]";
+       }
+
+       safe_ptr<basic_frame> receive()
+       {
+               safe_ptr<basic_frame> frame;
+               if (!frame_buffer_.try_pop(frame))
+               {
+                       return basic_frame::late();
+               }
+               return frame;
+       }
+};
+
+class layer_producer : public frame_producer
+{
+       monitor::subject                                        monitor_subject_;
+
+       const safe_ptr<frame_factory>                   frame_factory_;
+       int                                                                             layer_;
+       const std::shared_ptr<layer_consumer>   consumer_;
+
+       safe_ptr<basic_frame>                                   last_frame_;
+       uint64_t                                                                frame_number_;
+
+       const safe_ptr<stage>                   stage_;
+
+public:
+       explicit layer_producer(const safe_ptr<frame_factory>& frame_factory, const safe_ptr<stage>& stage, int layer) 
+               : frame_factory_(frame_factory)
+               , layer_(layer)
+               , stage_(stage)
+               , consumer_(new layer_consumer())
+               , last_frame_(basic_frame::empty())
+               , frame_number_(0)
+       {
+               stage_->add_layer_consumer(this, layer_, consumer_);
+               CASPAR_LOG(info) << print() << L" Initialized";
+       }
+
+       ~layer_producer()
+       {
+               stage_->remove_layer_consumer(this, layer_);
+               CASPAR_LOG(info) << print() << L" Uninitialized";
+       }
+
+       // frame_producer
+                       
+       virtual safe_ptr<basic_frame> receive(int) override
+       {
+               auto consumer_frame = consumer_->receive();
+               if (consumer_frame == basic_frame::late())
+                       return last_frame_;
+
+               frame_number_++;
+               return last_frame_ = consumer_frame;
+       }       
+
+       virtual safe_ptr<basic_frame> last_frame() const override
+       {
+               return last_frame_; 
+       }       
+
+       virtual std::wstring print() const override
+       {
+               return L"layer-producer[" + boost::lexical_cast<std::wstring>(layer_) + L"]";
+       }
+
+       virtual boost::property_tree::wptree info() const override
+       {
+               boost::property_tree::wptree info;
+               info.add(L"type", L"layer-producer");
+               return info;
+       }
+
+       monitor::source& monitor_output() 
+       {
+               return monitor_subject_;
+       }
+
+};
+
+safe_ptr<frame_producer> create_layer_producer(const safe_ptr<core::frame_factory>& frame_factory, const safe_ptr<stage>& stage, int layer)
+{
+       return create_producer_print_proxy(
+               make_safe<layer_producer>(frame_factory, stage, layer)
+       );
+}
+
+}}
\ No newline at end of file
diff --git a/core/producer/layer/layer_producer.h b/core/producer/layer/layer_producer.h
new file mode 100644 (file)
index 0000000..51726d1
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG 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 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG 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 CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Cambell Prince, cambell.prince@gmail.com
+*/
+
+#pragma once
+
+#include "../frame_producer.h"
+
+#include <string>
+#include <vector>
+
+namespace caspar { namespace core {
+
+class stage;
+struct frame_factory;
+
+safe_ptr<frame_producer> create_layer_producer(const safe_ptr<core::frame_factory>& frame_factory, const safe_ptr<stage>& stage, int layer);
+
+}}
index 57f7b5834e000547c9dbea728747b5fdf3abfda2..5dc8872bb21021f1b53991dbb2193d0f4b75db57 100644 (file)
@@ -31,6 +31,8 @@
 #include <common/concurrency/executor.h>\r
 \r
 #include <core/producer/frame/frame_transform.h>\r
+#include <core/consumer/frame_consumer.h>\r
+#include <core/consumer/write_frame_consumer.h>\r
 \r
 #include <boost/foreach.hpp>\r
 #include <boost/timer.hpp>\r
@@ -43,7 +45,7 @@
 #include <map>\r
 \r
 namespace caspar { namespace core {\r
-       \r
+\r
 template<typename T>\r
 class tweened_transform\r
 {\r
@@ -102,6 +104,11 @@ struct stage::implementation : public std::enable_shared_from_this<implementatio
        monitor::subject                                                                                                                         monitor_subject_;\r
 \r
        executor                                                                                                                                         executor_;\r
+\r
+private:\r
+       // map of layer -> map of tokens (src ref) -> layer_consumer\r
+       std::map<int, std::map<void*, std::shared_ptr<write_frame_consumer>>>           layer_consumers_;\r
+\r
 public:\r
        implementation(const safe_ptr<diagnostics::graph>& graph, const safe_ptr<stage::target_t>& target, const video_format_desc& format_desc)  \r
                : graph_(graph)\r
@@ -119,7 +126,28 @@ public:
                std::weak_ptr<implementation> self = shared_from_this();\r
                executor_.begin_invoke([=]{tick(self);});\r
        }\r
-                                                       \r
+       \r
+       void add_layer_consumer(void* token, int layer, const std::shared_ptr<write_frame_consumer>& layer_consumer)\r
+       {\r
+               executor_.begin_invoke([=]\r
+               {\r
+                       layer_consumers_[layer][token] = layer_consumer;\r
+               }, high_priority);\r
+       }\r
+\r
+       void remove_layer_consumer(void* token, int layer)\r
+       {\r
+               executor_.begin_invoke([=]\r
+               {\r
+                       auto& layer_map = layer_consumers_[layer];\r
+                       layer_map.erase(token);\r
+                       if (layer_map.empty())\r
+                       {\r
+                               layer_consumers_.erase(layer);\r
+                       }\r
+               }, high_priority);\r
+       }\r
+\r
        void tick(const std::weak_ptr<implementation>& self)\r
        {               \r
                try\r
@@ -146,7 +174,16 @@ public:
                                        hints |= frame_producer::ALPHA_HINT;\r
 \r
                                auto frame = layer.second->receive(hints);      \r
-                               \r
+                               auto layer_consumers_it = layer_consumers_.find(layer.first);\r
+                               if (layer_consumers_it != layer_consumers_.end())\r
+                               {\r
+                                       auto consumer_it = (*layer_consumers_it).second | boost::adaptors::map_values;\r
+                                       tbb::parallel_for_each(consumer_it.begin(), consumer_it.end(), [&](decltype(consumer_it[0]) layer_consumer) \r
+                                       {\r
+                                               layer_consumer->send(frame);\r
+                                       });\r
+                               }\r
+\r
                                auto frame1 = make_safe<core::basic_frame>(frame);\r
                                frame1->get_frame_transform() = transform;\r
 \r
@@ -161,7 +198,7 @@ public:
                        });\r
                        \r
                        graph_->set_value("produce-time", produce_timer_.elapsed()*format_desc_.fps*0.5);\r
-                       \r
+\r
                        std::shared_ptr<void> ticket(nullptr, [self](void*)\r
                        {\r
                                auto self2 = self.lock();\r
@@ -438,6 +475,8 @@ void stage::clear(){impl_->clear();}
 void stage::swap_layers(const safe_ptr<stage>& other){impl_->swap_layers(*other);}\r
 void stage::swap_layer(int index, size_t other_index){impl_->swap_layer(index, other_index);}\r
 void stage::swap_layer(int index, size_t other_index, const safe_ptr<stage>& other){impl_->swap_layer(index, other_index, *other);}\r
+void stage::add_layer_consumer(void* token, int layer, const std::shared_ptr<write_frame_consumer>& layer_consumer){impl_->add_layer_consumer(token, layer, layer_consumer);}\r
+void stage::remove_layer_consumer(void* token, int layer){impl_->remove_layer_consumer(token, layer);}\r
 boost::unique_future<safe_ptr<frame_producer>> stage::foreground(int index) {return impl_->foreground(index);}\r
 boost::unique_future<safe_ptr<frame_producer>> stage::background(int index) {return impl_->background(index);}\r
 boost::unique_future<std::wstring> stage::call(int index, bool foreground, const std::wstring& param){return impl_->call(index, foreground, param);}\r
index f8b2505ac4bc6879bbc27306bf0b9a45226fb2f7..2c6ec038defcbccb572e14d461e52b6b89e2d618 100644 (file)
@@ -39,6 +39,7 @@ namespace caspar { namespace core {
 \r
 struct video_format_desc;\r
 struct frame_transform;\r
+struct write_frame_consumer;\r
 \r
 class stage : boost::noncopyable\r
 {\r
@@ -73,7 +74,10 @@ public:
        void swap_layers(const safe_ptr<stage>& other);\r
        void swap_layer(int index, size_t other_index);\r
        void swap_layer(int index, size_t other_index, const safe_ptr<stage>& other);\r
-       \r
+\r
+       void add_layer_consumer(void* token, int layer, const std::shared_ptr<write_frame_consumer>& layer_consumer);\r
+       void remove_layer_consumer(void* token, int layer);\r
+\r
        boost::unique_future<std::wstring>                              call(int index, bool foreground, const std::wstring& param);\r
 \r
        // Properties\r
index 0ffd85cdd771461945bd466c067dda0113d976f0..84387bf406eefdcbc86a5077fd6b7a229711b408 100644 (file)
@@ -42,6 +42,7 @@
 #include <core/video_format.h>\r
 #include <core/producer/transition/transition_producer.h>\r
 #include <core/producer/channel/channel_producer.h>\r
+#include <core/producer/layer/layer_producer.h>\r
 #include <core/producer/frame/frame_transform.h>\r
 #include <core/producer/stage.h>\r
 #include <core/producer/layer.h>\r
 \r
 /* Return codes\r
 \r
-100 [action]                   Information om att n�got har h�nt  \r
-101 [action]                   Information om att n�got har h�nt, en rad data skickas  \r
+100 [action]                   Information om att något har hänt  \r
+101 [action]                   Information om att något har hänt, en rad data skickas  \r
 \r
-202 [kommando] OK              Kommandot har utfrts  \r
-201 [kommando] OK              Kommandot har utfrts, och en rad data skickas tillbaka  \r
-200 [kommando] OK              Kommandot har utfrts, och flera rader data skickas tillbaka. Avslutas med tomrad  \r
+202 [kommando] OK              Kommandot har utförts  \r
+201 [kommando] OK              Kommandot har utförts, och en rad data skickas tillbaka  \r
+200 [kommando] OK              Kommandot har utförts, och flera rader data skickas tillbaka. Avslutas med tomrad  \r
 \r
-400 ERROR                              Kommandot kunde inte f�rst�s  \r
+400 ERROR                              Kommandot kunde inte förstås  \r
 401 [kommando] ERROR   Ogiltig kanal  \r
 402 [kommando] ERROR   Parameter saknas  \r
 403 [kommando] ERROR   Ogiltig parameter  \r
 \r
 500 FAILED                             Internt configurationfel  \r
 501 [kommando] FAILED  Internt configurationfel  \r
-502 [kommando] FAILED  Olslig mediafil  \r
+502 [kommando] FAILED  Oläslig mediafil  \r
 \r
 600 [kommando] FAILED  funktion ej implementerad\r
 */\r
@@ -579,7 +580,7 @@ bool MixerCommand::DoExecute()
 \r
                        auto blend_str = _parameters.at(1);                                                             \r
                        int layer = GetLayerIndex();\r
-                       blend_mode::type && blend = get_blend_mode(blend_str);\r
+                       blend_mode::type blend = get_blend_mode(blend_str);\r
                        GetChannel()->mixer()->set_blend_mode(GetLayerIndex(), blend);  \r
                }\r
         else if(_parameters[0] == L"CHROMA")\r
@@ -600,7 +601,7 @@ bool MixerCommand::DoExecute()
                        }\r
 \r
                        int layer = GetLayerIndex();\r
-            chroma  chroma;\r
+            chroma chroma;\r
             chroma.key = get_chroma_mode(_parameters[1]);\r
 \r
                        if (chroma.key != chroma::none)\r
@@ -875,12 +876,94 @@ bool RemoveCommand::DoExecute()
        }\r
 }\r
 \r
+safe_ptr<core::frame_producer> RouteCommand::TryCreateProducer(AMCPCommand& command, std::wstring const& uri)\r
+{\r
+       safe_ptr<core::frame_producer> pFP(frame_producer::empty());\r
+\r
+       auto tokens = core::parameters::protocol_split(uri);\r
+       auto src_channel_layer_token = tokens[0] == L"route" ? tokens[1] : uri;\r
+       std::vector<std::wstring> src_channel_layer;\r
+       boost::split(src_channel_layer, src_channel_layer_token, boost::is_any_of("-"));\r
+\r
+       if (tokens[0] == L"route" || src_channel_layer.size() == 2) // It looks like a route\r
+       {\r
+               // Find the source channel\r
+               int src_channel_index = boost::lexical_cast<int>(src_channel_layer[0]);\r
+               auto channels = command.GetChannels();\r
+               auto src_channel = std::find_if(\r
+                       channels.begin(), \r
+                       channels.end(), \r
+                       [src_channel_index](const safe_ptr<core::video_channel>& item) { return item->index() == src_channel_index; }\r
+               );\r
+               if (src_channel == channels.end())\r
+                       BOOST_THROW_EXCEPTION(null_argument() << msg_info("src channel not found"));\r
+\r
+               // Find the source layer (if one is given)\r
+               int src_layer_index = -1;\r
+               if (src_channel_layer.size() > 1 && !src_channel_layer[1].empty())\r
+               {\r
+                       src_layer_index = boost::lexical_cast<int>(src_channel_layer[1]);\r
+               }\r
+\r
+               if (src_layer_index >= 0)\r
+               {\r
+                       pFP = create_layer_producer(command.GetChannel()->mixer(), (*src_channel)->stage(), src_layer_index);\r
+               } else \r
+               {\r
+                       pFP = create_channel_producer(command.GetChannel()->mixer(), *src_channel);\r
+               }\r
+       }\r
+       return pFP;\r
+}\r
+\r
+bool RouteCommand::DoExecute()\r
+{      \r
+       try\r
+       {\r
+               auto pFP = RouteCommand::TryCreateProducer(\r
+                               *this, _parameters.at_original(0));\r
+\r
+               if (pFP != frame_producer::empty())\r
+               {\r
+                       GetChannel()->stage()->load(GetLayerIndex(), pFP, true);\r
+                       GetChannel()->stage()->play(GetLayerIndex());\r
+\r
+                       SetReplyString(TEXT("202 ROUTE OK\r\n"));\r
+               \r
+                       return true;\r
+               }\r
+               SetReplyString(TEXT("404 ROUTE ERROR\r\n"));\r
+               return false;\r
+       }\r
+       catch(file_not_found&)\r
+       {\r
+               CASPAR_LOG_CURRENT_EXCEPTION();\r
+               SetReplyString(TEXT("404 ROUTE ERROR\r\n"));\r
+               return false;\r
+       }\r
+       catch(...)\r
+       {\r
+               CASPAR_LOG_CURRENT_EXCEPTION();\r
+               SetReplyString(TEXT("502 ROUTE FAILED\r\n"));\r
+               return false;\r
+       }\r
+}\r
+\r
 bool LoadCommand::DoExecute()\r
 {      \r
        //Perform loading of the clip\r
        try\r
        {\r
-               auto pFP = create_producer(GetChannel()->mixer(), _parameters);         \r
+               auto uri_tokens = parameters::protocol_split(_parameters.at_original(0));\r
+               auto pFP = frame_producer::empty();\r
+               if (uri_tokens[0].empty() || uri_tokens[0] == L"route")\r
+               {\r
+                       pFP = RouteCommand::TryCreateProducer(*this, _parameters.at_original(0));\r
+               }\r
+               if (pFP == frame_producer::empty())\r
+               {\r
+                       pFP = create_producer(GetChannel()->mixer(), _parameters);\r
+               }\r
                GetChannel()->stage()->load(GetLayerIndex(), pFP, true);\r
        \r
                SetReplyString(TEXT("202 LOAD OK\r\n"));\r
@@ -985,7 +1068,16 @@ bool LoadbgCommand::DoExecute()
        //Perform loading of the clip\r
        try\r
        {\r
-               auto pFP = create_producer(GetChannel()->mixer(), _parameters);\r
+               auto uri_tokens = core::parameters::protocol_split(_parameters.at_original(0));\r
+               auto pFP = frame_producer::empty();\r
+               if (uri_tokens[0].empty() || uri_tokens[0] == L"route")\r
+               {\r
+                       pFP = RouteCommand::TryCreateProducer(*this, _parameters.at_original(0));\r
+               }\r
+               if (pFP == frame_producer::empty())\r
+               {\r
+                       pFP = create_producer(GetChannel()->mixer(), _parameters);\r
+               }\r
                if(pFP == frame_producer::empty())\r
                        BOOST_THROW_EXCEPTION(file_not_found() << msg_info(_parameters.size() > 0 ? narrow(_parameters[0]) : ""));\r
 \r
@@ -1035,6 +1127,7 @@ bool PlayCommand::DoExecute()
                if(!_parameters.empty())\r
                {\r
                        LoadbgCommand lbg;\r
+                       lbg.SetChannels(GetChannels());\r
                        lbg.SetChannel(GetChannel());\r
                        lbg.SetChannelIndex(GetChannelIndex());\r
                        lbg.SetLayerIntex(GetLayerIndex());\r
index 2e7f0d4718eed43b3f49834af373c8ed77ad8a3a..1a14140d5326448f3a4685b297fbb0a79c88ba8d 100644 (file)
 #include "AMCPCommand.h"\r
 \r
 namespace caspar {\r
+\r
 namespace core {\r
        struct frame_transform;\r
+       struct frame_producer;\r
 }\r
 \r
 namespace protocol {\r
-       \r
+\r
 std::wstring ListMedia();\r
 std::wstring ListTemplates();\r
 \r
@@ -90,6 +92,20 @@ class SwapCommand : public AMCPCommandBase<true, AddToQueue, 1>
        bool DoExecute();\r
 };\r
 \r
+class RouteCommand : public AMCPCommandBase<true, AddToQueue, 1>\r
+{\r
+       std::wstring print() const { return L"RouteCommand";}\r
+       bool DoExecute();\r
+public:\r
+       static safe_ptr<core::frame_producer> TryCreateProducer(AMCPCommand& command, std::wstring const& uri);\r
+};\r
+\r
+/*class RouteCommand : public AMCPCommandBase<true, AddToQueue, 1>\r
+{\r
+       std::wstring print() const { return L"RouteCommand";}\r
+       bool DoExecute();\r
+};*/\r
+\r
 class LoadCommand : public AMCPCommandBase<true, AddToQueue, 1>\r
 {\r
        std::wstring print() const { return L"LoadCommand";}\r
index d89bd71abcc0a4e56dd2074c9aaacab50a0623a4..ff8270a5e6b5dcf6d5d5fca155d25f3bfc9e6ba2 100644 (file)
@@ -318,6 +318,7 @@ AMCPCommandPtr AMCPProtocolStrategy::CommandFactory(const std::wstring& str)
        else if(s == TEXT("CHANNEL_GRID"))      return std::make_shared<ChannelGridCommand>();\r
        else if(s == TEXT("CALL"))                      return std::make_shared<CallCommand>();\r
        else if(s == TEXT("SWAP"))                      return std::make_shared<SwapCommand>();\r
+       else if(s == TEXT("ROUTE"))                     return std::make_shared<RouteCommand>();\r
        else 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