\r
#include "frame_producer.h"\r
\r
+#include "../video_format.h"\r
#include "../frame/draw_frame.h"\r
#include "../frame/frame_transform.h"\r
\r
\r
struct layer::impl\r
{ \r
+ monitor::subject event_subject_;\r
spl::shared_ptr<frame_producer> foreground_;\r
spl::shared_ptr<frame_producer> background_;\r
int64_t frame_number_;\r
bool is_paused_;\r
\r
public:\r
- impl() \r
- : foreground_(frame_producer::empty())\r
+ impl(int index) \r
+ : event_subject_(monitor::path("layer") % index)\r
+ , foreground_(frame_producer::empty())\r
, background_(frame_producer::empty())\r
, frame_number_(0)\r
, is_paused_(false)\r
pause();\r
}\r
\r
- spl::shared_ptr<draw_frame> receive(frame_producer::flags flags)\r
+ spl::shared_ptr<draw_frame> receive(frame_producer::flags flags, const video_format_desc& format_desc)\r
{ \r
try\r
{\r
if(frames_left < 1)\r
{\r
play();\r
- return receive(flags);\r
+ return receive(flags, format_desc);\r
}\r
}\r
+\r
+ event_subject_ << monitor::event("state") % u8(is_paused_ ? L"paused" : (foreground_ == frame_producer::empty() ? L"stopped" : L"playing")) \r
+ << monitor::event("time") % monitor::duration(frame_number_/format_desc.fps)\r
+ % monitor::duration(static_cast<int64_t>(foreground_->nb_frames()) - static_cast<int64_t>(auto_play_delta_ ? *auto_play_delta_ : 0)/format_desc.fps)\r
+ << monitor::event("frame") % static_cast<int64_t>(frame_number_)\r
+ % static_cast<int64_t>((static_cast<int64_t>(foreground_->nb_frames()) - static_cast<int64_t>(auto_play_delta_ ? *auto_play_delta_ : 0)));\r
\r
return frame;\r
}\r
}\r
};\r
\r
-layer::layer() : impl_(new impl()){}\r
-layer::layer(const layer& other) : impl_(new impl(*other.impl_)){}\r
+layer::layer(int index) : impl_(new impl(index)){}\r
layer::layer(layer&& other) : impl_(std::move(other.impl_)){}\r
-layer& layer::operator=(layer other)\r
+layer& layer::operator=(layer&& other)\r
{\r
other.swap(*this);\r
return *this;\r
void layer::play(){impl_->play();}\r
void layer::pause(){impl_->pause();}\r
void layer::stop(){impl_->stop();}\r
-spl::shared_ptr<draw_frame> layer::receive(frame_producer::flags flags) {return impl_->receive(flags);}\r
+spl::shared_ptr<draw_frame> layer::receive(frame_producer::flags flags, const video_format_desc& format_desc) {return impl_->receive(flags, format_desc);}\r
spl::shared_ptr<frame_producer> layer::foreground() const { return impl_->foreground_;}\r
spl::shared_ptr<frame_producer> layer::background() const { return impl_->background_;}\r
boost::property_tree::wptree layer::info() const{return impl_->info();}\r
+void layer::subscribe(const monitor::observable::observer_ptr& o) {impl_->event_subject_.subscribe(o);}\r
+void layer::unsubscribe(const monitor::observable::observer_ptr& o) {impl_->event_subject_.unsubscribe(o);}\r
}}
\ No newline at end of file
\r
#include <tbb/parallel_for_each.h>\r
\r
+#include <functional>\r
#include <map>\r
#include <vector>\r
\r
struct stage::impl : public std::enable_shared_from_this<impl>\r
{ \r
spl::shared_ptr<diagnostics::graph> graph_;\r
+ spl::shared_ptr<monitor::subject> event_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
+ , event_subject_(new monitor::subject("stage"))\r
, executor_(L"stage")\r
{\r
graph_->set_color("produce-time", diagnostics::color(0.0f, 1.0f, 0.0f));\r
boost::timer frame_timer;\r
\r
std::map<int, spl::shared_ptr<class draw_frame>> frames;\r
-\r
+ \r
try\r
- { \r
- BOOST_FOREACH(auto& layer, layers_) \r
- frames[layer.first] = draw_frame::empty(); \r
+ { \r
+ std::vector<int> indices;\r
\r
- auto format_desc2 = format_desc;\r
-\r
- tbb::parallel_for_each(layers_.begin(), layers_.end(), [&](std::map<int, layer>::value_type& layer)\r
+ BOOST_FOREACH(auto& layer, layers_) \r
{\r
- auto& tween = tweens_[layer.first];\r
- auto transform = tween.fetch_and_tick(1);\r
-\r
- frame_producer::flags flags = frame_producer::flags::none;\r
- if(format_desc2.field_mode != field_mode::progressive)\r
- {\r
- flags |= std::abs(transform.fill_scale[1] - 1.0) > 0.0001 ? frame_producer::flags::deinterlace : frame_producer::flags::none;\r
- flags |= std::abs(transform.fill_translation[1]) > 0.0001 ? frame_producer::flags::deinterlace : frame_producer::flags::none;\r
- }\r
-\r
- if(transform.is_key)\r
- flags |= frame_producer::flags::alpha_only;\r
+ frames[layer.first] = draw_frame::empty(); \r
+ indices.push_back(layer.first);\r
+ } \r
\r
- auto frame = layer.second.receive(flags); \r
- \r
- auto frame1 = spl::make_shared<core::draw_frame>(frame);\r
- frame1->get_frame_transform() = transform;\r
-\r
- if(format_desc2.field_mode != core::field_mode::progressive)\r
- { \r
- auto frame2 = spl::make_shared<core::draw_frame>(frame);\r
- frame2->get_frame_transform() = tween.fetch_and_tick(1);\r
- frame1 = core::draw_frame::interlace(frame1, frame2, format_desc2.field_mode);\r
- }\r
-\r
- frames[layer.first] = frame1;\r
- }); \r
+ // WORKAROUND: Compiler doesn't seem to like lambda.\r
+ tbb::parallel_for_each(indices.begin(), indices.end(), std::bind(&stage::impl::draw, this, std::placeholders::_1, std::ref(format_desc), std::ref(frames)));\r
}\r
catch(...)\r
{\r
return frames;\r
});\r
}\r
+\r
+ void draw(int index, const video_format_desc& format_desc, std::map<int, spl::shared_ptr<draw_frame>>& frames)\r
+ {\r
+ auto& layer = layers_[index];\r
+ auto& tween = tweens_[index];\r
+ auto transform = tween.fetch_and_tick(1);\r
+\r
+ frame_producer::flags flags = frame_producer::flags::none;\r
+ if(format_desc.field_mode != field_mode::progressive)\r
+ {\r
+ flags |= std::abs(transform.fill_scale[1] - 1.0) > 0.0001 ? frame_producer::flags::deinterlace : frame_producer::flags::none;\r
+ flags |= std::abs(transform.fill_translation[1]) > 0.0001 ? frame_producer::flags::deinterlace : frame_producer::flags::none;\r
+ }\r
+\r
+ if(transform.is_key)\r
+ flags |= frame_producer::flags::alpha_only;\r
+\r
+ auto frame = layer.receive(flags, format_desc); \r
+ \r
+ auto frame1 = spl::make_shared<core::draw_frame>(frame);\r
+ frame1->get_frame_transform() = transform;\r
+\r
+ if(format_desc.field_mode != core::field_mode::progressive)\r
+ { \r
+ auto frame2 = spl::make_shared<core::draw_frame>(frame);\r
+ frame2->get_frame_transform() = tween.fetch_and_tick(1);\r
+ frame1 = core::draw_frame::interlace(frame1, frame2, format_desc.field_mode);\r
+ }\r
+\r
+ frames[index] = frame;\r
+ }\r
+\r
+ layer& get_layer(int index)\r
+ {\r
+ auto it = layers_.find(index);\r
+ if(it == std::end(layers_))\r
+ {\r
+ it = layers_.insert(std::make_pair(index, layer(index))).first;\r
+ it->second.subscribe(event_subject_);\r
+ }\r
+ return it->second;\r
+ }\r
\r
void apply_transforms(const std::vector<std::tuple<int, stage::transform_func_t, unsigned int, tweener>>& transforms)\r
{\r
{\r
executor_.begin_invoke([=]\r
{\r
- layers_[index].load(producer, auto_play_delta);\r
+ get_layer(index).load(producer, auto_play_delta);\r
}, task_priority::high_priority);\r
}\r
\r
}, task_priority::high_priority);\r
} \r
\r
- void swap_layers(const spl::shared_ptr<stage>& other)\r
+ void swap_layers(stage& other)\r
{\r
- if(other->impl_.get() == this)\r
+ auto other_impl = other.impl_;\r
+\r
+ if(other_impl.get() == this)\r
return;\r
\r
auto func = [=]\r
{\r
- std::swap(layers_, other->impl_->layers_);\r
+ auto layers = layers_ | boost::adaptors::map_values;\r
+ auto other_layers = other_impl->layers_ | boost::adaptors::map_values;\r
+\r
+ BOOST_FOREACH(auto& layer, layers)\r
+ layer.unsubscribe(event_subject_);\r
+ \r
+ BOOST_FOREACH(auto& layer, other_layers)\r
+ layer.unsubscribe(event_subject_);\r
+ \r
+ std::swap(layers_, other_impl->layers_);\r
+ \r
+ BOOST_FOREACH(auto& layer, layers)\r
+ layer.subscribe(event_subject_);\r
+ \r
+ BOOST_FOREACH(auto& layer, other_layers)\r
+ layer.subscribe(event_subject_);\r
}; \r
executor_.begin_invoke([=]\r
{\r
- other->impl_->executor_.invoke(func, task_priority::high_priority);\r
+ other_impl->executor_.invoke(func, task_priority::high_priority);\r
}, task_priority::high_priority);\r
}\r
\r
}, task_priority::high_priority);\r
}\r
\r
- void swap_layer(int index, int other_index, const spl::shared_ptr<stage>& other)\r
+ void swap_layer(int index, int other_index, stage& other)\r
{\r
- if(other->impl_.get() == this)\r
+ auto other_impl = other.impl_;\r
+\r
+ if(other_impl.get() == this)\r
swap_layer(index, other_index);\r
else\r
{\r
auto func = [=]\r
{\r
- std::swap(layers_[index], other->impl_->layers_[other_index]);\r
+ auto& my_layer = get_layer(index);\r
+ auto& other_layer = other_impl->get_layer(other_index);\r
+\r
+ my_layer.unsubscribe(event_subject_);\r
+ other_layer.unsubscribe(other_impl->event_subject_);\r
+\r
+ std::swap(my_layer, other_layer);\r
+\r
+ my_layer.subscribe(event_subject_);\r
+ other_layer.subscribe(other_impl->event_subject_);\r
}; \r
executor_.begin_invoke([=]\r
{\r
- other->impl_->executor_.invoke(func, task_priority::high_priority);\r
+ other_impl->executor_.invoke(func, task_priority::high_priority);\r
}, task_priority::high_priority);\r
}\r
}\r
void stage::stop(int index){impl_->stop(index);}\r
void stage::clear(int index){impl_->clear(index);}\r
void stage::clear(){impl_->clear();}\r
-void stage::swap_layers(const spl::shared_ptr<stage>& other){impl_->swap_layers(other);}\r
+void stage::swap_layers(stage& other){impl_->swap_layers(other);}\r
void stage::swap_layer(int index, int other_index){impl_->swap_layer(index, other_index);}\r
-void stage::swap_layer(int index, int other_index, const spl::shared_ptr<stage>& other){impl_->swap_layer(index, other_index, other);}\r
+void stage::swap_layer(int index, int other_index, stage& other){impl_->swap_layer(index, other_index, other);}\r
boost::unique_future<spl::shared_ptr<frame_producer>> stage::foreground(int index) {return impl_->foreground(index);}\r
boost::unique_future<spl::shared_ptr<frame_producer>> stage::background(int index) {return impl_->background(index);}\r
boost::unique_future<boost::property_tree::wptree> stage::info() const{return impl_->info();}\r
boost::unique_future<boost::property_tree::wptree> stage::info(int index) const{return impl_->info(index);}\r
std::map<int, spl::shared_ptr<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
}}
\ No newline at end of file
struct video_channel::impl sealed : public frame_factory\r
{\r
reactive::basic_subject<spl::shared_ptr<const data_frame>> frame_subject_;\r
- monitor::subject event_subject_;\r
+ spl::shared_ptr<monitor::subject> event_subject_;\r
\r
const int index_;\r
\r
executor executor_;\r
public:\r
impl(int index, const video_format_desc& format_desc, spl::shared_ptr<image_mixer> image_mixer) \r
- : event_subject_(monitor::path() % "channel" % index)\r
+ : event_subject_(new monitor::subject(monitor::path() % "channel" % index))\r
, index_(index)\r
, format_desc_(format_desc)\r
, output_(new caspar::core::output(graph_, format_desc, index))\r
graph_->set_text(print());\r
diagnostics::register_graph(graph_);\r
\r
+ stage_->subscribe(event_subject_);\r
+\r
executor_.begin_invoke([=]{tick();});\r
\r
CASPAR_LOG(info) << print() << " Successfully Initialized.";\r
\r
graph_->set_value("tick-time", frame_timer.elapsed()*format_desc.fps*0.5);\r
\r
- event_subject_ << monitor::event("debug/time") % frame_timer.elapsed();\r
- event_subject_ << monitor::event("format") % u8(format_desc.name);\r
+ *event_subject_ << monitor::event("debug/time") % frame_timer.elapsed();\r
+ *event_subject_ << monitor::event("format") % u8(format_desc.name);\r
}\r
catch(...)\r
{\r
boost::property_tree::wptree video_channel::info() const{return impl_->info();}\r
void video_channel::subscribe(const frame_observer::observer_ptr& o) {impl_->frame_subject_.subscribe(o);}\r
void video_channel::unsubscribe(const frame_observer::observer_ptr& o) {impl_->frame_subject_.unsubscribe(o);} \r
-void video_channel::subscribe(const event_observer::observer_ptr& o) {impl_->event_subject_.subscribe(o);}\r
-void video_channel::unsubscribe(const event_observer::observer_ptr& o) {impl_->event_subject_.unsubscribe(o);}\r
+void video_channel::subscribe(const monitor::observable::observer_ptr& o) {impl_->event_subject_->subscribe(o);}\r
+void video_channel::unsubscribe(const monitor::observable::observer_ptr& o) {impl_->event_subject_->unsubscribe(o);}\r
\r
}}
\ No newline at end of file