return consumer_->print();\r
}\r
\r
+ virtual boost::property_tree::wptree info() const override\r
+ {\r
+ return consumer_->info();\r
+ }\r
+\r
virtual bool has_synchronization_clock() const override\r
{\r
return consumer_->has_synchronization_clock();\r
return make_safe<cadence_guard>(std::move(consumer));\r
}\r
\r
+const safe_ptr<frame_consumer>& frame_consumer::empty()\r
+{\r
+ struct empty_frame_consumer : public frame_consumer\r
+ {\r
+ virtual bool send(const safe_ptr<read_frame>&) override {return false;}\r
+ virtual void initialize(const video_format_desc&, int) override{}\r
+ virtual std::wstring print() const override {return L"empty";}\r
+ virtual bool has_synchronization_clock() const override {return false;}\r
+ virtual size_t buffer_depth() const override {return 0;};\r
+ virtual int index() const{return -1;}\r
+ virtual boost::property_tree::wptree info() const override\r
+ {\r
+ boost::property_tree::wptree info;\r
+ info.add(L"type", L"empty-consumer");\r
+ return info;\r
+ }\r
+ };\r
+ static safe_ptr<frame_consumer> consumer = make_safe<empty_frame_consumer>();\r
+ return consumer;\r
+}\r
+\r
}}
\ No newline at end of file
#include <common/memory/safe_ptr.h>\r
\r
#include <boost/noncopyable.hpp>\r
+#include <boost/property_tree/ptree_fwd.hpp>\r
\r
#include <functional>\r
#include <string>\r
virtual bool send(const safe_ptr<read_frame>& frame) = 0;\r
virtual void initialize(const video_format_desc& format_desc, int channel_index) = 0;\r
virtual std::wstring print() const = 0;\r
+ virtual boost::property_tree::wptree info() const = 0;\r
virtual bool has_synchronization_clock() const {return true;}\r
virtual size_t buffer_depth() const = 0;\r
virtual int index() const = 0;\r
\r
- static const safe_ptr<frame_consumer>& empty()\r
- {\r
- struct empty_frame_consumer : public frame_consumer\r
- {\r
- virtual bool send(const safe_ptr<read_frame>&) override {return false;}\r
- virtual void initialize(const video_format_desc&, int) override{}\r
- virtual std::wstring print() const override {return L"empty";}\r
- virtual bool has_synchronization_clock() const override {return false;}\r
- virtual size_t buffer_depth() const override {return 0;};\r
- virtual int index() const{return -1;}\r
- };\r
- static safe_ptr<frame_consumer> consumer = make_safe<empty_frame_consumer>();\r
- return consumer;\r
- }\r
+ static const safe_ptr<frame_consumer>& empty();\r
};\r
\r
safe_ptr<frame_consumer> create_consumer_cadence_guard(const safe_ptr<frame_consumer>& consumer);\r
boost::property_tree::wptree info;\r
BOOST_FOREACH(auto& consumer, consumers_)\r
{\r
- auto& node = info.add(L"output.devices.device", L"");\r
- node.add(L"index", consumer.first);\r
- node.add(L"consumer", consumer.second->print());\r
+ info.add_child(L"consumers.consumer", consumer.second->info())\r
+ .add(L"index", consumer.first); \r
}\r
return info;\r
}, high_priority));\r
<ClCompile Include="consumer\frame_consumer.cpp">\r
<Filter>source\consumer</Filter>\r
</ClCompile>\r
- <ClCompile Include="producer\frame_producer.cpp">\r
- <Filter>source\producer</Filter>\r
- </ClCompile>\r
<ClCompile Include="producer\color\color_producer.cpp">\r
<Filter>source\producer\color</Filter>\r
</ClCompile>\r
<ClCompile Include="producer\playlist\playlist_producer.cpp">\r
<Filter>source\producer\playlist</Filter>\r
</ClCompile>\r
+ <ClCompile Include="producer\frame_producer.cpp">\r
+ <Filter>source\producer</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
</Project>
\ No newline at end of file
{\r
return L"color[" + color_str_ + L"]";\r
}\r
+\r
+ boost::property_tree::wptree info() const override\r
+ {\r
+ boost::property_tree::wptree info;\r
+ info.add(L"type", L"color-producer");\r
+ info.add(L"color", color_str_);\r
+ return info;\r
+ }\r
};\r
\r
std::wstring get_hex_color(const std::wstring& str)\r
}\r
}\r
\r
- virtual safe_ptr<basic_frame> receive(int hints) override {return (*producer_)->receive(hints);}\r
- virtual safe_ptr<basic_frame> last_frame() const override {return (*producer_)->last_frame();}\r
- virtual std::wstring print() const override {return (*producer_)->print();}\r
- virtual boost::unique_future<std::wstring> call(const std::wstring& str) override {return (*producer_)->call(str);}\r
- virtual safe_ptr<frame_producer> get_following_producer() const override {return (*producer_)->get_following_producer();}\r
- virtual void set_leading_producer(const safe_ptr<frame_producer>& producer) override {(*producer_)->set_leading_producer(producer);}\r
- virtual int64_t nb_frames() const override {return (*producer_)->nb_frames();}\r
- virtual int64_t file_nb_frames() const override {return (*producer_)->file_nb_frames();}\r
- virtual int64_t frame_number() const override {return (*producer_)->frame_number();}\r
- virtual int64_t file_frame_number() const override {return (*producer_)->file_frame_number();}\r
+ virtual safe_ptr<basic_frame> receive(int hints) override {return (*producer_)->receive(hints);}\r
+ virtual safe_ptr<basic_frame> last_frame() const override {return (*producer_)->last_frame();}\r
+ virtual std::wstring print() const override {return (*producer_)->print();}\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 safe_ptr<frame_producer> get_following_producer() const override {return (*producer_)->get_following_producer();}\r
+ virtual void set_leading_producer(const safe_ptr<frame_producer>& producer) override {(*producer_)->set_leading_producer(producer);}\r
+ virtual int64_t nb_frames() const override {return (*producer_)->nb_frames();}\r
};\r
\r
safe_ptr<core::frame_producer> create_producer_destroy_proxy(safe_ptr<core::frame_producer>&& producer)\r
virtual safe_ptr<core::basic_frame> last_frame() const{return frame_;}\r
virtual std::wstring print() const{return L"dummy[" + print_ + L"]";}\r
virtual int64_t nb_frames() const {return nb_frames_;} \r
+ virtual boost::property_tree::wptree info() const override\r
+ {\r
+ boost::property_tree::wptree info;\r
+ info.add(L"type", L"last-frame-producer");\r
+ return info;\r
+ }\r
};\r
\r
struct empty_frame_producer : public frame_producer\r
virtual void set_frame_factory(const safe_ptr<frame_factory>&){}\r
virtual int64_t nb_frames() const {return 0;}\r
virtual std::wstring print() const { return L"empty";}\r
+ \r
+ virtual boost::property_tree::wptree info() const override\r
+ {\r
+ boost::property_tree::wptree info;\r
+ info.add(L"type", L"empty-producer");\r
+ return info;\r
+ }\r
};\r
\r
const safe_ptr<frame_producer>& frame_producer::empty() // nothrow\r
#include <numeric>\r
\r
#include <boost/thread/future.hpp>\r
-#include <boost/property_tree/ptree.hpp>\r
+#include <boost/property_tree/ptree_fwd.hpp>\r
\r
namespace caspar { \r
\r
virtual ~frame_producer(){} \r
\r
virtual std::wstring print() const = 0; // nothrow\r
+ virtual boost::property_tree::wptree info() const = 0;\r
\r
virtual boost::unique_future<std::wstring> call(const std::wstring&) \r
{\r
return promise.get_future();\r
}\r
\r
- virtual boost::property_tree::wptree info() const\r
- {\r
- boost::property_tree::wptree info;\r
- info.push_front(std::make_pair(L"producer", print()));\r
- return info;\r
- }\r
-\r
virtual safe_ptr<frame_producer> get_following_producer() const {return frame_producer::empty();} // nothrow\r
virtual void set_leading_producer(const safe_ptr<frame_producer>&) {} // nothrow\r
\r
virtual int64_t nb_frames() const {return std::numeric_limits<int>::max();}\r
- virtual int64_t file_nb_frames() const {return nb_frames();}\r
-\r
- virtual int64_t frame_number() const {return 0;}\r
- virtual int64_t file_frame_number() const {return frame_number();}\r
\r
virtual safe_ptr<basic_frame> receive(int hints) = 0;\r
virtual safe_ptr<core::basic_frame> last_frame() const = 0;\r
}\r
}\r
\r
- layer_status status() const\r
- {\r
- layer_status status;\r
- status.foreground = foreground_->print();\r
- status.background = background_->print();\r
- status.is_paused = is_paused_;\r
- status.nb_frames = foreground_->nb_frames();\r
- status.frame_number = std::max(frame_number_, foreground_->frame_number());\r
- status.file_nb_frames = foreground_->file_nb_frames();\r
- status.file_frame_number = foreground_->file_frame_number();\r
-\r
- return status;\r
- }\r
-\r
boost::unique_future<std::wstring> call(bool foreground, const std::wstring& param)\r
{\r
return (foreground ? foreground_ : background_)->call(param);\r
boost::property_tree::wptree info() const\r
{\r
boost::property_tree::wptree info;\r
- info.add_child(L"layer.foreground", foreground_->info());\r
- info.add_child(L"layer.background", foreground_->info());\r
- info.add(L"layer.status", is_paused_ ? L"paused" : (foreground_ == frame_producer::empty() ? L"stopped" : L"playing"));\r
- info.add(L"layer.auto_delta", auto_play_delta_);\r
+ info.add(L"status", is_paused_ ? L"paused" : (foreground_ == frame_producer::empty() ? L"stopped" : L"playing"));\r
+ info.add(L"auto_delta", auto_play_delta_);\r
+ info.add(L"frame-number", frame_number_);\r
+\r
+ auto nb_frames = foreground_->nb_frames();\r
+\r
+ info.add(L"nb_frames", nb_frames == std::numeric_limits<int64_t>::max() ? -1 : nb_frames);\r
+ info.add(L"frames-left", nb_frames == std::numeric_limits<int64_t>::max() ? -1 : (foreground_->nb_frames() - frame_number_ - auto_play_delta_));\r
+ info.add_child(L"foreground", foreground_->info());\r
+ info.add_child(L"background", background_->info());\r
return info;\r
}\r
};\r
void layer::stop(){impl_->stop();}\r
bool layer::is_paused() const{return impl_->is_paused_;}\r
int64_t layer::frame_number() const{return impl_->frame_number_;}\r
-layer_status layer::status() const {return impl_->status();}\r
safe_ptr<basic_frame> layer::receive() {return impl_->receive();}\r
safe_ptr<frame_producer> layer::foreground() const { return impl_->foreground_;}\r
safe_ptr<frame_producer> layer::background() const { return impl_->background_;}\r
struct frame_producer;\r
class basic_frame;\r
\r
-struct layer_status\r
-{\r
- std::wstring foreground;\r
- std::wstring background;\r
- bool is_paused;\r
- int64_t nb_frames;\r
- int64_t frame_number;\r
- int64_t file_nb_frames;\r
- int64_t file_frame_number;\r
-};\r
-\r
class layer : boost::noncopyable\r
{\r
public:\r
\r
bool is_paused() const;\r
int64_t frame_number() const;\r
-\r
- layer_status status() const;\r
-\r
+ \r
bool empty() const;\r
\r
safe_ptr<frame_producer> foreground() const; // nothrow\r
#include <core/producer/frame/basic_frame.h>\r
\r
#include <boost/regex.hpp>\r
+#include <boost/property_tree/ptree.hpp>\r
\r
#include <deque>\r
\r
return L"playlist[" + current_->print() + L"]";\r
} \r
\r
+ virtual boost::property_tree::wptree info() const override\r
+ {\r
+ boost::property_tree::wptree info;\r
+ info.add(L"type", L"playlist-producer");\r
+ return info;\r
+ }\r
+\r
virtual int64_t nb_frames() const override\r
{\r
return std::numeric_limits<int>::max();\r
return disable_audio(last_frame_);\r
}\r
\r
- virtual std::wstring print() const override\r
- {\r
- return L"separated[fill:" + fill_producer_->print() + L"|key:" + key_producer_->print() + L"]";\r
- } \r
-\r
virtual int64_t nb_frames() const override\r
{\r
return std::min(fill_producer_->nb_frames(), key_producer_->nb_frames());\r
}\r
- \r
- virtual int64_t file_nb_frames() const override\r
- {\r
- return std::min(fill_producer_->file_nb_frames(), key_producer_->file_nb_frames());\r
- }\r
- \r
- virtual int64_t frame_number() const override\r
+\r
+ virtual std::wstring print() const override\r
{\r
- return std::max(fill_producer_->frame_number(), key_producer_->frame_number());\r
- }\r
- \r
- virtual int64_t file_frame_number() const override\r
+ return L"separated[fill:" + fill_producer_->print() + L"|key:" + key_producer_->print() + L"]";\r
+ } \r
+\r
+ boost::property_tree::wptree info() const override\r
{\r
- return std::max(fill_producer_->file_frame_number(), key_producer_->file_frame_number());\r
+ boost::property_tree::wptree info;\r
+ info.add(L"type", L"separated-producer");\r
+ info.add_child(L"fill.producer", fill_producer_->info());\r
+ info.add_child(L"key.producer", key_producer_->info());\r
+ return info;\r
}\r
};\r
\r
}, high_priority);\r
}\r
}\r
-\r
- boost::unique_future<layer_status> get_status(int index)\r
- { \r
- return executor_.begin_invoke([=]\r
- {\r
- return layers_[index].status();\r
- }, high_priority );\r
- }\r
- \r
+ \r
boost::unique_future<safe_ptr<frame_producer>> foreground(int index)\r
{\r
return executor_.begin_invoke([=]\r
return std::move(executor_.begin_invoke([&]() -> boost::property_tree::wptree\r
{\r
boost::property_tree::wptree info;\r
- auto& layers_node = info.add(L"stage.layers", L"");\r
- BOOST_FOREACH(auto& layer, layers_)\r
- {\r
- auto layer_info = layer.second.info();\r
- layer_info.add(L"layer.index", layer.first);\r
- BOOST_FOREACH(auto& update, layer_info) \r
- layers_node.add_child(update.first, update.second);\r
- }\r
+ BOOST_FOREACH(auto& layer, layers_) \r
+ info.add_child(L"layers.layer", layer.second.info())\r
+ .add(L"index", layer.first); \r
return info;\r
}, high_priority));\r
}\r
+\r
+ boost::unique_future<boost::property_tree::wptree> info(int index)\r
+ {\r
+ return std::move(executor_.begin_invoke([&]() -> boost::property_tree::wptree\r
+ {\r
+ return layers_[index].info();\r
+ }, high_priority));\r
+ }\r
};\r
\r
stage::stage(const safe_ptr<diagnostics::graph>& graph, const safe_ptr<target_t>& target, const video_format_desc& format_desc) : impl_(new implementation(graph, target, format_desc)){}\r
void stage::swap_layers(const safe_ptr<stage>& other){impl_->swap_layers(other);}\r
void stage::swap_layer(int index, size_t other_index){impl_->swap_layer(index, other_index);}\r
void stage::swap_layer(int index, size_t other_index, const safe_ptr<stage>& other){impl_->swap_layer(index, other_index, other);}\r
-boost::unique_future<layer_status> stage::get_status(int index){return impl_->get_status(index);}\r
-boost::unique_future<safe_ptr<frame_producer>> stage::foreground(size_t index) {return impl_->foreground(index);}\r
-boost::unique_future<safe_ptr<frame_producer>> stage::background(size_t index) {return impl_->background(index);}\r
+boost::unique_future<safe_ptr<frame_producer>> stage::foreground(int index) {return impl_->foreground(index);}\r
+boost::unique_future<safe_ptr<frame_producer>> stage::background(int index) {return impl_->background(index);}\r
boost::unique_future<std::wstring> stage::call(int index, bool foreground, const std::wstring& param){return impl_->call(index, foreground, param);}\r
void stage::set_video_format_desc(const video_format_desc& format_desc){impl_->set_video_format_desc(format_desc);}\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
}}
\ No newline at end of file
// stage\r
\r
void spawn_token();\r
-\r
\r
void load(int index, const safe_ptr<frame_producer>& producer, bool preview = false, int auto_play_delta = -1);\r
void pause(int index);\r
void swap_layer(int index, size_t other_index, const safe_ptr<stage>& other);\r
\r
boost::unique_future<std::wstring> call(int index, bool foreground, const std::wstring& param);\r
- boost::unique_future<layer_status> get_status(int index);\r
- boost::unique_future<safe_ptr<frame_producer>> foreground(size_t index);\r
- boost::unique_future<safe_ptr<frame_producer>> background(size_t index);\r
- \r
- void set_video_format_desc(const video_format_desc& format_desc);\r
+ boost::unique_future<safe_ptr<frame_producer>> foreground(int index);\r
+ boost::unique_future<safe_ptr<frame_producer>> background(int index);\r
\r
boost::unique_future<boost::property_tree::wptree> info() const;\r
+ boost::unique_future<boost::property_tree::wptree> info(int layer) const;\r
+ \r
+ void set_video_format_desc(const video_format_desc& format_desc);\r
\r
private:\r
struct implementation;\r
{\r
return get_following_producer()->nb_frames();\r
}\r
- \r
- virtual int64_t file_nb_frames() const override\r
- {\r
- return get_following_producer()->file_nb_frames();\r
- }\r
- \r
- virtual int64_t frame_number() const override\r
- {\r
- return get_following_producer()->frame_number();\r
- }\r
- \r
- virtual int64_t file_frame_number() const override\r
- {\r
- return get_following_producer()->file_frame_number();\r
- }\r
\r
virtual std::wstring print() const override\r
{\r
return L"transition[" + source_producer_->print() + L"|" + dest_producer_->print() + L"]";\r
}\r
\r
+ boost::property_tree::wptree info() const override\r
+ {\r
+ boost::property_tree::wptree info;\r
+ info.add(L"type", L"transition-producer");\r
+ info.add_child(L"source.producer", source_producer_->info());\r
+ info.add_child(L"destination.producer", dest_producer_->info());\r
+ return info;\r
+ }\r
+\r
// transition_producer\r
\r
safe_ptr<basic_frame> compose(const safe_ptr<basic_frame>& dest_frame, const safe_ptr<basic_frame>& src_frame) \r
boost::property_tree::wptree info() const\r
{\r
boost::property_tree::wptree info;\r
- info.put(L"channel.video-mode", format_desc_.name);\r
\r
- auto& channel_node = info.get_child(L"channel");\r
auto stage_info = stage_->info();\r
auto mixer_info = mixer_->info();\r
auto output_info = output_->info();\r
\r
- BOOST_FOREACH(auto& update, stage_info.get()) \r
- channel_node.put_child(update.first, update.second);\r
- BOOST_FOREACH(auto& update, mixer_info.get()) \r
- channel_node.put_child(update.first, update.second);\r
- BOOST_FOREACH(auto& update, output_info.get()) \r
- channel_node.put_child(update.first, update.second);\r
+ stage_info.timed_wait(boost::posix_time::seconds(2));\r
+ mixer_info.timed_wait(boost::posix_time::seconds(2));\r
+ output_info.timed_wait(boost::posix_time::seconds(2));\r
+ \r
+ info.add(L"video-mode", format_desc_.name);\r
+ info.add_child(L"stage", stage_info.get());\r
+ info.add_child(L"mixer", mixer_info.get());\r
+ info.add_child(L"output", output_info.get());\r
\r
return info; \r
}\r
\r
#include <boost/timer.hpp>\r
#include <boost/range/algorithm.hpp>\r
+#include <boost/property_tree/ptree.hpp>\r
\r
#include <memory>\r
#include <array>\r
return consumer_ ? consumer_->print() : L"[bluefish_consumer]";\r
}\r
\r
+ virtual boost::property_tree::wptree info() const override\r
+ {\r
+ boost::property_tree::wptree info;\r
+ info.add(L"type", L"bluefish-consumer");\r
+ info.add(L"key-only", key_only_);\r
+ info.add(L"device", device_index_);\r
+ info.add(L"embedded-audio", embedded_audio_);\r
+ return info;\r
+ }\r
+\r
size_t buffer_depth() const override\r
{\r
return 1;\r
\r
#include <boost/circular_buffer.hpp>\r
#include <boost/timer.hpp>\r
+#include <boost/property_tree/ptree.hpp>\r
\r
namespace caspar { namespace decklink { \r
\r
virtual std::wstring print() const override\r
{\r
return context_ ? context_->print() : L"[decklink_consumer]";\r
- } \r
+ } \r
+\r
+ virtual boost::property_tree::wptree info() const override\r
+ {\r
+ boost::property_tree::wptree info;\r
+ info.add(L"type", L"decklink-consumer");\r
+ info.add(L"key-only", config_.key_only);\r
+ info.add(L"device", config_.device_index);\r
+ info.add(L"low-latency", config_.low_latency);\r
+ info.add(L"embedded-audio", config_.embedded_audio);\r
+ info.add(L"low-latency", config_.low_latency);\r
+ info.add(L"internal-key", config_.internal_key);\r
+ return info;\r
+ }\r
\r
virtual size_t buffer_depth() const override\r
{\r
\r
\r
/* File created by MIDL compiler version 7.00.0555 */\r
-/* at Fri Dec 02 15:12:59 2011\r
+/* at Fri Dec 02 22:18:37 2011\r
*/\r
/* Compiler settings for interop\DeckLinkAPI.idl:\r
Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 7.00.0555 \r
\r
\r
/* File created by MIDL compiler version 7.00.0555 */\r
-/* at Fri Dec 02 15:12:59 2011\r
+/* at Fri Dec 02 22:18:37 2011\r
*/\r
/* Compiler settings for interop\DeckLinkAPI.idl:\r
Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 7.00.0555 \r
\r
#include <boost/algorithm/string.hpp>\r
#include <boost/foreach.hpp>\r
+#include <boost/property_tree/ptree.hpp>\r
#include <boost/timer.hpp>\r
\r
#if defined(_MSC_VER)\r
{\r
return context_->print();\r
}\r
+\r
+ virtual boost::property_tree::wptree info() const override\r
+ {\r
+ boost::property_tree::wptree info;\r
+ info.add(L"type", L"decklink-producer");\r
+ return info;\r
+ }\r
};\r
\r
safe_ptr<core::frame_producer> create_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::vector<std::wstring>& params)\r
#include <boost/filesystem.hpp>\r
#include <boost/foreach.hpp>\r
#include <boost/range/algorithm.hpp>\r
+#include <boost/property_tree/ptree.hpp>\r
\r
#include <common/utility/string.h>\r
#include <common/utility/assert.h>\r
#include <common/utility/string.h>\r
#include <common/env.h>\r
\r
+#include <boost/algorithm/string.hpp>\r
#include <boost/timer.hpp>\r
#include <boost/thread/once.hpp>\r
#include <boost/thread.hpp>\r
-#include <boost/algorithm/string.hpp>\r
+#include <boost/property_tree/ptree.hpp>\r
\r
#include <tbb/cache_aligned_allocator.h>\r
#include <tbb/parallel_invoke.h>\r
{\r
const std::wstring filename_;\r
const bool key_only_;\r
- const std::string codec_;\r
- const std::string options_;\r
+ const std::wstring codec_;\r
+ const std::wstring options_;\r
\r
std::unique_ptr<ffmpeg_consumer> consumer_;\r
\r
public:\r
\r
- ffmpeg_consumer_proxy(const std::wstring& filename, bool key_only, const std::string codec, const std::string& options)\r
+ ffmpeg_consumer_proxy(const std::wstring& filename, bool key_only, const std::wstring codec, const std::wstring& options)\r
: filename_(filename)\r
, key_only_(key_only)\r
, codec_(boost::to_lower_copy(codec))\r
virtual void initialize(const core::video_format_desc& format_desc, int)\r
{\r
consumer_.reset();\r
- consumer_.reset(new ffmpeg_consumer(narrow(filename_), format_desc, codec_, options_));\r
+ consumer_.reset(new ffmpeg_consumer(narrow(filename_), format_desc, narrow(codec_), narrow(options_)));\r
}\r
\r
virtual bool send(const safe_ptr<core::read_frame>& frame) override\r
{\r
return consumer_ ? consumer_->print() : L"[ffmpeg_consumer]";\r
}\r
+\r
+ virtual boost::property_tree::wptree info() const override\r
+ {\r
+ boost::property_tree::wptree info;\r
+ info.add(L"type", L"ffmpeg-consumer");\r
+ info.add(L"key-only", key_only_);\r
+ info.add(L"filename", filename_);\r
+ info.add(L"codec", codec_);\r
+ info.add(L"options", options_);\r
+ return info;\r
+ }\r
\r
virtual bool has_synchronization_clock() const override\r
{\r
\r
bool key_only = std::find(params.begin(), params.end(), L"KEY_ONLY") != params.end();\r
\r
- std::string codec = "libx264";\r
+ std::wstring codec = L"libx264";\r
auto codec_it = std::find(params.begin(), params.end(), L"CODEC");\r
if(codec_it != params.end() && codec_it++ != params.end())\r
- codec = narrow(*codec_it);\r
+ codec = *codec_it;\r
\r
- if(codec == "H264")\r
- codec = "libx264";\r
+ if(codec == L"H264")\r
+ codec = L"libx264";\r
\r
- if(codec == "DVCPRO")\r
- codec = "dvvideo";\r
+ if(codec == L"DVCPRO")\r
+ codec = L"dvvideo";\r
\r
- std::string options = "";\r
+ std::wstring options = L"";\r
auto options_it = std::find(params.begin(), params.end(), L"OPTIONS");\r
if(options_it != params.end() && options_it++ != params.end())\r
- options = narrow(*options_it);\r
+ options = *options_it;\r
\r
return make_safe<ffmpeg_consumer_proxy>(env::media_folder() + filename, key_only, codec, boost::to_lower_copy(options));\r
}\r
auto codec = ptree.get("codec", "libx264");\r
auto options = ptree.get("options", "");\r
\r
- return make_safe<ffmpeg_consumer_proxy>(env::media_folder() + widen(filename), key_only, codec, options);\r
+ return make_safe<ffmpeg_consumer_proxy>(env::media_folder() + widen(filename), key_only, widen(codec), widen(options));\r
}\r
\r
}}\r
return nb_frames - start_;\r
}\r
\r
- virtual int64_t file_nb_frames() const override\r
+ virtual int64_t file_nb_frames() const\r
{\r
int64_t file_nb_frames = 0;\r
file_nb_frames = std::max(file_nb_frames, video_decoder_ ? video_decoder_->nb_frames() : 0);\r
return file_nb_frames;\r
}\r
\r
- virtual int64_t frame_number() const override\r
+ virtual int64_t frame_number() const\r
{\r
return frame_number_;\r
}\r
\r
- virtual int64_t file_frame_number() const override\r
+ virtual int64_t file_frame_number() const\r
{\r
return file_frame_number_;\r
}\r
\r
virtual std::wstring print() const override\r
{\r
- if(video_decoder_)\r
- {\r
- return L"ffmpeg[" + boost::filesystem::wpath(filename_).filename() + L"|" + print_mode(video_decoder_->width(), video_decoder_->height(), fps_, !video_decoder_->is_progressive())\r
- + L"|" + boost::lexical_cast<std::wstring>(file_frame_number()) + L"/" + boost::lexical_cast<std::wstring>(file_nb_frames()) + L"]";\r
- }\r
- \r
- return L"ffmpeg[" + boost::filesystem::wpath(filename_).filename() + L"]";\r
+ return L"ffmpeg[" + boost::filesystem::wpath(filename_).filename() + L"|" \r
+ + print_mode() + L"|" \r
+ + boost::lexical_cast<std::wstring>(file_frame_number()) + L"/" + boost::lexical_cast<std::wstring>(file_nb_frames()) + L"]";\r
+ }\r
+\r
+ boost::property_tree::wptree info() const override\r
+ {\r
+ boost::property_tree::wptree info;\r
+ info.add(L"type", L"ffmpeg-producer");\r
+ info.add(L"filename", filename_);\r
+ info.add(L"width", video_decoder_ ? video_decoder_->width() : 0);\r
+ info.add(L"height", video_decoder_ ? video_decoder_->height() : 0);\r
+ info.add(L"progressive", video_decoder_ ? video_decoder_->is_progressive() : false);\r
+ info.add(L"fps", fps_);\r
+ info.add(L"loop", input_.loop());\r
+ info.add(L"frame-number", frame_number_);\r
+ auto nb_frames2 = nb_frames();\r
+ info.add(L"nb-frames", nb_frames2 == std::numeric_limits<int64_t>::max() ? -1 : nb_frames2);\r
+ info.add(L"file-frame-number", file_frame_number_);\r
+ info.add(L"file-nb-frames", file_nb_frames());\r
+ return info;\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
+ }\r
\r
std::wstring do_call(const std::wstring& param)\r
{\r
#include <boost/filesystem.hpp>\r
#include <boost/foreach.hpp>\r
#include <boost/range/algorithm.hpp>\r
+#include <boost/format.hpp>\r
+#include <boost/algorithm/string.hpp>\r
+#include <boost/regex.hpp>\r
+#include <boost/property_tree/ptree.hpp>\r
\r
#include "../common/utility/string.h"\r
#include "../common/memory/safe_ptr.h"\r
#include <boost/format.hpp>\r
#include <boost/algorithm/string.hpp>\r
#include <boost/regex.hpp>\r
+#include <boost/property_tree/ptree.hpp>\r
\r
namespace caspar { namespace flash {\r
\r
return flash_producer_->call(str);\r
}\r
\r
- boost::unique_future<std::wstring> info()\r
+ boost::unique_future<std::wstring> template_host_info()\r
{\r
auto str = (boost::wformat(L"<invoke name=\"GetInfo\" returntype=\"xml\"><arguments></arguments></invoke>")).str();\r
CASPAR_LOG(info) << flash_producer_->print() << " Invoking info-command: " << str;\r
else if(boost::regex_match(str, what, description_exp))\r
return description(boost::lexical_cast<int>(what["LAYER"].str())); \r
else if(boost::regex_match(str, what, invoke_exp))\r
- return info(); \r
+ return template_host_info(); \r
\r
return flash_producer_->call(str);\r
}\r
return flash_producer_->print();\r
}\r
\r
+ boost::property_tree::wptree info() const\r
+ {\r
+ boost::property_tree::wptree info;\r
+ info.add(L"type", L"cg-producer");\r
+ return info;\r
+ }\r
+\r
std::wstring timed_invoke(int layer, const std::wstring& label)\r
{\r
auto result = invoke(layer, label);\r
return result.get();\r
return L"";\r
}\r
- std::wstring timed_info()\r
+ std::wstring timed_template_host_info()\r
{\r
- auto result = info();\r
+ auto result = template_host_info();\r
if(result.timed_wait(boost::posix_time::seconds(2)))\r
return result.get();\r
return L"";\r
boost::unique_future<std::wstring> cg_producer::call(const std::wstring& str){return impl_->call(str);}\r
std::wstring cg_producer::invoke(int layer, const std::wstring& label){return impl_->timed_invoke(layer, label);}\r
std::wstring cg_producer::description(int layer){return impl_->timed_description(layer);}\r
-std::wstring cg_producer::info(){return impl_->timed_info();}\r
+std::wstring cg_producer::template_host_info(){return impl_->timed_template_host_info();}\r
+boost::property_tree::wptree cg_producer::info() const{return impl_->info();}\r
\r
}}
\ No newline at end of file
virtual safe_ptr<core::basic_frame> last_frame() const override;\r
virtual std::wstring print() const override;\r
virtual boost::unique_future<std::wstring> call(const std::wstring&) override;\r
+ virtual boost::property_tree::wptree info() const override;\r
\r
//cg_producer\r
\r
void update(int layer, const std::wstring& data);\r
std::wstring invoke(int layer, const std::wstring& label);\r
std::wstring description(int layer);\r
- std::wstring info();\r
+ std::wstring template_host_info();\r
\r
private:\r
struct implementation;\r
#include <common/utility/timer.h>\r
\r
#include <boost/filesystem.hpp>\r
+#include <boost/property_tree/ptree.hpp>\r
#include <boost/thread.hpp>\r
#include <boost/timer.hpp>\r
#include <boost/algorithm/string.hpp>\r
return L"flash[" + boost::filesystem::wpath(filename_).filename() + L"|" + boost::lexical_cast<std::wstring>(fps_) + L"]"; \r
} \r
\r
+ virtual boost::property_tree::wptree info() const override\r
+ {\r
+ boost::property_tree::wptree info;\r
+ info.add(L"type", L"flash-producer");\r
+ return info;\r
+ }\r
+\r
// flash_producer\r
\r
void initialize()\r
return L"image[]";\r
}\r
\r
+ virtual boost::property_tree::wptree info() const override\r
+ {\r
+ boost::property_tree::wptree info;\r
+ info.add(L"type", L"image-consumer");\r
+ return info;\r
+ }\r
+\r
virtual size_t buffer_depth() const override\r
{\r
return 0;\r
\r
#include <boost/assign.hpp>\r
#include <boost/filesystem.hpp>\r
+#include <boost/property_tree/ptree.hpp>\r
\r
#include <algorithm>\r
\r
{\r
return L"image_producer[" + filename_ + L"]";\r
}\r
+\r
+ virtual boost::property_tree::wptree info() const override\r
+ {\r
+ boost::property_tree::wptree info;\r
+ info.add(L"type", L"image-producer");\r
+ info.add(L"filename", filename_);\r
+ return info;\r
+ }\r
};\r
\r
safe_ptr<core::frame_producer> create_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::vector<std::wstring>& params)\r
#include <boost/filesystem.hpp>\r
#include <boost/foreach.hpp>\r
#include <boost/lexical_cast.hpp>\r
+#include <boost/property_tree/ptree.hpp>\r
\r
#include <algorithm>\r
#include <array>\r
return L"image_scroll_producer[" + filename_ + L"]";\r
}\r
\r
+ virtual boost::property_tree::wptree info() const override\r
+ {\r
+ boost::property_tree::wptree info;\r
+ info.add(L"type", L"image-scroll-producer");\r
+ info.add(L"filename", filename_);\r
+ return info;\r
+ }\r
+\r
virtual int64_t nb_frames() const override\r
{\r
if(height_ > format_desc_.height)\r
#include <SFML/Audio.hpp>\r
\r
#include <boost/circular_buffer.hpp>\r
+#include <boost/property_tree/ptree.hpp>\r
#include <boost/timer.hpp>\r
\r
#include <tbb/concurrent_queue.h>\r
{\r
return L"oal[" + boost::lexical_cast<std::wstring>(channel_index_) + L"|" + format_desc_.name + L"]";\r
}\r
+\r
+ virtual boost::property_tree::wptree info() const override\r
+ {\r
+ boost::property_tree::wptree info;\r
+ info.add(L"type", L"oal-consumer");\r
+ return info;\r
+ }\r
\r
virtual size_t buffer_depth() const override\r
{\r
#include <boost/circular_buffer.hpp>\r
#include <boost/foreach.hpp>\r
#include <boost/thread.hpp>\r
+#include <boost/property_tree/ptree.hpp>\r
\r
#include <tbb/atomic.h>\r
#include <tbb/concurrent_queue.h>\r
return consumer_ ? consumer_->print() : L"[ogl_consumer]";\r
}\r
\r
+ virtual boost::property_tree::wptree info() const override\r
+ {\r
+ boost::property_tree::wptree info;\r
+ info.add(L"type", L"ogl-consumer");\r
+ info.add(L"key-only", config_.key_only);\r
+ info.add(L"windowed", config_.windowed);\r
+ info.add(L"auto-deinterlace", config_.auto_deinterlace);\r
+ return info;\r
+ }\r
+\r
virtual bool has_synchronization_clock() const override\r
{\r
return false;\r
\r
namespace caspar { namespace protocol { namespace amcp {\r
\r
-AMCPCommandQueue::AMCPCommandQueue() : newCommandEvent_(FALSE, FALSE) \r
-{}\r
-\r
-AMCPCommandQueue::~AMCPCommandQueue() \r
-{\r
- Stop();\r
-}\r
-\r
-bool AMCPCommandQueue::Start() \r
+AMCPCommandQueue::AMCPCommandQueue() \r
+ : executor_(L"AMCPCommandQueue")\r
{\r
- if(commandPump_.IsRunning())\r
- return false;\r
-\r
- return commandPump_.Start(this);\r
}\r
\r
-void AMCPCommandQueue::Stop() \r
+AMCPCommandQueue::~AMCPCommandQueue() \r
{\r
- commandPump_.Stop();\r
}\r
\r
-void AMCPCommandQueue::AddCommand(AMCPCommandPtr pNewCommand)\r
+void AMCPCommandQueue::AddCommand(AMCPCommandPtr pCurrentCommand)\r
{\r
- {\r
- tbb::mutex::scoped_lock lock(mutex_);\r
+ if(!pCurrentCommand)\r
+ return;\r
\r
- if(pNewCommand->GetScheduling() == ImmediatelyAndClear) {\r
- //Clears the queue, objects are deleted automatically\r
- commands_.clear();\r
-\r
- commands_.push_back(pNewCommand);\r
- CASPAR_LOG(info) << "Cleared queue and added command";\r
- }\r
- else {\r
- commands_.push_back(pNewCommand);\r
- CASPAR_LOG(info) << "Added command to end of queue";\r
- }\r
- }\r
-\r
- SetEvent(newCommandEvent_);\r
-}\r
-\r
-void AMCPCommandQueue::Run(HANDLE stopEvent)\r
-{\r
- bool logTemporarilyBadState = true;\r
- AMCPCommandPtr pCurrentCommand;\r
-\r
- CASPAR_LOG(info) << "AMCP CommandPump started";\r
-\r
- while(WaitForSingleObject(stopEvent, 0) != WAIT_OBJECT_0)\r
+ //if(pNewCommand->GetScheduling() == ImmediatelyAndClear)\r
+ // executor_.clear();\r
+ \r
+ executor_.begin_invoke([=]\r
{\r
- DWORD waitResult = WaitForSingleObject(newCommandEvent_, 50);\r
- if(waitResult == WAIT_OBJECT_0) \r
- {\r
- tbb::mutex::scoped_lock lock(mutex_);\r
-\r
- if(commands_.size() > 0)\r
- {\r
- CASPAR_LOG(debug) << "Found " << commands_.size() << " commands in queue";\r
-\r
- AMCPCommandPtr pNextCommand = commands_.front();\r
-\r
- if(pCurrentCommand == 0 || pNextCommand->GetScheduling() == ImmediatelyAndClear) {\r
- pCurrentCommand = pNextCommand;\r
- commands_.pop_front();\r
- }\r
- }\r
- }\r
-\r
- if(pCurrentCommand != 0) \r
+ try\r
{\r
try\r
{\r
}\r
\r
pCurrentCommand->SendReply();\r
- pCurrentCommand.reset();\r
-\r
- newCommandEvent_.Set();\r
- logTemporarilyBadState = true;\r
-\r
+ \r
CASPAR_LOG(info) << "Ready for a new command";\r
}\r
- }\r
-\r
- CASPAR_LOG(info) << "CommandPump ended";\r
-}\r
-\r
-bool AMCPCommandQueue::OnUnhandledException(const std::exception& ex) throw() \r
-{\r
- bool bDoRestart = true;\r
-\r
- try \r
- {\r
- CASPAR_LOG(fatal) << "UNHANDLED EXCEPTION in commandqueue. Message: " << ex.what();\r
- }\r
- catch(...)\r
- {\r
- bDoRestart = false;\r
- }\r
-\r
- return bDoRestart;\r
+ catch(...)\r
+ {\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ }\r
+ });\r
}\r
\r
}}}
\ No newline at end of file
\r
#include "AMCPCommand.h"\r
\r
+#include <common/concurrency/executor.h>\r
+\r
#include <tbb\mutex.h>\r
\r
namespace caspar { namespace protocol { namespace amcp {\r
\r
-class AMCPCommandQueue : public IRunnable\r
+class AMCPCommandQueue\r
{\r
AMCPCommandQueue(const AMCPCommandQueue&);\r
AMCPCommandQueue& operator=(const AMCPCommandQueue&);\r
AMCPCommandQueue();\r
~AMCPCommandQueue();\r
\r
- bool Start();\r
- void Stop();\r
void AddCommand(AMCPCommandPtr pCommand);\r
\r
private:\r
- Thread commandPump_;\r
- virtual void Run(HANDLE stopEvent);\r
- virtual bool OnUnhandledException(const std::exception& ex) throw();\r
-\r
- Event newCommandEvent_;\r
-\r
- //Needs synro-protection\r
- std::list<AMCPCommandPtr> commands_;\r
- tbb::mutex mutex_;\r
+ executor executor_;\r
};\r
typedef std::tr1::shared_ptr<AMCPCommandQueue> AMCPCommandQueuePtr;\r
\r
return true;\r
}\r
\r
-bool StatusCommand::DoExecute()\r
-{ \r
- if (GetLayerIndex() > -1)\r
- {\r
- auto status = GetChannel()->stage()->get_status(GetLayerIndex()).get();\r
- std::wstringstream status_text;\r
- status_text\r
- << L"201 STATUS OK\r\n"\r
- << L"<layer>"\r
- << L"\n\t<index>" << GetLayerIndex() << L"</index>"\r
- << L"\n\t<foreground>" << status.foreground << L"</foreground>"\r
- << L"\n\t<background>" << status.background << L"</background>"\r
- << L"\n\t<status>" << (status.is_paused ? L"paused" : L"playing") << L"</status>"\r
- << L"\n\t<nb-frames>" << (status.nb_frames == std::numeric_limits<int64_t>::max() ? 0 : status.nb_frames) << L"</nb-frames>"\r
- << L"\n\t<frame-number>" << status.frame_number << L"</frame-number>"\r
- << L"\n\t<file-nb-frames>" << (status.file_nb_frames == std::numeric_limits<int64_t>::max() ? 0 : status.file_nb_frames) << L"</file-nb-frames>"\r
- << L"\n\t<file-frame-number>" << status.file_frame_number << L"</file-frame-number>"\r
- << L"\n</layer>"\r
- << L"\r\n";\r
-\r
- SetReplyString(status_text.str());\r
- return true;\r
- }\r
- else\r
- {\r
- //NOTE: Possible to extend soo that "channel" status is returned when no layer is specified.\r
-\r
- SetReplyString(TEXT("403 LAYER MUST BE SPECIFIED\r\n"));\r
- return false;\r
- }\r
-}\r
-\r
bool LogCommand::DoExecute()\r
{\r
if(_parameters.at(0) == L"LEVEL")\r
}\r
else \r
{\r
- auto info = flash::get_default_cg_producer(safe_ptr<core::video_channel>(GetChannel()), GetLayerIndex(flash::cg_producer::DEFAULT_LAYER))->info();\r
+ auto info = flash::get_default_cg_producer(safe_ptr<core::video_channel>(GetChannel()), GetLayerIndex(flash::cg_producer::DEFAULT_LAYER))->template_host_info();\r
replyString << info << TEXT("\r\n"); \r
} \r
\r
\r
if(_parameters.size() >= 1)\r
{\r
- int channelIndex = boost::lexical_cast<int>(_parameters.at(0).c_str())-1; \r
- boost::property_tree::xml_parser::write_xml(replyString, channels_.at(channelIndex)->info(), boost::property_tree::xml_writer_settings<wchar_t>(' ', 3));\r
+ std::vector<std::wstring> split;\r
+ boost::split(split, _parameters[0], boost::is_any_of("-"));\r
+ \r
+ int layer = std::numeric_limits<int>::min();\r
+ int channel = boost::lexical_cast<int>(split[0]) - 1;\r
+\r
+ if(split.size() > 1)\r
+ layer = boost::lexical_cast<int>(split[1]);\r
+ \r
+ if(layer == std::numeric_limits<int>::min())\r
+ boost::property_tree::xml_parser::write_xml(replyString, channels_.at(channel)->info(), boost::property_tree::xml_writer_settings<wchar_t>(' ', 3));\r
+ else\r
+ boost::property_tree::xml_parser::write_xml(replyString, channels_.at(channel)->stage()->info(layer).get(), boost::property_tree::xml_writer_settings<wchar_t>(' ', 3));\r
}\r
else\r
{\r
boost::property_tree::wptree info;\r
- auto& node = info.add(L"channels", L"");\r
int index = 0;\r
BOOST_FOREACH(auto channel, channels_)\r
- {\r
- BOOST_FOREACH(auto update, channel->info())\r
- {\r
- auto& channel = node.add_child(update.first, update.second);\r
- channel.push_front(std::make_pair(L"index", boost::lexical_cast<std::wstring>(++index)));\r
- }\r
- }\r
+ info.add_child(L"channels.channel", channel->info())\r
+ .add(L"index", ++index);\r
+\r
boost::property_tree::xml_parser::write_xml(replyString, info, boost::property_tree::xml_writer_settings<wchar_t>(' ', 3));\r
}\r
replyString << TEXT("\r\n");\r
bool DoExecute();\r
};\r
\r
-class StatusCommand : public AMCPCommandBase<true, AddToQueue, 0>\r
-{\r
- std::wstring print() const { return L"StatusCommand";}\r
- bool DoExecute();\r
-};\r
-\r
class LogCommand : public AMCPCommandBase<false, AddToQueue, 0>\r
{\r
std::wstring print() const { return L"LogCommand";}\r
\r
AMCPProtocolStrategy::AMCPProtocolStrategy(const std::vector<safe_ptr<core::video_channel>>& channels) : channels_(channels) {\r
AMCPCommandQueuePtr pGeneralCommandQueue(new AMCPCommandQueue());\r
- if(!pGeneralCommandQueue->Start()) {\r
- CASPAR_LOG(error) << "Failed to start the general command-queue";\r
-\r
- //TODO: THROW!\r
- }\r
- else\r
- commandQueues_.push_back(pGeneralCommandQueue);\r
+ commandQueues_.push_back(pGeneralCommandQueue);\r
\r
\r
std::shared_ptr<core::video_channel> pChannel;\r
//HACK: Perform real conversion from int to string\r
TCHAR num = TEXT('1')+static_cast<TCHAR>(index);\r
title += num;\r
-\r
- if(!pChannelCommandQueue->Start()) {\r
- std::wstring logString = TEXT("Failed to start command-queue for ");\r
- logString += title;\r
- CASPAR_LOG(error) << logString;\r
-\r
- //TODO: THROW!\r
- }\r
- else\r
- commandQueues_.push_back(pChannelCommandQueue);\r
+ \r
+ commandQueues_.push_back(pChannelCommandQueue);\r
}\r
}\r
\r
else if(s == TEXT("STOP")) return std::make_shared<StopCommand>();\r
else if(s == TEXT("CLEAR")) return std::make_shared<ClearCommand>();\r
else if(s == TEXT("PRINT")) return std::make_shared<PrintCommand>();\r
- else if(s == TEXT("STATUS")) return std::make_shared<StatusCommand>();\r
else if(s == TEXT("LOG")) return std::make_shared<LogCommand>();\r
else if(s == TEXT("CG")) return std::make_shared<CGCommand>();\r
else if(s == TEXT("DATA")) return std::make_shared<DataCommand>();\r
<template-path>D:\casparcg\_templates\</template-path>\r
</paths>\r
<channels>\r
- <channel>\r
- <video-mode>720p5000</video-mode>\r
- <consumers>\r
- <decklink>\r
- <device>1</device>\r
- </decklink>\r
- </consumers>\r
- </channel>\r
<channel>\r
<video-mode>720p5000</video-mode>\r
<consumers>\r