\r
}\r
\r
-template<typename T, typename C, typename F = detail::true_func<T>>\r
+template<typename T, typename C>\r
class observer_function : public observer<T>\r
{\r
public:\r
{\r
}\r
\r
- observer_function(C func, F filter)\r
- : func_(std::move(func))\r
- , filter_(std::move(filter))\r
- {\r
- }\r
-\r
observer_function(const observer_function& other)\r
: func_(other.func_)\r
- , filter_(other.filter_)\r
{\r
}\r
\r
observer_function(observer_function&& other)\r
: func_(std::move(other.func_))\r
- , filter_(std::move(other.filter_))\r
{\r
}\r
\r
\r
virtual void on_next(const T& e) override\r
{\r
- if(!filter_(e))\r
- return;\r
-\r
func_(e);\r
}\r
private:\r
C func_;\r
- F filter_;\r
};\r
\r
-template<typename T, typename F>\r
-class observer_function<T, detail::void_func<T>, F> : public observer<T>\r
+template<typename T>\r
+class observer_function<T, detail::void_func<T>> : public observer<T>\r
{\r
public: \r
virtual void on_next(const T& e) override\r
}\r
};\r
\r
-template<typename I, typename O = I, typename F = detail::true_func<const I&>, typename T = detail::forward_func<I, O>>\r
+template<typename I, typename O = I>\r
class basic_subject : public subject<I, O>\r
{ \r
- template <typename, typename, typename, typename> friend class basic_subject;\r
+ template <typename, typename> friend class basic_subject;\r
\r
basic_subject(const basic_subject&);\r
basic_subject& operator=(const basic_subject&);\r
public: \r
typedef typename subject<I, O>::observer observer;\r
typedef typename subject<I, O>::observer_ptr observer_ptr;\r
- typedef F filter;\r
- typedef T transform;\r
\r
basic_subject()\r
{\r
}\r
- \r
- basic_subject(F filter)\r
- : filter_(std::move(filter))\r
- {\r
- }\r
- \r
- basic_subject(T transform)\r
- : transform_(std::move(transform))\r
- {\r
- }\r
- \r
- basic_subject(std::function<O(const I&)> transform)\r
- : transform_(std::move(transform))\r
- {\r
- }\r
-\r
- basic_subject(F filter, T transform)\r
- : filter_(std::move(filter))\r
- , transform_(std::move(transform))\r
- {\r
- }\r
- \r
+ \r
virtual ~basic_subject()\r
{\r
}\r
\r
- template<typename F1, typename T1>\r
- basic_subject(basic_subject<typename observer::value_type, typename observable::value_type, F1, T1>&& other)\r
+ basic_subject(basic_subject<typename observer::value_type, typename observable::value_type>&& other)\r
: observers_(std::move(other.observers_))\r
- , filter_(std::move(other.filter_))\r
- , transform_(std::move(other.transform_))\r
{\r
}\r
\r
- template<typename F1, typename T1>\r
- basic_subject& operator=(basic_subject<typename observer::value_type, typename observable::value_type, F1, T1>&& other)\r
+ basic_subject& operator=(basic_subject<typename observer::value_type, typename observable::value_type>&& other)\r
{\r
other.swap(*this);\r
return *this;\r
}\r
\r
- template<typename F1, typename T1>\r
- void swap(basic_subject<typename observer::value_type, typename observable::value_type, F1, T1>& other)\r
+ void swap(basic_subject<typename observer::value_type, typename observable::value_type>& other)\r
{ \r
tbb::spin_rw_mutex::scoped_lock lock(mutex_, true);\r
tbb::spin_rw_mutex::scoped_lock other_lock(other.mutex_, true);\r
\r
std::swap(observers_, other.observers_);\r
- std::swap(filter_, other.filter_); \r
}\r
\r
virtual void clear()\r
\r
virtual void on_next(const I& e) override\r
{ \r
- if(!filter_(e))\r
- return;\r
-\r
std::vector<spl::shared_ptr<observer>> observers;\r
\r
{\r
} \r
}\r
\r
- const auto& e2 = transform_(e);\r
for(auto it = std::begin(observers); it != std::end(observers); ++it)\r
- (*it)->on_next(e2);\r
+ (*it)->on_next(e);\r
}\r
private:\r
typedef tbb::cache_aligned_allocator<std::weak_ptr<observer>> allocator;\r
std::owner_less<std::weak_ptr<observer>> comp_;\r
std::vector<std::weak_ptr<observer>, allocator> observers_;\r
mutable tbb::spin_rw_mutex mutex_;\r
- F filter_;\r
- T transform_;\r
};\r
\r
-template<typename F>\r
-spl::shared_ptr<basic_subject<typename std::decay<typename detail::function_traits<F>::arg1_type>::type, typename std::decay<typename detail::function_traits<F>::arg1_type>::type, F>> \r
-make_filter(F filter)\r
-{\r
- return std::make_shared<basic_subject<std::decay<typename detail::function_traits<F>::arg1_type>::type, typename std::decay<typename detail::function_traits<F>::arg1_type>::type, F>>(std::move(filter));\r
-}\r
-\r
template<typename F>\r
spl::shared_ptr<observer_function<typename std::decay<typename detail::function_traits<F>::arg1_type>::type, F>> \r
make_observer(F func)\r
return std::make_shared<observer_function<std::decay<typename detail::function_traits<F>::arg1_type>::type, F>>(std::move(func));\r
}\r
\r
-template<typename F1, typename F2>\r
-spl::shared_ptr<observer_function<typename std::decay<typename detail::function_traits<F1>::arg1_type>::type, F1, F2>> \r
-make_observer(F1 func, F2 filter)\r
+template<typename T>\r
+basic_subject<T>& operator<<(basic_subject<T>& s, const T& val)\r
{\r
- return std::make_shared<observer_function<std::decay<typename detail::function_traits<F1>::arg1_type>::type, F1, F2>>(std::move(func), std::move(filter));\r
+ s.on_next(val);\r
+ return s;\r
}\r
\r
}}\r
lhs.swap(rhs);\r
}\r
\r
-template <typename I, typename O, typename F1, typename F2, typename T1, typename T2>\r
-void swap(caspar::reactive::basic_subject<I, O, F1, T1>& lhs, caspar::reactive::basic_subject<I, O, F2, T2>& rhs) \r
+template <typename I, typename O>\r
+void swap(caspar::reactive::basic_subject<I, O>& lhs, caspar::reactive::basic_subject<I, O>& rhs) \r
{\r
lhs.swap(rhs);\r
}\r
\r
struct output::impl\r
{ \r
+ spl::shared_ptr<diagnostics::graph> graph_;\r
const int channel_index_;\r
video_format_desc format_desc_;\r
std::map<int, spl::shared_ptr<frame_consumer>> consumers_; \r
boost::circular_buffer<spl::shared_ptr<const data_frame>> frames_;\r
executor executor_; \r
public:\r
- impl(const video_format_desc& format_desc, int channel_index) \r
- : channel_index_(channel_index)\r
+ impl(spl::shared_ptr<diagnostics::graph> graph, const video_format_desc& format_desc, int channel_index) \r
+ : graph_(std::move(graph))\r
+ , channel_index_(channel_index)\r
, format_desc_(format_desc)\r
, executor_(L"output")\r
{\r
+ graph_->set_color("consume-time", diagnostics::color(1.0f, 0.4f, 0.0f, 0.8));\r
} \r
\r
void add(int index, spl::shared_ptr<frame_consumer> consumer)\r
{\r
executor_.invoke([&]\r
{\r
+ boost::timer frame_timer;\r
+\r
auto it = consumers_.begin();\r
while(it != consumers_.end())\r
{ \r
\r
format_desc_ = format_desc;\r
frames_.clear();\r
+\r
+ graph_->set_value("consume-time", frame_timer.elapsed()*format_desc.fps*0.5);\r
});\r
}\r
\r
}\r
};\r
\r
-output::output(const video_format_desc& format_desc, int channel_index) : impl_(new impl(format_desc, channel_index)){}\r
+output::output(spl::shared_ptr<diagnostics::graph> graph, const video_format_desc& format_desc, int channel_index) : impl_(new impl(std::move(graph), format_desc, channel_index)){}\r
void output::add(int index, const spl::shared_ptr<frame_consumer>& consumer){impl_->add(index, consumer);}\r
void output::add(const spl::shared_ptr<frame_consumer>& consumer){impl_->add(consumer);}\r
void output::remove(int index){impl_->remove(index);}\r
class output sealed : boost::noncopyable\r
{\r
public:\r
- explicit output(const struct video_format_desc& format_desc, int channel_index);\r
+ explicit output(spl::shared_ptr<diagnostics::graph> graph, const struct video_format_desc& format_desc, int channel_index);\r
\r
// output\r
\r
<ClInclude Include="frame\write_frame.h" />\r
<ClInclude Include="mixer\audio\audio_util.h" />\r
<ClInclude Include="mixer\image\blend_modes.h" />\r
+ <ClInclude Include="monitor\monitor.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)'=='Debug|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
</ClCompile>\r
+ <ClCompile Include="monitor\monitor.cpp">\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../StdAfx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../StdAfx.h</PrecompiledHeaderFile>\r
+ </ClCompile>\r
<ClCompile Include="video_channel.cpp" />\r
<ClCompile Include="consumer\frame_consumer.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../StdAfx.h</PrecompiledHeaderFile>\r
<Filter Include="source\frame">\r
<UniqueIdentifier>{b19721c1-8dd1-45fb-b9e3-212b548ebbb6}</UniqueIdentifier>\r
</Filter>\r
+ <Filter Include="source\monitor">\r
+ <UniqueIdentifier>{e09a01c7-bfd9-4b56-97fd-ec9d060c0bbc}</UniqueIdentifier>\r
+ </Filter>\r
</ItemGroup>\r
<ItemGroup>\r
<ClInclude Include="producer\transition\transition_producer.h">\r
<ClInclude Include="frame\write_frame.h">\r
<Filter>source\frame</Filter>\r
</ClInclude>\r
+ <ClInclude Include="monitor\monitor.h">\r
+ <Filter>source\monitor</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
<ItemGroup>\r
<ClCompile Include="producer\transition\transition_producer.cpp">\r
<ClCompile Include="frame\data_frame.cpp">\r
<Filter>source\frame</Filter>\r
</ClCompile>\r
+ <ClCompile Include="monitor\monitor.cpp">\r
+ <Filter>source\monitor</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
</Project>
\ No newline at end of file
\r
struct mixer::impl : boost::noncopyable\r
{ \r
+ spl::shared_ptr<diagnostics::graph> graph_;\r
audio_mixer audio_mixer_;\r
spl::shared_ptr<image_mixer> image_mixer_;\r
\r
executor executor_;\r
\r
public:\r
- impl(spl::shared_ptr<image_mixer> image_mixer) \r
- : audio_mixer_()\r
+ impl(spl::shared_ptr<diagnostics::graph> graph, spl::shared_ptr<image_mixer> image_mixer) \r
+ : graph_(std::move(graph))\r
+ , audio_mixer_()\r
, image_mixer_(std::move(image_mixer))\r
, executor_(L"mixer")\r
{ \r
+ graph_->set_color("mix-time", diagnostics::color(1.0f, 0.0f, 0.9f, 0.8));\r
} \r
\r
spl::shared_ptr<const data_frame> operator()(std::map<int, spl::shared_ptr<draw_frame>> frames, const video_format_desc& format_desc)\r
return executor_.invoke([=]() mutable -> spl::shared_ptr<const struct data_frame>\r
{ \r
try\r
- { \r
+ { \r
+ boost::timer frame_timer;\r
+\r
BOOST_FOREACH(auto& frame, frames)\r
{\r
auto blend_it = blend_modes_.find(frame.first);\r
\r
auto image = (*image_mixer_)(format_desc);\r
auto audio = audio_mixer_(format_desc);\r
+ \r
+ graph_->set_value("mix-time", frame_timer.elapsed()*format_desc.fps*0.5);\r
\r
return spl::make_shared<mixed_frame>(this, std::move(image), std::move(audio), format_desc); \r
}\r
}\r
};\r
\r
-mixer::mixer(spl::shared_ptr<image_mixer> image_mixer) \r
- : impl_(new impl(std::move(image_mixer))){}\r
+mixer::mixer(spl::shared_ptr<diagnostics::graph> graph, spl::shared_ptr<image_mixer> image_mixer) \r
+ : impl_(new impl(std::move(graph), std::move(image_mixer))){}\r
void mixer::set_blend_mode(int index, blend_mode value){impl_->set_blend_mode(index, value);}\r
boost::unique_future<boost::property_tree::wptree> mixer::info() const{return impl_->info();}\r
spl::shared_ptr<const data_frame> mixer::operator()(std::map<int, spl::shared_ptr<draw_frame>> frames, const struct video_format_desc& format_desc){return (*impl_)(std::move(frames), format_desc);}\r
class mixer sealed : boost::noncopyable\r
{\r
public: \r
- explicit mixer(spl::shared_ptr<struct image_mixer> image_mixer);\r
+ explicit mixer(spl::shared_ptr<diagnostics::graph> graph, spl::shared_ptr<struct image_mixer> image_mixer);\r
\r
spl::shared_ptr<const struct data_frame> operator()(std::map<int, spl::shared_ptr<class draw_frame>> frames, const struct video_format_desc& format_desc);\r
\r
--- /dev/null
+#include "../StdAfx.h"\r
+\r
+#include "monitor.h"\r
+\r
+#include <utility>\r
+\r
+namespace caspar { namespace monitor {\r
+ \r
+// param\r
+ \r
+namespace detail {\r
+\r
+struct param_visitor : public boost::static_visitor<void>\r
+{\r
+ std::ostream& o;\r
+\r
+ param_visitor(std::ostream& o)\r
+ : o(o)\r
+ {\r
+ }\r
+\r
+ void operator()(const std::vector<int8_t>& bytes)\r
+ { \r
+ o << std::string(std::begin(bytes), std::end(bytes));\r
+ }\r
+\r
+ void operator()(const duration& duration)\r
+ { \r
+ o << duration.count();\r
+ }\r
+\r
+ template<typename T>\r
+ void operator()(const T& value)\r
+ {\r
+ o << value;\r
+ }\r
+};\r
+\r
+}\r
+\r
+std::ostream& operator<<(std::ostream& o, const param& p)\r
+{\r
+ detail::param_visitor v(o);\r
+ boost::apply_visitor(v, p);\r
+ return o;\r
+}\r
+\r
+// path\r
+\r
+path::path()\r
+{\r
+}\r
+\r
+path::path(const char* path)\r
+ : str_(path)\r
+{\r
+\r
+}\r
+\r
+path::path(std::string path)\r
+ : str_(path)\r
+{\r
+\r
+}\r
+\r
+path::path(const path& other)\r
+ : str_(other.str_)\r
+{ \r
+}\r
+ \r
+path::path(path&& other)\r
+ : str_(std::move(other.str_))\r
+{ \r
+}\r
+\r
+path& path::operator=(path other)\r
+{\r
+ std::swap(*this, other);\r
+ return *this;\r
+}\r
+\r
+path& path::operator%=(path other)\r
+{\r
+ return *this %= other.str_;\r
+}\r
+\r
+void path::swap(path& other)\r
+{\r
+ std::swap(str_, other.str_);\r
+}\r
+ \r
+const std::string& path::str() const\r
+{\r
+ return str_;\r
+}\r
+\r
+bool path::empty() const\r
+{\r
+ return str_.empty();\r
+}\r
+\r
+// event\r
+\r
+event::event(monitor::path path)\r
+ : read_only_(true)\r
+ , path_(std::move(path))\r
+ , params_(std::make_shared<params_t>())\r
+{\r
+}\r
+ \r
+event::event(monitor::path path, std::shared_ptr<params_t> params)\r
+ : read_only_(true)\r
+ , path_(std::move(path))\r
+ , params_(std::move(params))\r
+{\r
+ if(params_ == nullptr)\r
+ throw std::invalid_argument("params");\r
+}\r
+\r
+event::event(const event& other)\r
+ : read_only_(true)\r
+ , path_(other.path_)\r
+ , params_(other.params_)\r
+{\r
+}\r
+\r
+event::event(event&& other)\r
+ : read_only_(true)\r
+ , path_(std::move(other.path_))\r
+ , params_(std::move(other.params_))\r
+{\r
+}\r
+\r
+event& event::operator=(event other)\r
+{\r
+ std::swap(*this, other);\r
+ return *this;\r
+}\r
+\r
+void event::swap(event& other)\r
+{\r
+ std::swap(read_only_, other.read_only_);\r
+ std::swap(path_, other.path_);\r
+ std::swap(params_, other.params_);\r
+}\r
+ \r
+const path& event::path() const \r
+{\r
+ return path_;\r
+}\r
+\r
+const event::params_t& event::params() const \r
+{\r
+ return *params_;\r
+}\r
+\r
+event event::propagate(monitor::path path) const\r
+{\r
+ return event(std::move(path) % path_, params_);\r
+}\r
+\r
+}}
\ No newline at end of file
--- /dev/null
+#pragma once\r
+\r
+#include <common/reactive.h>\r
+#include <common/spl/memory.h>\r
+\r
+#include <functional>\r
+#include <string>\r
+#include <vector>\r
+#include <ostream>\r
+#include <type_traits>\r
+\r
+#include <boost/variant.hpp>\r
+#include <boost/lexical_cast.hpp>\r
+#include <boost/chrono.hpp>\r
+\r
+#include <tbb/cache_aligned_allocator.h>\r
+#include <tbb/spin_mutex.h>\r
+\r
+#ifndef _SCL_SECURE_NO_WARNINGS\r
+#define _SCL_SECURE_NO_WARNINGS\r
+#endif\r
+\r
+namespace caspar { namespace monitor {\r
+ \r
+// path\r
+\r
+class path sealed\r
+{\r
+public: \r
+ path(); \r
+ path(const char* path);\r
+ path(std::string path);\r
+\r
+ path(const path& other); \r
+ path(path&& other);\r
+ \r
+ path& operator=(path other);\r
+ path& operator%=(path other);\r
+\r
+ template<typename T>\r
+ typename std::enable_if<!std::is_same<typename std::decay<T>::type, path>::value, path&>::type operator%=(T&& value)\r
+ {\r
+ auto str = boost::lexical_cast<std::string>(std::forward<T>(value));\r
+\r
+ if(!str.empty())\r
+ str_ += (str.front() != '/' ? "/" : "") + std::move(str);\r
+\r
+ return *this;\r
+ }\r
+\r
+ void swap(path& other);\r
+\r
+ const std::string& str() const; \r
+ bool empty() const;\r
+private:\r
+ std::string str_;\r
+};\r
+\r
+template<typename T>\r
+path operator%(path path, T&& value)\r
+{ \r
+ return std::move(path %= std::forward<T>(value));\r
+}\r
+\r
+// param\r
+\r
+typedef boost::chrono::duration<double, boost::ratio<1, 1>> duration;\r
+\r
+typedef boost::variant<bool, int32_t, int64_t, float, double, std::string, std::vector<int8_t>, duration> param;\r
+\r
+std::ostream& operator<<(std::ostream& o, const param& p);\r
+\r
+// event\r
+\r
+class event sealed\r
+{ \r
+public: \r
+ typedef std::vector<param, tbb::cache_aligned_allocator<param>> params_t;\r
+ \r
+ event(path path); \r
+ event(path path, std::shared_ptr<params_t> params); \r
+ \r
+ event(const event& other);\r
+ event(event&& other);\r
+ event& operator=(event other);\r
+\r
+ void swap(event& other);\r
+ \r
+ template<typename T>\r
+ event& operator%(T&& value)\r
+ {\r
+ if(read_only_)\r
+ {\r
+ read_only_ = false;\r
+ params_ = spl::make_shared<params_t>(*params_);\r
+ }\r
+ params_->push_back(std::forward<T>(value));\r
+ return *this;\r
+ }\r
+ \r
+ event propagate(path path) const;\r
+ const path& path() const;\r
+ const params_t& params() const;\r
+private:\r
+ bool read_only_; \r
+ monitor::path path_;\r
+ std::shared_ptr<params_t> params_;\r
+};\r
+ \r
+class subject : public reactive::subject<monitor::event>\r
+{ \r
+ subject(const subject&);\r
+ subject& operator=(const subject&);\r
+ \r
+ typedef reactive::basic_subject<monitor::event> impl;\r
+public: \r
+ subject(monitor::path path = monitor::path())\r
+ : path_(std::move(path))\r
+ , impl_(std::make_shared<impl>())\r
+\r
+ {\r
+ }\r
+ \r
+ subject(subject&& other)\r
+ : path_(std::move(other.path_))\r
+ , impl_(std::move(other.impl_))\r
+ {\r
+ }\r
+\r
+ virtual ~subject()\r
+ {\r
+ }\r
+ \r
+ virtual void subscribe(const observer_ptr& o) override\r
+ { \r
+ impl_->subscribe(o);\r
+ }\r
+\r
+ virtual void unsubscribe(const observer_ptr& o) override\r
+ {\r
+ impl_->unsubscribe(o);\r
+ }\r
+ \r
+ virtual void on_next(const monitor::event& e) override\r
+ { \r
+ impl_->on_next(path_.empty() ? e : e.propagate(path_));\r
+ }\r
+private:\r
+ monitor::path path_;\r
+ std::shared_ptr<impl> impl_;\r
+};\r
+\r
+inline subject& operator<<(subject& s, const event& e)\r
+{\r
+ s.on_next(e);\r
+ return s;\r
+}\r
+\r
+}}\r
+\r
+namespace std {\r
+\r
+inline void swap(caspar::monitor::path& lhs, caspar::monitor::path& rhs) \r
+{\r
+ lhs.swap(rhs);\r
+}\r
+ \r
+inline void swap(caspar::monitor::event& lhs, caspar::monitor::event& rhs) \r
+{\r
+ lhs.swap(rhs);\r
+}\r
+\r
+}\r
namespace caspar { namespace core {\r
\r
struct stage::impl : public std::enable_shared_from_this<impl>\r
-{ \r
+{ \r
+ spl::shared_ptr<diagnostics::graph> graph_;\r
std::map<int, layer> layers_; \r
std::map<int, tweened_transform> tweens_; \r
executor executor_;\r
public:\r
- impl() : executor_(L"stage")\r
+ impl(spl::shared_ptr<diagnostics::graph> graph) \r
+ : graph_(std::move(graph))\r
+ , executor_(L"stage")\r
{\r
+ graph_->set_color("produce-time", diagnostics::color(0.0f, 1.0f, 0.0f));\r
}\r
\r
std::map<int, spl::shared_ptr<draw_frame>> operator()(const struct video_format_desc& format_desc)\r
{ \r
return executor_.invoke([=]() -> std::map<int, spl::shared_ptr<draw_frame>>\r
{\r
+ boost::timer frame_timer;\r
+\r
std::map<int, spl::shared_ptr<class draw_frame>> frames;\r
\r
try\r
layers_.clear();\r
CASPAR_LOG_CURRENT_EXCEPTION();\r
} \r
+ \r
+ graph_->set_value("produce-time", frame_timer.elapsed()*format_desc.fps*0.5);\r
\r
return frames;\r
});\r
} \r
};\r
\r
-stage::stage() : impl_(new impl()){}\r
+stage::stage(spl::shared_ptr<diagnostics::graph> graph) : impl_(new impl(std::move(graph))){}\r
void stage::apply_transforms(const std::vector<stage::transform_tuple_t>& transforms){impl_->apply_transforms(transforms);}\r
void stage::apply_transform(int index, const std::function<core::frame_transform(core::frame_transform)>& transform, unsigned int mix_duration, const tweener& tween){impl_->apply_transform(index, transform, mix_duration, tween);}\r
void stage::clear_transforms(int index){impl_->clear_transforms(index);}\r
typedef std::function<struct frame_transform(struct frame_transform)> transform_func_t;\r
typedef std::tuple<int, transform_func_t, unsigned int, tweener> transform_tuple_t;\r
\r
- stage();\r
+ stage(spl::shared_ptr<diagnostics::graph> graph);\r
\r
std::map<int, spl::shared_ptr<class draw_frame>> operator()(const struct video_format_desc& format_desc);\r
\r
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
\r
const int index_;\r
\r
const spl::shared_ptr<caspar::core::mixer> mixer_;\r
const spl::shared_ptr<caspar::core::stage> stage_; \r
\r
- boost::timer tick_timer_;\r
- boost::timer produce_timer_;\r
- boost::timer mix_timer_;\r
- boost::timer consume_timer_;\r
-\r
executor executor_;\r
public:\r
impl(int index, const video_format_desc& format_desc, spl::shared_ptr<image_mixer> image_mixer) \r
- : index_(index)\r
+ : event_subject_(monitor::path() % "channel" % index)\r
+ , index_(index)\r
, format_desc_(format_desc)\r
- , output_(new caspar::core::output(format_desc, index))\r
- , mixer_(new caspar::core::mixer(std::move(image_mixer)))\r
- , stage_(new caspar::core::stage()) \r
+ , output_(new caspar::core::output(graph_, format_desc, index))\r
+ , mixer_(new caspar::core::mixer(graph_, std::move(image_mixer)))\r
+ , stage_(new caspar::core::stage(graph_)) \r
, executor_(L"video_channel")\r
{\r
- //graph_->set_color("mix-time", diagnostics::color(1.0f, 0.0f, 0.9f, 0.8));\r
- graph_->set_color("produce-time", diagnostics::color(0.0f, 1.0f, 0.0f));\r
graph_->set_color("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f)); \r
- graph_->set_color("consume-time", diagnostics::color(1.0f, 0.4f, 0.0f, 0.8));\r
graph_->set_text(print());\r
diagnostics::register_graph(graph_);\r
\r
{\r
try\r
{\r
- tick_timer_.restart();\r
+ boost::timer frame_timer;\r
\r
// Produce\r
-\r
- produce_timer_.restart();\r
-\r
+ \r
auto stage_frames = (*stage_)(format_desc_);\r
- \r
- graph_->set_value("produce-time", produce_timer_.elapsed()*format_desc_.fps*0.5);\r
\r
// Mix\r
-\r
- //mix_timer_.restart();\r
-\r
+ \r
auto mixed_frame = (*mixer_)(std::move(stage_frames), format_desc_);\r
- \r
- //graph_->set_value("mix-time", mix_timer_.elapsed()*format_desc_.fps*0.5);\r
\r
// Consume\r
-\r
- consume_timer_.restart();\r
-\r
- frame_subject_.on_next(mixed_frame);\r
-\r
- graph_->set_value("consume-time", consume_timer_.elapsed()*format_desc_.fps*0.5);\r
-\r
+ \r
+ frame_subject_ << mixed_frame;\r
+ \r
(*output_)(std::move(mixed_frame), format_desc_);\r
\r
- graph_->set_value("tick-time", tick_timer_.elapsed()*format_desc_.fps*0.5);\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");\r
}\r
catch(...)\r
{\r
video_format_desc video_channel::get_video_format_desc() const{return impl_->format_desc_;}\r
void video_channel::set_video_format_desc(const video_format_desc& format_desc){impl_->set_video_format_desc(format_desc);}\r
boost::property_tree::wptree video_channel::info() const{return impl_->info();}\r
-void video_channel::subscribe(const observer_ptr& o) {impl_->frame_subject_.subscribe(o);}\r
-void video_channel::unsubscribe(const observer_ptr& o) {impl_->frame_subject_.unsubscribe(o);}\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
\r
}}
\ No newline at end of file
#include <common/reactive.h>\r
#include <common/forward.h>\r
\r
+#include "monitor/monitor.h"\r
+\r
#include <boost/property_tree/ptree_fwd.hpp>\r
\r
FORWARD3(caspar, core, ogl, class accelerator);\r
\r
namespace caspar { namespace core {\r
\r
-class video_channel sealed : public reactive::observable<spl::shared_ptr<const struct data_frame>>\r
+typedef reactive::observable<spl::shared_ptr<const struct data_frame>> frame_observer;\r
+typedef reactive::observable<monitor::event> event_observer;\r
+\r
+class video_channel sealed : public frame_observer\r
+ , public event_observer\r
{\r
video_channel(const video_channel&);\r
video_channel& operator=(const video_channel&);\r
\r
boost::property_tree::wptree info() const;\r
\r
- // observable\r
+ // observable<spl::shared_ptr<const struct data_frame>>\r
\r
- virtual void subscribe(const observer_ptr& o) override;\r
- virtual void unsubscribe(const observer_ptr& o) override;\r
+ virtual void subscribe(const frame_observer::observer_ptr& o) override;\r
+ virtual void unsubscribe(const frame_observer::observer_ptr& o) override;\r
+ \r
+ virtual void subscribe(const event_observer::observer_ptr& o) override;\r
+ virtual void unsubscribe(const event_observer::observer_ptr& o) override;\r
private:\r
struct impl;\r
spl::shared_ptr<impl> impl_;\r