\r
struct stage::impl : public std::enable_shared_from_this<impl>\r
{ \r
- spl::shared_ptr<diagnostics::graph> graph_;\r
- monitor::basic_subject event_subject_;\r
- std::map<int, layer> layers_; \r
- std::map<int, tweened_transform> tweens_; \r
- executor executor_;\r
+ spl::shared_ptr<diagnostics::graph> graph_;\r
+ monitor::basic_subject event_subject_;\r
+ reactive::basic_subject<std::map<int, class draw_frame>> frames_subject_;\r
+ std::map<int, layer> layers_; \r
+ std::map<int, tweened_transform> tweens_; \r
+ executor executor_;\r
public:\r
impl(spl::shared_ptr<diagnostics::graph> graph) \r
: graph_(std::move(graph))\r
\r
std::map<int, draw_frame> operator()(const struct video_format_desc& format_desc)\r
{ \r
- return executor_.invoke([=]() -> std::map<int, draw_frame>\r
+ auto frames = executor_.invoke([=]() -> std::map<int, draw_frame>\r
{\r
boost::timer frame_timer;\r
\r
\r
return frames;\r
});\r
+ \r
+ frames_subject_ << frames;\r
+ return frames;\r
}\r
\r
void draw(int index, const video_format_desc& format_desc, std::map<int, draw_frame>& frames)\r
std::map<int, class draw_frame> stage::operator()(const video_format_desc& format_desc){return (*impl_)(format_desc);}\r
void stage::subscribe(const monitor::observable::observer_ptr& o) {impl_->event_subject_.subscribe(o);}\r
void stage::unsubscribe(const monitor::observable::observer_ptr& o) {impl_->event_subject_.unsubscribe(o);}\r
+void stage::subscribe(const frame_observable::observer_ptr& o) {impl_->frames_subject_.subscribe(o);}\r
+void stage::unsubscribe(const frame_observable::observer_ptr& o) {impl_->frames_subject_.unsubscribe(o);}\r
}}
\ No newline at end of file
#include <boost/property_tree/ptree_fwd.hpp>\r
\r
#include <functional>\r
+#include <map>\r
#include <tuple>\r
#include <vector>\r
\r
FORWARD2(caspar, diagnostics, class graph);\r
\r
namespace caspar { namespace core {\r
+\r
+typedef reactive::observable<std::map<int, class draw_frame>> frame_observable;\r
\r
-class stage sealed : public monitor::observable\r
+class stage sealed : public monitor::observable, public frame_observable\r
{\r
stage(const stage&);\r
stage& operator=(const stage&);\r
\r
void subscribe(const monitor::observable::observer_ptr& o) override;\r
void unsubscribe(const monitor::observable::observer_ptr& o) override;\r
+ \r
+ // frame_observable\r
+\r
+ void subscribe(const frame_observable::observer_ptr& o) override;\r
+ void unsubscribe(const frame_observable::observer_ptr& o) override;\r
\r
// Properties\r
\r
#include <core/frame/frame_factory.h>\r
#include <core/frame/pixel_format.h>\r
#include <core/frame/frame.h>\r
+#include <core/video_channel.h>\r
+#include <core/producer/stage.h>\r
\r
#include <common/except.h>\r
#include <common/diagnostics/graph.h>\r
#include <tbb/concurrent_queue.h>\r
\r
#include <boost/property_tree/ptree.hpp>\r
+#include <boost/foreach.hpp>\r
+#include <boost/optional.hpp>\r
#include <boost/range/algorithm_ext/push_back.hpp>\r
+#include <boost/range/numeric.hpp>\r
+#include <boost/range/adaptor/map.hpp>\r
\r
#include <queue>\r
\r
namespace caspar { namespace reroute {\r
-// \r
-//class reroute_producer : public reactive::observer<spl::shared_ptr<const core::frame>>\r
-// , public core::frame_producer\r
-//{\r
-// const spl::shared_ptr<diagnostics::graph> graph_;\r
-// const spl::shared_ptr<core::frame_factory> frame_factory_;\r
-// \r
-// tbb::concurrent_bounded_queue<std::shared_ptr<const core::frame>> input_buffer_;\r
-// std::queue<core::draw_frame> frame_buffer_;\r
-// uint64_t frame_number_;\r
-//\r
-// core::draw_frame last_frame_;\r
-//\r
-//public:\r
-// explicit reroute_producer(const spl::shared_ptr<core::frame_factory>& frame_factory) \r
-// : frame_factory_(frame_factory)\r
-// , frame_number_(0)\r
-// , last_frame_(core::draw_frame::empty())\r
-// {\r
-// graph_->set_color("late-frame", diagnostics::color(0.6f, 0.3f, 0.3f));\r
-// graph_->set_color("dropped-frame", diagnostics::color(0.3f, 0.6f, 0.3f));\r
-// graph_->set_text(print());\r
-// diagnostics::register_graph(graph_);\r
-//\r
-// input_buffer_.set_capacity(1);\r
-// }\r
-// \r
-// // observable\r
-//\r
-// void on_next(const spl::shared_ptr<const core::frame>& frame)\r
-// {\r
-// if(!input_buffer_.try_push(frame))\r
-// graph_->set_tag("dropped-frame");\r
-// }\r
-//\r
-// // frame_producer\r
-// \r
-// core::draw_frame receive(int) override\r
-// {\r
-// if(!frame_buffer_.empty())\r
-// {\r
-// auto frame = std::move(frame_buffer_.front());\r
-// frame_buffer_.pop();\r
-// return last_frame_ = frame;\r
-// }\r
-// \r
-// std::shared_ptr<const core::frame> read_frame;\r
-// if(!input_buffer_.try_pop(read_frame))\r
-// {\r
-// graph_->set_tag("late-frame");\r
-// return core::draw_frame::late(); \r
-// }\r
-// \r
-// frame_number_++;\r
-// \r
-// bool double_speed = std::abs(frame_factory_->video_format_desc().fps / 2.0 - read_frame->frame_rate()) < 0.01; \r
-// bool half_speed = std::abs(read_frame->frame_rate() / 2.0 - frame_factory_->video_format_desc().fps) < 0.01;\r
-//\r
-// if(half_speed && frame_number_ % 2 == 0) // Skip frame\r
-// return receive(0);\r
-//\r
-// auto frame = frame_factory_->create_frame(this, read_frame->pixel_format_desc());\r
-//\r
-// A_memcpy(frame->image_data(0).begin(), read_frame->image_data().begin(), read_frame->image_data().size());\r
-// boost::push_back(frame->audio_data(), read_frame->audio_data());\r
-// \r
-// auto draw_frame = core::draw_frame(std::move(frame));\r
-//\r
-// frame_buffer_.push(draw_frame);\r
-// \r
-// if(double_speed) \r
-// frame_buffer_.push(draw_frame);\r
-//\r
-// return receive(0);\r
-// } \r
-//\r
-// core::draw_frame last_frame() const override\r
-// {\r
-// return core::draw_frame::still(last_frame_);\r
-// }\r
-// \r
-// std::wstring print() const override\r
-// {\r
-// return L"reroute[]";\r
-// }\r
-//\r
-// std::wstring name() const override\r
-// {\r
-// return L"reroute";\r
-// }\r
-//\r
-// boost::property_tree::wptree info() const override\r
-// {\r
-// boost::property_tree::wptree info;\r
-// info.add(L"type", L"rerotue-producer");\r
-// return info;\r
-// }\r
-//};\r
-\r
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, core::video_channel& channel)\r
+ \r
+class reroute_producer : public reactive::observer<std::map<int, core::draw_frame>>\r
+ , public core::frame_producer_base\r
{\r
- BOOST_THROW_EXCEPTION(not_implemented());\r
- //return core::frame_producer::empty();\r
- //auto producer = spl::make_shared<reroute_producer>(frame_factory);\r
- //o.subscribe(producer);\r
- //return core::wrap_producer(producer);\r
+ const spl::shared_ptr<diagnostics::graph> graph_;\r
+ \r
+ tbb::concurrent_bounded_queue<std::map<int, core::draw_frame>> input_buffer_;\r
+public:\r
+ explicit reroute_producer() \r
+ {\r
+ graph_->set_color("late-frame", diagnostics::color(0.6f, 0.3f, 0.3f));\r
+ graph_->set_color("dropped-frame", diagnostics::color(0.3f, 0.6f, 0.3f));\r
+ graph_->set_text(print());\r
+ diagnostics::register_graph(graph_);\r
+\r
+ input_buffer_.set_capacity(1);\r
+ }\r
+ \r
+ // observable\r
+\r
+ void on_next(const std::map<int, core::draw_frame>& frames)\r
+ {\r
+ if(!input_buffer_.try_push(frames))\r
+ {\r
+ std::map<int, core::draw_frame> dummy;\r
+ input_buffer_.try_pop(dummy);\r
+ input_buffer_.try_push(frames);\r
+\r
+ graph_->set_tag("dropped-frame");\r
+ }\r
+ }\r
+\r
+ // frame_producer\r
+ \r
+ core::draw_frame receive_impl() override\r
+ { \r
+ std::map<int, core::draw_frame> frames;\r
+ if(!input_buffer_.try_pop(frames))\r
+ {\r
+ graph_->set_tag("late-frame");\r
+ return core::draw_frame::late(); \r
+ }\r
+\r
+ return boost::accumulate(frames | boost::adaptors::map_values, core::draw_frame::empty(), core::draw_frame::over);\r
+ } \r
+ \r
+ std::wstring print() const override\r
+ {\r
+ return L"reroute[]";\r
+ }\r
+\r
+ std::wstring name() const override\r
+ {\r
+ return L"reroute";\r
+ }\r
+\r
+ boost::property_tree::wptree info() const override\r
+ {\r
+ boost::property_tree::wptree info;\r
+ info.add(L"type", L"rerotue-producer");\r
+ return info;\r
+ }\r
+ \r
+ void subscribe(const monitor::observable::observer_ptr& o) override\r
+ {\r
+ }\r
+\r
+ void unsubscribe(const monitor::observable::observer_ptr& o) override\r
+ {\r
+ }\r
+};\r
+\r
+spl::shared_ptr<core::frame_producer> create_producer(core::video_channel& channel)\r
+{\r
+ auto producer = spl::make_shared<reroute_producer>();\r
+ \r
+ std::weak_ptr<reactive::observer<std::map<int, core::draw_frame>>> o = producer;\r
+\r
+ channel.stage().subscribe(o);\r
+\r
+ return producer;\r
}\r
\r
}}
\ No newline at end of file
\r
#include <common/memory.h>\r
#include <common/forward.h>\r
-\r
-#include <core/frame/frame_factory.h>\r
-#include <core/producer/frame_producer.h>\r
-#include <core/frame/frame.h>\r
+#include <common/reactive.h>\r
\r
FORWARD2(caspar, core, class video_channel);\r
+FORWARD2(caspar, core, class frame_producer);\r
\r
namespace caspar { namespace reroute {\r
\r
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, core::video_channel& channel);\r
+spl::shared_ptr<core::frame_producer> create_producer(core::video_channel& channel);\r
\r
}}\r
#include <core/mixer/mixer.h>\r
#include <core/consumer/output.h>\r
\r
+#include <modules/reroute/producer/reroute_producer.h>\r
#include <modules/bluefish/bluefish.h>\r
#include <modules/decklink/decklink.h>\r
#include <modules/ffmpeg/ffmpeg.h>\r
{\r
BOOST_THROW_EXCEPTION(not_implemented());\r
\r
- int index = 1;\r
- auto self = GetChannels().back();\r
- \r
- std::vector<std::wstring> params;\r
- params.push_back(L"SCREEN");\r
- params.push_back(L"NAME");\r
- params.push_back(L"Channel Grid Window");\r
- auto screen = create_consumer(params);\r
-\r
- self->output().add(screen);\r
-\r
- BOOST_FOREACH(auto channel, GetChannels())\r
- {\r
- if(channel != self)\r
- {\r
- auto producer = reroute::create_producer(self->frame_factory(), *channel); \r
- self->stage().load(index, producer, false);\r
- self->stage().play(index);\r
- index++;\r
- }\r
- }\r
-\r
- int n = GetChannels().size()-1;\r
- double delta = 1.0/static_cast<double>(n);\r
- for(int x = 0; x < n; ++x)\r
- {\r
- for(int y = 0; y < n; ++y)\r
- {\r
- int index = x+y*n+1;\r
- auto transform = [=](frame_transform transform) -> frame_transform\r
- { \r
- transform.image_transform.fill_translation[0] = x*delta;\r
- transform.image_transform.fill_translation[1] = y*delta;\r
- transform.image_transform.fill_scale[0] = delta;\r
- transform.image_transform.fill_scale[1] = delta;\r
- transform.image_transform.clip_translation[0] = x*delta;\r
- transform.image_transform.clip_translation[1] = y*delta;\r
- transform.image_transform.clip_scale[0] = delta;\r
- transform.image_transform.clip_scale[1] = delta; \r
- return transform;\r
- };\r
- self->stage().apply_transform(index, transform);\r
- }\r
- }\r
-\r
- return true;\r
+ //int index = 1;\r
+ //auto self = GetChannels().back();\r
+ //\r
+ //std::vector<std::wstring> params;\r
+ //params.push_back(L"SCREEN");\r
+ //params.push_back(L"NAME");\r
+ //params.push_back(L"Channel Grid Window");\r
+ //auto screen = create_consumer(params);\r
+\r
+ //self->output().add(screen);\r
+\r
+ //BOOST_FOREACH(auto channel, GetChannels())\r
+ //{\r
+ // if(channel != self)\r
+ // {\r
+ // auto producer = reroute::create_producer(self->frame_factory(), *channel); \r
+ // self->stage().load(index, producer, false);\r
+ // self->stage().play(index);\r
+ // index++;\r
+ // }\r
+ //}\r
+\r
+ //int n = GetChannels().size()-1;\r
+ //double delta = 1.0/static_cast<double>(n);\r
+ //for(int x = 0; x < n; ++x)\r
+ //{\r
+ // for(int y = 0; y < n; ++y)\r
+ // {\r
+ // int index = x+y*n+1;\r
+ // auto transform = [=](frame_transform transform) -> frame_transform\r
+ // { \r
+ // transform.image_transform.fill_translation[0] = x*delta;\r
+ // transform.image_transform.fill_translation[1] = y*delta;\r
+ // transform.image_transform.fill_scale[0] = delta;\r
+ // transform.image_transform.fill_scale[1] = delta;\r
+ // transform.image_transform.clip_translation[0] = x*delta;\r
+ // transform.image_transform.clip_translation[1] = y*delta;\r
+ // transform.image_transform.clip_scale[0] = delta;\r
+ // transform.image_transform.clip_scale[1] = delta; \r
+ // return transform;\r
+ // };\r
+ // self->stage().apply_transform(index, transform);\r
+ // }\r
+ //}\r
+\r
+ //return true;\r
}\r
\r
bool CallCommand::DoExecute()\r
//Perform loading of the clip\r
try\r
{\r
- _parameters[0] = _parameters[0];\r
- auto pFP = create_producer(GetChannel()->frame_factory(), GetChannel()->video_format_desc(), _parameters);\r
+ std::shared_ptr<core::frame_producer> pFP;\r
+ \r
+ static boost::wregex expr(L"\\[(?<CHANNEL>\\d+)\\]", boost::regex::icase);\r
+ \r
+ boost::wsmatch what;\r
+ if(boost::regex_match(_parameters.at(0), what, expr))\r
+ {\r
+ auto channel_index = boost::lexical_cast<int>(what["CHANNEL"].str());\r
+ pFP = reroute::create_producer(*GetChannels().at(channel_index-1)); \r
+ }\r
+ else\r
+ pFP = create_producer(GetChannel()->frame_factory(), GetChannel()->video_format_desc(), _parameters);\r
+ \r
if(pFP == frame_producer::empty())\r
BOOST_THROW_EXCEPTION(file_not_found() << msg_info(_parameters.size() > 0 ? _parameters[0] : L""));\r
\r
bool auto_play = std::find(_parameters.begin(), _parameters.end(), L"AUTO") != _parameters.end();\r
\r
- auto pFP2 = create_transition_producer(GetChannel()->video_format_desc().field_mode, pFP, transitionInfo);\r
+ auto pFP2 = create_transition_producer(GetChannel()->video_format_desc().field_mode, spl::make_shared_ptr(pFP), transitionInfo);\r
if(auto_play)\r
GetChannel()->stage().load(GetLayerIndex(), pFP2, false, transitionInfo.duration); // TODO: LOOP\r
else\r
GetChannel()->stage().load(GetLayerIndex(), pFP2, false); // TODO: LOOP\r
\r
+ \r
SetReplyString(TEXT("202 LOADBG OK\r\n"));\r
\r
return true;\r
{\r
LoadbgCommand lbg;\r
lbg.SetChannel(GetChannel());\r
+ lbg.SetChannels(GetChannels());\r
lbg.SetChannelIndex(GetChannelIndex());\r
lbg.SetLayerIntex(GetLayerIndex());\r
lbg.SetClientInfo(GetClientInfo());\r
}\r
\r
pCommand->SetChannel(pChannel);\r
+ pCommand->SetChannels(channels_);\r
pCommand->SetChannelIndex(channelIndex);\r
pCommand->SetLayerIntex(layerIndex);\r
\r
</paths>\r
<log-level>trace</log-level>\r
<accelerator>auto</accelerator>\r
- <force-deinterlacing>false</force-deinterlacing>\r
<flash>\r
<buffer-depth>4</buffer-depth>\r
</flash>\r
<channels>\r
<channel>\r
- <video-mode>NTSC</video-mode>\r
+ <video-mode>720p5000</video-mode>\r
<consumers>\r
<screen>\r
<device>1</device>\r
- <name>PROGRAM</name>\r
- <aspect-ratio>default</aspect-ratio>\r
- <stretch>uniform</stretch>\r
- <windowed>true</windowed>\r
- <key-only>false</key-only>\r
- <auto-deinterlace>true</auto-deinterlace>\r
- <vsync>true</vsync>\r
+ </screen>\r
+ </consumers>\r
+ </channel>\r
+ <channel>\r
+ <video-mode>720p5000</video-mode>\r
+ <consumers>\r
+ <screen>\r
+ <device>2</device>\r
</screen>\r
</consumers>\r
</channel>\r