spl::shared_ptr<observer_function<typename std::decay<typename detail::function_traits<F>::arg1_type>::type, F>> \r
make_observer(F func)\r
{\r
- return std::make_shared<observer_function<std::decay<typename detail::function_traits<F>::arg1_type>::type, F>>(std::move(func));\r
+ return spl::make_shared<observer_function<std::decay<typename detail::function_traits<F>::arg1_type>::type, F>>(std::move(func));\r
}\r
\r
template<typename T>\r
return L"color[" + color_str_ + L"]";\r
}\r
\r
+ virtual std::wstring name() const override\r
+ {\r
+ return L"color";\r
+ }\r
+\r
boost::property_tree::wptree info() const override\r
{\r
boost::property_tree::wptree info;\r
virtual void set_frame_factory(const spl::shared_ptr<frame_factory>&){}\r
virtual uint32_t nb_frames() const {return 0;}\r
virtual std::wstring print() const { return L"empty";}\r
+ virtual void subscribe(const monitor::observable::observer_ptr& o){}\r
+ virtual void unsubscribe(const monitor::observable::observer_ptr& o){} \r
+ virtual std::wstring name() const {return L"empty";}\r
\r
virtual boost::property_tree::wptree info() const override\r
{\r
virtual spl::shared_ptr<draw_frame> receive(int hints) override {return producer_->receive(hints);}\r
virtual spl::shared_ptr<draw_frame> last_frame() const override {return producer_->last_frame();}\r
virtual std::wstring print() const override {return producer_->print();}\r
+ virtual std::wstring name() const override {return producer_->name();}\r
virtual boost::property_tree::wptree info() const override {return producer_->info();}\r
virtual boost::unique_future<std::wstring> call(const std::wstring& str) override {return producer_->call(str);}\r
virtual spl::shared_ptr<frame_producer> get_following_producer() const override {return producer_->get_following_producer();}\r
virtual void set_leading_producer(const spl::shared_ptr<frame_producer>& producer) override {return producer_->set_leading_producer(producer);}\r
virtual uint32_t nb_frames() const override {return producer_->nb_frames();}\r
+ virtual void subscribe(const monitor::observable::observer_ptr& o) {return producer_->subscribe(o);}\r
+ virtual void unsubscribe(const monitor::observable::observer_ptr& o) {return producer_->unsubscribe(o);}\r
};\r
\r
class follow_producer_proxy : public producer_proxy_base\r
{ \r
+ spl::shared_ptr<monitor::subject> event_subject_;\r
public:\r
follow_producer_proxy(spl::shared_ptr<frame_producer>&& producer) \r
: producer_proxy_base(std::move(producer))\r
+ , event_subject_(new monitor::subject("asd"))\r
{\r
+ producer->subscribe(event_subject_);\r
}\r
\r
virtual spl::shared_ptr<draw_frame> receive(int hints) override \r
if(following != frame_producer::empty())\r
{\r
following->set_leading_producer(spl::make_shared_ptr(producer_));\r
+\r
+ producer_->unsubscribe(event_subject_);\r
producer_ = std::move(following);\r
+ event_subject_->subscribe(event_subject_);\r
}\r
\r
return receive(hints);\r
{\r
return draw_frame::mute(producer_->last_frame());\r
}\r
+\r
+ virtual void subscribe(const monitor::observable::observer_ptr& o) override \r
+ {\r
+ return event_subject_->subscribe(o);\r
+ }\r
+\r
+ virtual void unsubscribe(const monitor::observable::observer_ptr& o) override \r
+ {\r
+ return event_subject_->unsubscribe(o);\r
+ }\r
};\r
\r
class destroy_producer_proxy : public producer_proxy_base\r
\r
#pragma once\r
\r
+#include "../monitor/monitor.h"\r
+\r
#include <common/forward.h>\r
#include <common/spl/memory.h>\r
#include <common/enum_class.h>\r
\r
namespace caspar { namespace core {\r
\r
-struct frame_producer : boost::noncopyable\r
+struct frame_producer : public monitor::observable\r
+ , boost::noncopyable\r
{\r
struct flags_def\r
{\r
virtual ~frame_producer(){} \r
\r
virtual std::wstring print() const = 0; // nothrow\r
+ virtual std::wstring name() const = 0;\r
virtual boost::property_tree::wptree info() const = 0;\r
\r
virtual boost::unique_future<std::wstring> call(const std::wstring&);\r
virtual spl::shared_ptr<class draw_frame> receive(int flags) = 0;\r
virtual spl::shared_ptr<class draw_frame> last_frame() const = 0;\r
\r
+\r
static const spl::shared_ptr<frame_producer>& empty(); // nothrow\r
+\r
+ // monitor::observable\r
+\r
+ virtual void subscribe(const monitor::observable::observer_ptr& o) {}\r
+ virtual void unsubscribe(const monitor::observable::observer_ptr& o) {}\r
};\r
\r
typedef std::function<spl::shared_ptr<core::frame_producer>(const spl::shared_ptr<struct frame_factory>&, const std::vector<std::wstring>&)> producer_factory_t;\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
- boost::optional<int32_t> auto_play_delta_;\r
- bool is_paused_;\r
+ spl::shared_ptr<monitor::subject> event_subject_;\r
+ spl::shared_ptr<monitor::subject> foreground_event_subject_;\r
+ spl::shared_ptr<monitor::subject> background_event_subject_;\r
+ spl::shared_ptr<frame_producer> foreground_;\r
+ spl::shared_ptr<frame_producer> background_;\r
+ int64_t frame_number_;\r
+ boost::optional<int32_t> auto_play_delta_;\r
+ bool is_paused_;\r
\r
public:\r
impl(int index) \r
- : event_subject_(monitor::path("layer") % index)\r
+ : event_subject_(new monitor::subject(monitor::path("layer") % index))\r
+ , foreground_event_subject_(new monitor::subject("foreground"))\r
+ , background_event_subject_(new monitor::subject("background"))\r
, foreground_(frame_producer::empty())\r
, background_(frame_producer::empty())\r
, frame_number_(0)\r
, is_paused_(false)\r
{\r
+ foreground_event_subject_->subscribe(event_subject_);\r
+ background_event_subject_->subscribe(event_subject_);\r
}\r
- \r
+\r
void pause()\r
{\r
is_paused_ = true;\r
\r
void load(spl::shared_ptr<frame_producer> producer, const boost::optional<int32_t>& auto_play_delta)\r
{ \r
- background_ = std::move(producer);\r
+ background_->unsubscribe(background_event_subject_);\r
+ background_ = std::move(producer);\r
+ background_->subscribe(background_event_subject_);\r
+\r
auto_play_delta_ = auto_play_delta;\r
\r
if(auto_play_delta_ && foreground_ == frame_producer::empty())\r
if(background_ != frame_producer::empty())\r
{\r
background_->set_leading_producer(foreground_);\r
- foreground_ = background_;\r
- background_ = frame_producer::empty();\r
+\r
+ background_->unsubscribe(background_event_subject_);\r
+ foreground_->unsubscribe(foreground_event_subject_);\r
+\r
+ foreground_ = std::move(background_);\r
+ background_ = std::move(frame_producer::empty());\r
+ \r
+ foreground_->subscribe(foreground_event_subject_);\r
+\r
frame_number_ = 0;\r
auto_play_delta_.reset();\r
}\r
\r
void stop()\r
{\r
- foreground_ = frame_producer::empty();\r
+ foreground_->unsubscribe(foreground_event_subject_);\r
+\r
+ foreground_ = std::move(frame_producer::empty());\r
+\r
frame_number_ = 0;\r
auto_play_delta_.reset();\r
\r
}\r
}\r
\r
- event_subject_ << monitor::event("state") % u8(is_paused_ ? L"paused" : (foreground_ == frame_producer::empty() ? L"stopped" : L"playing")) \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
+ *foreground_event_subject_ << monitor::event("type") % u8(foreground_->name());\r
+ *background_event_subject_ << monitor::event("type") % u8(foreground_->name());\r
\r
return frame;\r
}\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
+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
return L"separated[fill:" + fill_producer_->print() + L"|key[" + key_producer_->print() + L"]]";\r
} \r
\r
+ virtual std::wstring name() const override\r
+ {\r
+ return L"separated";\r
+ }\r
+\r
boost::property_tree::wptree info() const override\r
{\r
boost::property_tree::wptree info;\r
info.add_child(L"key.producer", key_producer_->info());\r
return info;\r
}\r
+\r
+ virtual void subscribe(const monitor::observable::observer_ptr& o) override \r
+ {\r
+ return fill_producer_->subscribe(o);\r
+ }\r
+\r
+ virtual void unsubscribe(const monitor::observable::observer_ptr& o) override \r
+ {\r
+ return fill_producer_->unsubscribe(o);\r
+ }\r
};\r
\r
spl::shared_ptr<frame_producer> create_separated_producer(const spl::shared_ptr<frame_producer>& fill, const spl::shared_ptr<frame_producer>& key)\r
} \r
\r
graph_->set_value("produce-time", frame_timer.elapsed()*format_desc.fps*0.5);\r
+ //*event_subject_ << monitor::event("profiler/time") % frame_timer.elapsed() % (1.0/format_desc.fps);\r
\r
return frames;\r
});\r
#include "../frame_producer.h"\r
#include "../../frame/draw_frame.h"\r
#include "../../frame/frame_transform.h"\r
+#include "../../monitor/monitor.h"\r
\r
#include <tbb/parallel_invoke.h>\r
\r
\r
struct transition_producer : public frame_producer\r
{ \r
- const field_mode mode_;\r
- unsigned int current_frame_;\r
+ spl::shared_ptr<monitor::subject> event_subject_;\r
+ const field_mode mode_;\r
+ int current_frame_;\r
\r
- const transition_info info_;\r
+ const transition_info info_;\r
\r
- spl::shared_ptr<frame_producer> dest_producer_;\r
- spl::shared_ptr<frame_producer> source_producer_;\r
+ spl::shared_ptr<frame_producer> dest_producer_;\r
+ spl::shared_ptr<frame_producer> source_producer_;\r
\r
- spl::shared_ptr<draw_frame> last_frame_;\r
+ spl::shared_ptr<draw_frame> last_frame_;\r
\r
explicit transition_producer(const field_mode& mode, const spl::shared_ptr<frame_producer>& dest, const transition_info& info) \r
: mode_(mode)\r
, info_(info)\r
, dest_producer_(dest)\r
, source_producer_(frame_producer::empty())\r
- , last_frame_(draw_frame::empty()){}\r
+ , last_frame_(draw_frame::empty())\r
+ {\r
+ dest->subscribe(event_subject_);\r
+ }\r
\r
// frame_producer\r
\r
if(++current_frame_ >= info_.duration)\r
return draw_frame::eof();\r
\r
+ *event_subject_ << monitor::event("transition/frame") % current_frame_ % info_.duration\r
+ << monitor::event("transition/type") % [&]() -> std::string\r
+ {\r
+ switch(info_.type.value())\r
+ {\r
+ case transition_type::mix: return "mix";\r
+ case transition_type::wipe: return "wipe";\r
+ case transition_type::slide: return "slide";\r
+ case transition_type::push: return "push";\r
+ case transition_type::cut: return "cut";\r
+ default: return "n/a";\r
+ }\r
+ }();\r
+\r
auto dest = draw_frame::empty();\r
auto source = draw_frame::empty();\r
\r
source = source_producer_->receive(flags);\r
if(source == core::draw_frame::late())\r
source = source_producer_->last_frame();\r
- });\r
+ }); \r
\r
return compose(dest, source);\r
}\r
{\r
return L"transition[" + source_producer_->print() + L"=>" + dest_producer_->print() + L"]";\r
}\r
+\r
+ virtual std::wstring name() const override\r
+ {\r
+ return L"transition";\r
+ }\r
\r
boost::property_tree::wptree info() const override\r
{\r
\r
return draw_frame::over(s_frame, d_frame);\r
}\r
+\r
+ virtual void subscribe(const monitor::observable::observer_ptr& o) override \r
+ {\r
+ return event_subject_->subscribe(o);\r
+ }\r
+\r
+ virtual void unsubscribe(const monitor::observable::observer_ptr& o) override \r
+ {\r
+ return event_subject_->unsubscribe(o);\r
+ }\r
};\r
\r
spl::shared_ptr<frame_producer> create_transition_producer(const field_mode& mode, const spl::shared_ptr<frame_producer>& destination, const transition_info& info)\r
, direction(transition_direction::from_left)\r
, tweener(L"linear"){}\r
\r
- size_t duration;\r
+ int duration;\r
transition_direction direction;\r
transition_type type;\r
tweener tweener;\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/profiler") % frame_timer.elapsed() % (1.0/format_desc_.fps);\r
+ //*event_subject_ << monitor::event("format") % u8(format_desc.name);\r
}\r
catch(...)\r
{\r
return length_;\r
}\r
\r
- std::wstring print() const override\r
+ virtual std::wstring print() const override\r
{\r
return producer_->print();\r
}\r
+ \r
+ virtual std::wstring name() const override\r
+ {\r
+ return L"decklinke";\r
+ }\r
\r
virtual boost::property_tree::wptree info() const override\r
{\r
#include <core/frame/frame_factory.h>\r
#include <core/frame/draw_frame.h>\r
#include <core/frame/frame_transform.h>\r
+#include <core/monitor/monitor.h>\r
\r
#include <boost/algorithm/string.hpp>\r
#include <common/assert.h>\r
\r
struct ffmpeg_producer : public core::frame_producer\r
{\r
+ spl::shared_ptr<monitor::subject> event_subject_;\r
const std::wstring filename_;\r
\r
const spl::shared_ptr<diagnostics::graph> graph_;\r
- boost::timer frame_timer_;\r
\r
const spl::shared_ptr<core::frame_factory> frame_factory_;\r
const core::video_format_desc format_desc_;\r
\r
virtual spl::shared_ptr<core::draw_frame> receive(int flags) override\r
{ \r
- frame_timer_.restart();\r
+ boost::timer frame_timer;\r
\r
std::shared_ptr<core::draw_frame> frame = try_decode_frame(flags);\r
\r
- graph_->set_value("frame-time", frame_timer_.elapsed()*format_desc_.fps*0.5);\r
+ graph_->set_value("frame-time", frame_timer.elapsed()*format_desc_.fps*0.5);\r
+ \r
+ *event_subject_ << monitor::event("profiler/time") % frame_timer.elapsed() % (1.0/format_desc_.fps) \r
+ << monitor::event("file/time") % monitor::duration(file_frame_number()/fps_) \r
+ % monitor::duration(file_nb_frames()/fps_)\r
+ << monitor::event("file/frame") % static_cast<int64_t>(file_frame_number())\r
+ % static_cast<int64_t>(file_nb_frames())\r
+ << monitor::event("file/fps") % fps_\r
+ << monitor::event("file/video/mode") % u8(print_mode())\r
+ << monitor::event("file/video/codec") % (video_decoder_ ? u8(video_decoder_->print()) : "n/a")\r
+ << monitor::event("file/audio/codec") % (audio_decoder_ ? u8(audio_decoder_->print()) : "n/a")\r
+ << monitor::event("filename") % u8(filename_)\r
+ << monitor::event("loop") % input_.loop();\r
\r
if(!frame)\r
{\r
- if(!input_.eof()) \r
+ if(!input_.eof()) \r
+ {\r
graph_->set_tag("underflow"); \r
+ *event_subject_ << monitor::event("underflow") % true;\r
+ }\r
return last_frame();\r
}\r
\r
+ boost::lexical_cast<std::wstring>(file_frame_number()) + L"/" + boost::lexical_cast<std::wstring>(file_nb_frames()) + L"]";\r
}\r
\r
+ virtual std::wstring name() const override\r
+ {\r
+ return L"ffmpeg";\r
+ }\r
+\r
boost::property_tree::wptree info() const override\r
{\r
boost::property_tree::wptree info;\r
info.add(L"file-nb-frames", file_nb_frames());\r
return info;\r
}\r
+ \r
+ virtual void subscribe(const monitor::observable::observer_ptr& o) override\r
+ {\r
+ event_subject_->subscribe(o);\r
+ }\r
+\r
+ virtual void unsubscribe(const monitor::observable::observer_ptr& o) override\r
+ {\r
+ event_subject_->unsubscribe(o);\r
+ }\r
\r
// ffmpeg_producer\r
\r
std::wstring print_mode() const\r
{\r
- return video_decoder_ ? ffmpeg::print_mode(video_decoder_->width(), video_decoder_->height(), fps_, !video_decoder_->is_progressive()) : L"";\r
+ return video_decoder_ ? ffmpeg::print_mode(video_decoder_->width(), video_decoder_->height(), fps_, !video_decoder_->is_progressive()) : L"n/a";\r
}\r
\r
std::wstring do_call(const std::wstring& param)\r
return L"flash[" + boost::filesystem::path(filename_).wstring() + L"|" + boost::lexical_cast<std::wstring>(fps_) + L"]"; \r
} \r
\r
+ virtual std::wstring name() const override\r
+ {\r
+ return L"flash";\r
+ }\r
+\r
virtual boost::property_tree::wptree info() const override\r
{\r
boost::property_tree::wptree info;\r
return L"image_producer[" + filename_ + L"]";\r
}\r
\r
+ virtual std::wstring name() const override\r
+ {\r
+ return L"image";\r
+ }\r
+\r
virtual boost::property_tree::wptree info() const override\r
{\r
boost::property_tree::wptree info;\r
return L"image_scroll_producer[" + filename_ + L"]";\r
}\r
\r
+ virtual std::wstring name() const override\r
+ {\r
+ return L"image-scroll";\r
+ }\r
+\r
virtual boost::property_tree::wptree info() const override\r
{\r
boost::property_tree::wptree info;\r
return L"reroute[]";\r
}\r
\r
+ virtual std::wstring name() const override\r
+ {\r
+ return L"reroute";\r
+ }\r
+\r
virtual boost::property_tree::wptree info() const override\r
{\r
boost::property_tree::wptree info;\r
\r
// Print environment information.\r
print_info();\r
- \r
+ \r
std::wstringstream str;\r
boost::property_tree::xml_writer_settings<wchar_t> w(' ', 3);\r
boost::property_tree::write_xml(str, caspar::env::properties(), w);\r
\r
// Create a dummy client which prints amcp responses to console.\r
auto console_client = std::make_shared<caspar::IO::ConsoleClientInfo>();\r
+ \r
+ //auto console_obs = caspar::reactive::make_observer([](const caspar::monitor::event& e)\r
+ //{\r
+ // std::cout << e.path().str() << std::endl;\r
+ //});\r
+ //\r
+ //caspar_server.subscribe(console_obs);\r
\r
std::wstring wcmd;\r
while(true)\r
\r
struct server::impl : boost::noncopyable\r
{\r
+ spl::shared_ptr<monitor::subject> event_subject_;\r
std::unique_ptr<accelerator::factory> accel_factory_;\r
std::vector<spl::shared_ptr<IO::AsyncEventServer>> async_servers_; \r
std::vector<spl::shared_ptr<video_channel>> channels_;\r
if(format_desc.format == video_format::invalid)\r
BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("Invalid video-mode."));\r
\r
- channels_.push_back(spl::make_shared<video_channel>(static_cast<int>(channels_.size()+1), format_desc, accel_factory_->create_image_mixer()));\r
+ auto channel = spl::make_shared<video_channel>(static_cast<int>(channels_.size()+1), format_desc, accel_factory_->create_image_mixer());\r
\r
BOOST_FOREACH(auto& xml_consumer, xml_channel.second.get_child(L"consumers"))\r
{\r
{\r
auto name = xml_consumer.first;\r
if(name == L"screen")\r
- channels_.back()->output()->add(caspar::screen::create_consumer(xml_consumer.second)); \r
+ channel->output()->add(caspar::screen::create_consumer(xml_consumer.second)); \r
else if(name == L"bluefish") \r
- channels_.back()->output()->add(bluefish::create_consumer(xml_consumer.second)); \r
+ channel->output()->add(bluefish::create_consumer(xml_consumer.second)); \r
else if(name == L"decklink") \r
- channels_.back()->output()->add(decklink::create_consumer(xml_consumer.second)); \r
+ channel->output()->add(decklink::create_consumer(xml_consumer.second)); \r
else if(name == L"file") \r
- channels_.back()->output()->add(ffmpeg::create_consumer(xml_consumer.second)); \r
+ channel->output()->add(ffmpeg::create_consumer(xml_consumer.second)); \r
else if(name == L"system-audio")\r
- channels_.back()->output()->add(oal::create_consumer()); \r
+ channel->output()->add(oal::create_consumer()); \r
else if(name != L"<xmlcomment>")\r
CASPAR_LOG(warning) << "Invalid consumer: " << name; \r
}\r
{\r
CASPAR_LOG_CURRENT_EXCEPTION();\r
}\r
- } \r
+ } \r
+\r
+ channel->subscribe(monitor::observable::observer_ptr(event_subject_));\r
+ channels_.push_back(channel);\r
}\r
\r
// Dummy diagnostics channel\r
{\r
return impl_->channels_;\r
}\r
+void server::subscribe(const monitor::observable::observer_ptr& o){impl_->event_subject_->subscribe(o);}\r
+void server::unsubscribe(const monitor::observable::observer_ptr& o){impl_->event_subject_->unsubscribe(o);}\r
\r
}
\ No newline at end of file
\r
#include <common/spl/memory.h>\r
\r
+#include <core/monitor/monitor.h>\r
+\r
#include <boost/noncopyable.hpp>\r
\r
#include <vector>\r
class video_channel;\r
}\r
\r
-class server sealed : boost::noncopyable\r
+class server sealed : public monitor::subject\r
+ , boost::noncopyable\r
{\r
public:\r
server();\r
const std::vector<spl::shared_ptr<core::video_channel>> get_channels() const;\r
+\r
+ // monitor::observable\r
+\r
+ virtual void subscribe(const monitor::observable::observer_ptr& o) override;\r
+ virtual void unsubscribe(const monitor::observable::observer_ptr& o) override;\r
private:\r
struct impl;\r
spl::shared_ptr<impl> impl_;\r