});\r
}\r
\r
- void reset(const std::function<T*()>& factory)\r
+ void reset(const std::function<T*()>& factory = nullptr)\r
{\r
executor::invoke([&]\r
{\r
+ instance_.reset();\r
if(factory)\r
instance_.reset(factory());\r
- else\r
- instance_.reset(nullptr);\r
});\r
}\r
\r
#include <GLee.h>\r
#include <SFML/Window.hpp>\r
\r
-#include <tchar.h>\r
-#include <sstream>\r
-#include <memory>\r
+#include <algorithm>\r
#include <array>\r
#include <functional>\r
-#include <algorithm>\r
-#include <vector>\r
#include <deque>\r
+#include <map>\r
+#include <memory>\r
#include <queue>\r
#include <string>\r
-#include <math.h>\r
+#include <vector>\r
\r
#include <tbb/atomic.h>\r
#include <tbb/concurrent_queue.h>\r
#include <boost/filesystem.hpp>\r
#include <boost/foreach.hpp>\r
#include <boost/range/algorithm.hpp>\r
-#include <boost/signals2.hpp>\r
\r
#include <common/utility/string.h>\r
#include <common/memory/safe_ptr.h>\r
#include "channel.h"\r
\r
#include "video_format.h"\r
-#include "consumer/frame_consumer_device.h"\r
-#include "mixer/frame_mixer_device.h"\r
-#include "producer/frame_producer_device.h"\r
#include "producer/layer.h"\r
\r
#include <common/concurrency/executor.h>\r
\r
#include <boost/range/algorithm_ext/erase.hpp>\r
\r
-#include <tbb/parallel_for.h>\r
-\r
-#include <memory>\r
-\r
#ifdef _MSC_VER\r
#pragma warning(disable : 4355)\r
#endif\r
const int index_;\r
video_format_desc format_desc_;\r
\r
- safe_ptr<frame_mixer_device> mixer_; // Mixer must be destroyed last in order to make sure that all frames have been returned to the pool.\r
- safe_ptr<frame_consumer_device> consumer_;\r
- safe_ptr<frame_producer_device> producer_;\r
-\r
- boost::signals2::scoped_connection mixer_connection_;\r
- boost::signals2::scoped_connection producer_connection_;\r
-\r
+ std::shared_ptr<frame_consumer_device> consumer_;\r
+ std::shared_ptr<frame_mixer_device> mixer_;\r
+ std::shared_ptr<frame_producer_device> producer_;\r
+ \r
public:\r
implementation(int index, const video_format_desc& format_desc) \r
: index_(index)\r
, format_desc_(format_desc)\r
+ , mixer_(new frame_mixer_device(format_desc, [=](const safe_ptr<const read_frame>& frame){consumer_->send(frame);}))\r
, consumer_(new frame_consumer_device(format_desc))\r
- , mixer_(new frame_mixer_device(format_desc))\r
- , producer_(new frame_producer_device(format_desc_)) \r
- , mixer_connection_(mixer_->connect([=](const safe_ptr<const read_frame>& frame){consumer_->send(frame);}))\r
- , producer_connection_(producer_->connect([=](const std::map<int, safe_ptr<basic_frame>>& frames){mixer_->send(frames);}))\r
+ , producer_(new frame_producer_device(format_desc_, [=](const std::map<int, safe_ptr<basic_frame>>& frames){mixer_->send(frames);})) \r
{\r
CASPAR_LOG(info) << print() << " Successfully Initialized.";\r
}\r
void set_video_format_desc(const video_format_desc& format_desc)\r
{\r
format_desc_ = format_desc;\r
- producer_connection_.disconnect();\r
- mixer_connection_.disconnect();\r
+ producer_.reset();\r
+ mixer_.reset();\r
\r
consumer_->set_video_format_desc(format_desc_);\r
- mixer_ = make_safe<frame_mixer_device>(format_desc_);\r
- producer_ = make_safe<frame_producer_device>(format_desc_);\r
-\r
- mixer_connection_ = mixer_->connect([=](const safe_ptr<const read_frame>& frame){consumer_->send(frame);});\r
- producer_connection_ = producer_->connect([=](const std::map<int, safe_ptr<basic_frame>>& frames){mixer_->send(frames);});\r
+ mixer_ = make_safe<frame_mixer_device>(format_desc_, [=](const safe_ptr<const read_frame>& frame){consumer_->send(frame);});\r
+ producer_ = make_safe<frame_producer_device>(format_desc_, [=](const std::map<int, safe_ptr<basic_frame>>& frames){mixer_->send(frames);});\r
}\r
};\r
\r
channel::channel(int index, const video_format_desc& format_desc) : impl_(new implementation(index, format_desc)){}\r
channel::channel(channel&& other) : impl_(std::move(other.impl_)){}\r
-const safe_ptr<frame_producer_device>& channel::producer() { return impl_->producer_;} \r
-const safe_ptr<frame_mixer_device>& channel::mixer() { return impl_->mixer_;} \r
-const safe_ptr<frame_consumer_device>& channel::consumer() { return impl_->consumer_;} \r
+safe_ptr<frame_producer_device> channel::producer() { return make_safe(impl_->producer_);} \r
+safe_ptr<frame_mixer_device> channel::mixer() { return make_safe(impl_->mixer_);} \r
+safe_ptr<frame_consumer_device> channel::consumer() { return make_safe(impl_->consumer_);} \r
const video_format_desc& channel::get_video_format_desc() const{return impl_->format_desc_;}\r
void channel::set_video_format_desc(const video_format_desc& format_desc){impl_->set_video_format_desc(format_desc);}\r
std::wstring channel::print() const { return impl_->print();}\r
#include <common/memory/safe_ptr.h>\r
\r
#include <boost/noncopyable.hpp>\r
-#include <boost/thread/future.hpp>\r
\r
namespace caspar { namespace core {\r
-\r
+ \r
class channel : boost::noncopyable\r
{\r
public:\r
explicit channel(int index, const video_format_desc& format_desc);\r
channel(channel&& other);\r
\r
- const safe_ptr<frame_producer_device>& producer();\r
- const safe_ptr<frame_mixer_device>& mixer();\r
- const safe_ptr<frame_consumer_device>& consumer();\r
+ safe_ptr<frame_producer_device> producer();\r
+ safe_ptr<frame_mixer_device> mixer();\r
+ safe_ptr<frame_consumer_device> consumer();\r
\r
const video_format_desc& get_video_format_desc() const;\r
void set_video_format_desc(const video_format_desc& format_desc);\r
audio_mixer audio_mixer_;\r
image_mixer image_mixer_;\r
\r
- output_t output_;\r
+ std::function<void(const safe_ptr<const core::read_frame>&)> output_;\r
\r
typedef std::unordered_map<int, tweened_transform<core::image_transform>> image_transforms;\r
typedef std::unordered_map<int, tweened_transform<core::audio_transform>> audio_transforms;\r
\r
executor executor_;\r
public:\r
- implementation(const core::video_format_desc& format_desc) \r
+ implementation(const core::video_format_desc& format_desc, const std::function<void(const safe_ptr<const core::read_frame>&)>& output) \r
: format_desc_(format_desc)\r
, diag_(diagnostics::create_graph(narrow(print())))\r
, image_mixer_(format_desc)\r
+ , output_(output)\r
, executor_(L"frame_mixer_device")\r
{\r
diag_->add_guide("frame-time", 0.5f); \r
\r
CASPAR_LOG(info) << print() << L" Successfully initialized."; \r
}\r
-\r
- boost::signals2::connection connect(const output_t::slot_type& subscriber)\r
- {\r
- return output_.connect(subscriber);\r
- }\r
-\r
+ \r
boost::unique_future<safe_ptr<const host_buffer>> mix_image(std::map<int, safe_ptr<core::basic_frame>> frames)\r
{ \r
auto& root_image_transform = boost::fusion::at_key<core::image_transform>(root_transforms_);\r
}\r
};\r
\r
-frame_mixer_device::frame_mixer_device(const core::video_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
+frame_mixer_device::frame_mixer_device(const core::video_format_desc& format_desc, const std::function<void(const safe_ptr<const core::read_frame>&)>& output) : impl_(new implementation(format_desc, output)){}\r
frame_mixer_device::frame_mixer_device(frame_mixer_device&& other) : impl_(std::move(other.impl_)){}\r
-boost::signals2::connection frame_mixer_device::connect(const output_t::slot_type& subscriber){return impl_->connect(subscriber);}\r
void frame_mixer_device::send(const std::map<int, safe_ptr<core::basic_frame>>& frames){impl_->send(frames);}\r
const core::video_format_desc& frame_mixer_device::get_video_format_desc() const { return impl_->format_desc_; }\r
safe_ptr<core::write_frame> frame_mixer_device::create_frame(void* tag, const core::pixel_format_desc& desc){ return impl_->create_frame(tag, desc); } \r
\r
#include <common/memory/safe_ptr.h>\r
\r
-#include <boost/signals2.hpp>\r
-\r
#include <functional>\r
+#include <map>\r
\r
namespace caspar { \r
\r
\r
class frame_mixer_device : public core::frame_factory\r
{\r
-public:\r
- typedef boost::signals2::signal<void(const safe_ptr<const core::read_frame>&)> output_t;\r
- \r
- boost::signals2::connection connect(const output_t::slot_type& subscriber);\r
- \r
- frame_mixer_device(const core::video_format_desc& format_desc);\r
+public: \r
+ frame_mixer_device(const core::video_format_desc& format_desc, const std::function<void(const safe_ptr<const core::read_frame>&)>& output);\r
frame_mixer_device(frame_mixer_device&& other); // nothrow\r
\r
void send(const std::map<int, safe_ptr<core::basic_frame>>& frames); // nothrow\r
\r
#include <tbb/parallel_for.h>\r
#include <tbb/mutex.h>\r
-#include <tbb/combinable.h>\r
\r
#include <array>\r
#include <memory>\r
\r
safe_ptr<diagnostics::graph> diag_;\r
\r
- output_t output_;\r
+ const std::function<void(const std::map<int, safe_ptr<basic_frame>>&)> output_;\r
\r
boost::timer frame_timer_;\r
boost::timer tick_timer_;\r
\r
mutable executor executor_;\r
public:\r
- implementation(const video_format_desc& format_desc) \r
+ implementation(const video_format_desc& format_desc, const std::function<void(const std::map<int, safe_ptr<basic_frame>>&)>& output) \r
: format_desc_(format_desc)\r
, diag_(diagnostics::create_graph(std::string("frame_producer_device")))\r
, executor_(L"frame_producer_device")\r
+ , output_(output)\r
{\r
diag_->add_guide("frame-time", 0.5f); \r
diag_->set_color("frame-time", diagnostics::color(1.0f, 0.0f, 0.0f));\r
{\r
SetThreadPriority(GetCurrentThread(), ABOVE_NORMAL_PRIORITY_CLASS);\r
});\r
+ executor_.begin_invoke([=]{tick();}); \r
}\r
-\r
- boost::signals2::connection connect(const output_t::slot_type& subscriber)\r
- {\r
- return executor_.invoke([&]() -> boost::signals2::connection\r
- {\r
- if(output_.empty())\r
- executor_.begin_invoke([=]{tick();}); \r
- return output_.connect(subscriber);\r
- });\r
- }\r
- \r
+ \r
void tick()\r
{ \r
- if(output_.empty())\r
- return; \r
- \r
auto frame = draw();\r
output_timer_.restart();\r
output_(frame);\r
{ \r
frame_timer_.restart();\r
\r
- tbb::combinable<std::map<int, safe_ptr<basic_frame>>> frames;\r
+ std::map<int, safe_ptr<basic_frame>> frames;\r
+ for(auto it = layers_.begin(); it != layers_.end(); ++it)\r
+ frames[it->first] = basic_frame::empty();\r
\r
tbb::parallel_for_each(layers_.begin(), layers_.end(), [&](decltype(*layers_.begin())& pair)\r
{\r
auto frame = pair.second.receive();\r
if(is_concrete_frame(frame))\r
- frames.local()[pair.first] = frame; \r
+ frames[pair.first] = frame; \r
});\r
-\r
- std::map<int, safe_ptr<basic_frame>> result;\r
- frames.combine_each([&](const std::map<int, safe_ptr<basic_frame>>& map)\r
- {\r
- result.insert(map.begin(), map.end());\r
- });\r
-\r
+ \r
diag_->update_value("frame-time", static_cast<float>(frame_timer_.elapsed()*format_desc_.fps*0.5));\r
- \r
+\r
diag_->update_value("tick-time", static_cast<float>(tick_timer_.elapsed()*format_desc_.fps*0.5));\r
tick_timer_.restart();\r
\r
- return result;\r
+ return frames;\r
}\r
\r
void load(int index, const safe_ptr<frame_producer>& producer, bool preview)\r
}\r
};\r
\r
-frame_producer_device::frame_producer_device(const video_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
+frame_producer_device::frame_producer_device(const video_format_desc& format_desc, const std::function<void(const std::map<int, safe_ptr<basic_frame>>&)>& output) : impl_(new implementation(format_desc, output)){}\r
frame_producer_device::frame_producer_device(frame_producer_device&& other) : impl_(std::move(other.impl_)){}\r
-boost::signals2::connection frame_producer_device::connect(const output_t::slot_type& subscriber){return impl_->connect(subscriber);}\r
void frame_producer_device::swap(frame_producer_device& other){impl_->swap(other);}\r
void frame_producer_device::load(int index, const safe_ptr<frame_producer>& producer, bool preview){impl_->load(index, producer, preview);}\r
void frame_producer_device::pause(int index){impl_->pause(index);}\r
#include <common/memory/safe_ptr.h>\r
\r
#include <boost/noncopyable.hpp>\r
-#include <boost/signals2.hpp>\r
#include <boost/thread/future.hpp>\r
\r
namespace caspar { namespace core {\r
class frame_producer_device : boost::noncopyable\r
{\r
public:\r
- typedef boost::signals2::signal<void(const std::map<int, safe_ptr<basic_frame>>&)> output_t;\r
- \r
- explicit frame_producer_device(const video_format_desc& format_desc);\r
+ explicit frame_producer_device(const video_format_desc& format_desc, const std::function<void(const std::map<int, safe_ptr<basic_frame>>&)>& output);\r
frame_producer_device(frame_producer_device&& other);\r
- \r
- boost::signals2::connection connect(const output_t::slot_type& subscriber);\r
\r
void swap(frame_producer_device& other);\r
\r
<videomode>1080i5000</videomode>\r
<consumers>\r
<decklink>\r
- <device>1</device> <!-- [1..] Specifies which device to use. -->\r
- <embedded-audio>true</embedded-audio> <!-- [true/false] -->\r
- <low-latency>false</low-latency> <!-- [true/false] - Experimental feature that reduces frame delay by 3 frames or less. -->\r
- <external-key>true</external-key> <!-- [true/false]-->\r
- <key-only>false</key-only> <!-- [true/false] - Copies key into fill channels. -->\r
+ <device>1</device> \r
+ <embedded-audio>true</embedded-audio> \r
+ <low-latency>true</low-latency> \r
+ <external-key>true</external-key> \r
+ <key-only>false</key-only> \r
</decklink>\r
<!--<audio>\r
</audio>-->\r