\r
void wait()\r
{\r
- invoke([]{});\r
+ if(is_running_)\r
+ invoke([]{});\r
}\r
\r
void clear()\r
{\r
std::function<void()> func;\r
- while(true)\r
+ auto size = execution_queue_.size();\r
+ for(int n = 0; n < size; ++n)\r
{\r
try\r
{\r
\r
void render(sf::RenderTarget& target)\r
{\r
- auto count = std::max<size_t>(10, drawables_.size());\r
+ auto count = std::max<size_t>(8, drawables_.size());\r
float target_dy = 1.0f/static_cast<float>(count);\r
\r
float last_y = 0.0f;\r
struct graph::implementation : public drawable\r
{\r
std::map<std::string, diagnostics::line> lines_;\r
+ const printer parent_printer_;\r
std::string name_;\r
- std::string display_name_;\r
+\r
+ int counter_;\r
\r
implementation(const std::string& name) \r
- : name_(name), display_name_(name_){}\r
+ : name_(name)\r
+ , counter_(0){}\r
+\r
+ implementation(const printer& parent_printer) \r
+ : parent_printer_(parent_printer)\r
+ , name_(parent_printer_ ? narrow(parent_printer_()) : "")\r
+ , counter_(0){}\r
\r
void update(const std::string& name, float value)\r
{\r
lines_[name].guide(diagnostics::guide(value));\r
});\r
}\r
-\r
- void set_display_name(const std::string& name)\r
- {\r
- context::begin_invoke([=]\r
- {\r
- display_name_ = name;\r
- }); \r
- }\r
-\r
+ \r
private:\r
void render(sf::RenderTarget& target)\r
{\r
+ if(counter_++ > 25) // Don't update name too often since print can be implemented with locks.\r
+ {\r
+ counter_ = 0;\r
+ if(parent_printer_)\r
+ name_ = narrow(parent_printer_());\r
+ }\r
const size_t text_size = 15;\r
const size_t text_margin = 2;\r
- const size_t text_offset = text_size+text_margin*2;\r
+ const size_t text_offset = (text_size+text_margin*2)*2;\r
\r
- sf::String text(display_name_.c_str(), sf::Font::GetDefaultFont(), text_size);\r
+ sf::String text(name_.c_str(), sf::Font::GetDefaultFont(), text_size);\r
text.SetStyle(sf::String::Italic);\r
text.Move(text_margin, text_margin);\r
\r
glPushMatrix();\r
glScaled(1.0f/GetScale().x, 1.0f/GetScale().y, 1.0f);\r
target.Draw(text);\r
- float x_offset = text.GetPosition().x + text.GetRect().Right + text_margin*4;\r
+ float x_offset = text_margin;\r
for(auto it = lines_.begin(); it != lines_.end(); ++it)\r
{ \r
sf::String line_text(it->first, sf::Font::GetDefaultFont(), text_size);\r
- line_text.SetPosition(x_offset, text_margin);\r
+ line_text.SetPosition(x_offset, text_margin+text_offset/2);\r
auto c = it->second.get_color();\r
line_text.SetColor(sf::Color(c.red*255.0f, c.green*255.0f, c.blue*255.0f, c.alpha*255.0f));\r
target.Draw(line_text);\r
context::register_drawable(impl_);\r
}\r
\r
+graph::graph(const printer& parent_printer) : impl_(env::properties().get("configuration.diagnostics.graphs", true) ? new implementation(parent_printer) : nullptr)\r
+{\r
+ if(impl_)\r
+ context::register_drawable(impl_);\r
+}\r
+\r
void graph::update(const std::string& name, float value){if(impl_)impl_->update(name, value);}\r
void graph::set(const std::string& name, float value){if(impl_)impl_->set(name, value);}\r
void graph::tag(const std::string& name){if(impl_)impl_->tag(name);}\r
void graph::guide(const std::string& name, float value){if(impl_)impl_->guide(name, value);}\r
void graph::set_color(const std::string& name, color c){if(impl_)impl_->set_color(name, c);}\r
-void graph::set_display_name(const std::string& name){if(impl_)impl_->set_display_name(name);}\r
\r
safe_ptr<graph> create_graph(const std::string& name)\r
{\r
return safe_ptr<graph>(new graph(name));\r
}\r
+safe_ptr<graph> create_graph(const printer& parent_printer)\r
+{\r
+ return safe_ptr<graph>(new graph(parent_printer));\r
+}\r
\r
}}
\ No newline at end of file
\r
#include "../memory/safe_ptr.h"\r
\r
+#include "../utility/printable.h"\r
+\r
#include <string>\r
\r
namespace caspar { namespace diagnostics {\r
class graph\r
{\r
friend safe_ptr<graph> create_graph(const std::string& name);\r
+ friend safe_ptr<graph> create_graph(const printer& parent_printer);\r
graph(const std::string& name);\r
+ graph(const printer& parent_printer);\r
public:\r
void update(const std::string& name, float value);\r
void set(const std::string& name, float value);\r
void tag(const std::string& name);\r
void guide(const std::string& name, float value);\r
void set_color(const std::string& name, color c);\r
- void set_display_name(const std::string& name);\r
private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
};\r
\r
safe_ptr<graph> create_graph(const std::string& name);\r
+safe_ptr<graph> create_graph(const printer& parent_printer);\r
\r
}}
\ No newline at end of file
#include <type_traits>\r
#include <exception>\r
\r
+#include <tbb/spin_mutex.h>\r
+\r
namespace caspar {\r
\r
template<typename T>\r
class safe_ptr\r
{ \r
+ std::shared_ptr<T> impl_;\r
+ tbb::spin_mutex mutex_;\r
template <typename> friend class safe_ptr;\r
public:\r
typedef T element_type;\r
\r
template<class D, class U> \r
D* get_deleter(safe_ptr<U> const& ptr) { return impl_.get_deleter(); } // noexcept\r
- \r
-private: \r
- std::shared_ptr<T> impl_;\r
};\r
\r
template<class T, class U>\r
struct channel::implementation : boost::noncopyable\r
{ \r
const int index_;\r
+ const video_format_desc format_desc_;\r
\r
std::shared_ptr<frame_consumer_device> consumer_;\r
std::shared_ptr<frame_mixer_device> mixer_;\r
std::shared_ptr<frame_producer_device> producer_;\r
\r
- const video_format_desc format_desc_;\r
-\r
public:\r
implementation(int index, const video_format_desc& format_desc) \r
: index_(index)\r
, format_desc_(format_desc)\r
- , consumer_(new frame_consumer_device(format_desc))\r
- , mixer_(new frame_mixer_device(format_desc, std::bind(&frame_consumer_device::send, consumer_.get(), std::placeholders::_1)))\r
- , producer_(new frame_producer_device(safe_ptr<frame_factory>(mixer_), std::bind(&frame_mixer_device::send, mixer_.get(), std::placeholders::_1), std::bind(&implementation::print, this))) {}\r
+ , consumer_(new frame_consumer_device(std::bind(&implementation::print, this), format_desc))\r
+ , mixer_(new frame_mixer_device(std::bind(&implementation::print, this), format_desc, std::bind(&frame_consumer_device::send, consumer_.get(), std::placeholders::_1)))\r
+ , producer_(new frame_producer_device(std::bind(&implementation::print, this), safe_ptr<frame_factory>(mixer_), std::bind(&frame_mixer_device::send, mixer_.get(), std::placeholders::_1))) {}\r
\r
~implementation()\r
{\r
// Shutdown order is important! Destroy all created frames to mixer before destroying mixer.\r
- CASPAR_LOG(info) << print() << " shutting down channel.";\r
+ CASPAR_LOG(info) << print() << " Shutting down channel.";\r
producer_.reset();\r
- CASPAR_LOG(info) << print() << "successfully shut down producer-device.";\r
+ CASPAR_LOG(info) << print() << " Successfully shut down producer-device.";\r
consumer_.reset();\r
- CASPAR_LOG(info) << print() << "successfully shut down consumer-device.";\r
+ CASPAR_LOG(info) << print() << " Successfully shut down consumer-device.";\r
mixer_.reset();\r
- CASPAR_LOG(info) << print() << "successfully shut down mixer-device.";\r
+ CASPAR_LOG(info) << print() << " Successfully shut down mixer-device.";\r
}\r
\r
std::wstring print() const\r
{\r
- return L"channel[" + boost::lexical_cast<std::wstring>(index_) + L"]";\r
+ return L"channel[" + format_desc_.name + L", " + boost::lexical_cast<std::wstring>(index_+1) + L"]";\r
}\r
};\r
\r
frame_mixer_device& channel::mixer() { return *impl_->mixer_;} \r
frame_consumer_device& channel::consumer() { return *impl_->consumer_;} \r
const video_format_desc& channel::get_video_format_desc() const{return impl_->format_desc_;}\r
+std::wstring channel::print() const { return impl_->print();}\r
\r
}}
\ No newline at end of file
\r
const video_format_desc& get_video_format_desc() const;\r
\r
+ std::wstring print() const;\r
+\r
private:\r
struct implementation;\r
safe_ptr<implementation> impl_;\r
\r
struct bluefish_consumer::implementation : boost::noncopyable\r
{\r
+ printer parent_printer_;\r
std::wstring model_name_;\r
const unsigned int device_index_;\r
\r
\r
CASPAR_LOG(info) << print() << TEXT(" Successfully initialized for ") << format_desc_ << TEXT(".");\r
}\r
+\r
+ void set_parent_printer(const printer& parent_printer)\r
+ {\r
+ parent_printer_ = parent_printer;\r
+ }\r
\r
void enable_video_output()\r
{\r
\r
std::wstring print() const\r
{\r
- return model_name_ + L" [output-" + boost::lexical_cast<std::wstring>(device_index_) + L"]";\r
+ return (parent_printer_ ? parent_printer_() + L"/" : L"") + model_name_ + L" [" + boost::lexical_cast<std::wstring>(device_index_) + L"]";\r
}\r
};\r
\r
bluefish_consumer::bluefish_consumer(bluefish_consumer&& other) : impl_(std::move(other.impl_)){}\r
bluefish_consumer::bluefish_consumer(unsigned int device_index, bool embed_audio) : impl_(new implementation(device_index, embed_audio)){} \r
void bluefish_consumer::initialize(const video_format_desc& format_desc){impl_->initialize(format_desc);}\r
+void bluefish_consumer::set_parent_printer(const printer& parent_printer){impl_->set_parent_printer(parent_printer);}\r
void bluefish_consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
size_t bluefish_consumer::buffer_depth() const{return impl_->buffer_depth();}\r
\r
bluefish_consumer(bluefish_consumer&& other);\r
\r
virtual void initialize(const video_format_desc& format_desc);\r
+ virtual void set_parent_printer(const printer& parent_printer);\r
virtual void send(const safe_ptr<const read_frame>&);\r
virtual size_t buffer_depth() const;\r
private:\r
~co_init(){CoUninitialize();}\r
} co_;\r
\r
+ const printer parent_printer_;\r
std::wstring model_name_;\r
const size_t device_index_;\r
\r
tbb::concurrent_bounded_queue<safe_ptr<const read_frame>> audio_frame_buffer_;\r
\r
public:\r
- decklink_output(size_t device_index, bool embed_audio, bool internalKey) \r
- : model_name_(L"DECKLINK")\r
+ decklink_output(const printer& parent_printer, size_t device_index, bool embed_audio, bool internalKey) \r
+ : parent_printer_(parent_printer)\r
+ , model_name_(L"DECKLINK")\r
, device_index_(device_index)\r
, audio_container_(5)\r
, embed_audio_(embed_audio)\r
\r
std::wstring print() const\r
{\r
- return model_name_ + L" [output-" + boost::lexical_cast<std::wstring>(device_index_) + L"]";\r
+ return (parent_printer_ ? parent_printer_() + L"/" : L"") + model_name_ + L" [" + boost::lexical_cast<std::wstring>(device_index_) + L"]";\r
}\r
};\r
\r
struct decklink_consumer::implementation\r
{\r
+ printer parent_printer_;\r
std::unique_ptr<decklink_output> input_;\r
\r
executor executor_;\r
executor_.start();\r
executor_.invoke([&]\r
{\r
- input_.reset(new decklink_output(device_index, embed_audio, internalKey));\r
+ input_.reset(new decklink_output(parent_printer_, device_index, embed_audio, internalKey));\r
});\r
}\r
\r
});\r
}\r
\r
+ void set_parent_printer(const printer& parent_printer)\r
+ {\r
+ parent_printer_ = parent_printer;\r
+ }\r
+\r
void send(const safe_ptr<const read_frame>& frame)\r
{\r
input_->send(frame);\r
decklink_consumer::decklink_consumer(size_t device_index, bool embed_audio, bool internalKey) : impl_(new implementation(device_index, embed_audio, internalKey)){}\r
decklink_consumer::decklink_consumer(decklink_consumer&& other) : impl_(std::move(other.impl_)){}\r
void decklink_consumer::initialize(const video_format_desc& format_desc){impl_->initialize(format_desc);}\r
+void decklink_consumer::set_parent_printer(const printer& parent_printer){impl_->set_parent_printer(parent_printer);}\r
void decklink_consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
size_t decklink_consumer::buffer_depth() const{return impl_->buffer_depth();}\r
\r
decklink_consumer(decklink_consumer&& other);\r
\r
virtual void initialize(const video_format_desc& format_desc);\r
+ virtual void set_parent_printer(const printer& parent_printer);\r
virtual void send(const safe_ptr<const read_frame>&);\r
virtual size_t buffer_depth() const;\r
private:\r
\r
struct ffmpeg_consumer::implementation : boost::noncopyable\r
{ \r
+ printer parent_printer_;\r
const std::string filename_;\r
\r
// Audio\r
\r
av_write_header(oc_.get()); // write the stream header, if any \r
}\r
+ \r
+ void set_parent_printer(const printer& parent_printer) \r
+ {\r
+ parent_printer_ = parent_printer;\r
+ }\r
\r
AVStream* add_video_stream(enum CodecID codec_id)\r
{ \r
void ffmpeg_consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
size_t ffmpeg_consumer::buffer_depth() const{return impl_->buffer_depth();}\r
void ffmpeg_consumer::initialize(const video_format_desc& format_desc) {impl_->initialize(format_desc);}\r
+void ffmpeg_consumer::set_parent_printer(const printer& parent_printer){impl_->set_parent_printer(parent_printer);}\r
\r
safe_ptr<frame_consumer> create_ffmpeg_consumer(const std::vector<std::wstring>& params)\r
{\r
ffmpeg_consumer(ffmpeg_consumer&& other);\r
\r
virtual void initialize(const video_format_desc& format_desc);\r
+ virtual void set_parent_printer(const printer& parent_printer);\r
virtual void send(const safe_ptr<const read_frame>&);\r
virtual size_t buffer_depth() const;\r
private:\r
\r
#include <boost/noncopyable.hpp>\r
\r
+#include <common/utility/printable.h>\r
+\r
namespace caspar { namespace core {\r
\r
class read_frame;\r
virtual void send(const safe_ptr<const read_frame>& frame) = 0;\r
virtual size_t buffer_depth() const = 0;\r
virtual void initialize(const video_format_desc& format_desc) = 0;\r
+ virtual void set_parent_printer(const printer& parent_printer) = 0;\r
\r
static const safe_ptr<frame_consumer>& empty()\r
{\r
virtual void send(const safe_ptr<const read_frame>&){}\r
virtual size_t buffer_depth() const{return 0;}\r
void initialize(const video_format_desc&){}\r
+ void set_parent_printer(const printer&){}\r
};\r
static safe_ptr<frame_consumer> consumer = make_safe<empty_frame_consumer>();\r
return consumer;\r
\r
struct frame_consumer_device::implementation\r
{ \r
+ const printer parent_printer_;\r
timer clock_;\r
\r
boost::circular_buffer<safe_ptr<const read_frame>> buffer_;\r
\r
executor executor_; \r
public:\r
- implementation(const video_format_desc& format_desc) \r
- : format_desc_(format_desc)\r
+ implementation(const printer& parent_printer, const video_format_desc& format_desc) \r
+ : parent_printer_(parent_printer)\r
+ , format_desc_(format_desc)\r
, executor_(L"frame_consumer_device")\r
{ \r
executor_.set_capacity(2);\r
\r
void add(int index, safe_ptr<frame_consumer>&& consumer)\r
{ \r
+ consumer->set_parent_printer(std::bind(&implementation::print, this));\r
consumer->initialize(format_desc_);\r
executor_.invoke([&]\r
{\r
clock_.tick(1.0/format_desc_.fps);\r
});\r
}\r
+\r
+ std::wstring print() const\r
+ {\r
+ return (parent_printer_ ? parent_printer_() + L"/" : L"") + L"consumer";\r
+ }\r
};\r
\r
frame_consumer_device::frame_consumer_device(frame_consumer_device&& other) : impl_(std::move(other.impl_)){}\r
-frame_consumer_device::frame_consumer_device(const video_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
+frame_consumer_device::frame_consumer_device(const printer& parent_printer, const video_format_desc& format_desc) : impl_(new implementation(parent_printer, format_desc)){}\r
void frame_consumer_device::add(int index, safe_ptr<frame_consumer>&& consumer){impl_->add(index, std::move(consumer));}\r
void frame_consumer_device::remove(int index){impl_->remove(index);}\r
void frame_consumer_device::send(const safe_ptr<const read_frame>& future_frame) { impl_->send(future_frame); }\r
#include "../consumer/frame_consumer.h"\r
\r
#include <common/memory/safe_ptr.h>\r
+#include <common/utility/printable.h>\r
\r
#include <vector>\r
\r
class frame_consumer_device : boost::noncopyable\r
{\r
public:\r
- explicit frame_consumer_device(const video_format_desc& format_desc);\r
+ explicit frame_consumer_device(const printer& parent_printer, const video_format_desc& format_desc);\r
frame_consumer_device(frame_consumer_device&& other);\r
\r
void add(int index, safe_ptr<frame_consumer>&& consumer);\r
\r
struct oal_consumer::implementation : public sf::SoundStream, boost::noncopyable\r
{\r
+ printer parent_printer_;\r
safe_ptr<diagnostics::graph> graph_;\r
timer perf_timer_;\r
\r
Play(); \r
CASPAR_LOG(info) << print() << " Sucessfully initialized.";\r
}\r
- \r
+\r
+ void set_parent_printer(const printer& parent_printer)\r
+ {\r
+ parent_printer_ = parent_printer;\r
+ }\r
+ \r
void send(const safe_ptr<const read_frame>& frame)\r
{ \r
if(!frame->audio_data().empty())\r
\r
std::wstring print() const\r
{\r
- return L"Default Audio Device [output]";\r
+ return (parent_printer_ ? parent_printer_() + L"/" : L"") + L"oal";\r
}\r
};\r
\r
void oal_consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
size_t oal_consumer::buffer_depth() const{return impl_->buffer_depth();}\r
void oal_consumer::initialize(const video_format_desc& format_desc){impl_->initialize(format_desc);}\r
+void oal_consumer::set_parent_printer(const printer& parent_printer){impl_->set_parent_printer(parent_printer);}\r
\r
safe_ptr<frame_consumer> create_oal_consumer(const std::vector<std::wstring>& params)\r
{\r
oal_consumer(oal_consumer&& other);\r
\r
virtual void initialize(const video_format_desc& format_desc); \r
+ virtual void set_parent_printer(const printer& parent_printer);\r
+\r
virtual void send(const safe_ptr<const read_frame>&);\r
virtual size_t buffer_depth() const;\r
private:\r
namespace caspar { namespace core {\r
\r
struct ogl_consumer::implementation : boost::noncopyable\r
-{ \r
+{ \r
+ printer parent_printer_;\r
boost::unique_future<void> active_;\r
\r
float wratio_;\r
, screen_y_(0)\r
, screen_index_(screen_index)\r
, graph_(diagnostics::create_graph(narrow(print())))\r
+ , executor_(print())\r
{ \r
graph_->guide("frame-time", 0.5);\r
graph_->set_color("frame-time", diagnostics::color(1.0f, 0.0f, 0.0f));\r
-\r
- CASPAR_LOG(info) << print() << " Sucessfully initialized.";\r
}\r
\r
~implementation()\r
executor_.start();\r
executor_.invoke([=]\r
{\r
- window_.Create(sf::VideoMode(format_desc_.width, format_desc_.height, 32), "CasparCG", windowed_ ? sf::Style::Titlebar : sf::Style::Fullscreen);\r
+ window_.Create(sf::VideoMode(format_desc_.width, format_desc_.height, 32), narrow(print()), windowed_ ? sf::Style::Titlebar : sf::Style::Fullscreen);\r
window_.ShowMouseCursor(false);\r
window_.SetPosition(screen_x_, screen_y_);\r
window_.SetSize(screen_width_, screen_height_);\r
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);\r
});\r
active_ = executor_.begin_invoke([]{});\r
+ CASPAR_LOG(info) << print() << " Sucessfully initialized.";\r
+ }\r
+\r
+ void set_parent_printer(const printer& parent_printer)\r
+ {\r
+ parent_printer_ = parent_printer;\r
}\r
\r
std::pair<float, float> None()\r
\r
std::wstring print() const\r
{\r
- return L"OpenGL Device [output-" + boost::lexical_cast<std::wstring>(screen_index_) + L"]";\r
+ return (parent_printer_ ? parent_printer_() + L"/" : L"") + L"ogl[" + boost::lexical_cast<std::wstring>(screen_index_) + L"]";\r
}\r
\r
size_t buffer_depth() const{return 2;}\r
void ogl_consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
size_t ogl_consumer::buffer_depth() const{return impl_->buffer_depth();}\r
void ogl_consumer::initialize(const video_format_desc& format_desc){impl_->initialize(format_desc);}\r
+void ogl_consumer::set_parent_printer(const printer& parent_printer){impl_->set_parent_printer(parent_printer);}\r
\r
safe_ptr<frame_consumer> create_ogl_consumer(const std::vector<std::wstring>& params)\r
{\r
ogl_consumer(ogl_consumer&& other);\r
\r
virtual void initialize(const video_format_desc& format_desc);\r
+ virtual void set_parent_printer(const printer& parent_printer);\r
virtual void send(const safe_ptr<const read_frame>&);\r
virtual size_t buffer_depth() const;\r
private:\r
\r
public:\r
\r
- explicit color_producer(const std::wstring& color) : color_str_(color), frame_(draw_frame::empty())\r
+ explicit color_producer(const std::wstring& color) \r
+ : color_str_(color)\r
+ , frame_(draw_frame::empty())\r
{\r
if(color.length() != 9 || color[0] != '#')\r
BOOST_THROW_EXCEPTION(invalid_argument() << arg_name_info("color") << arg_value_info(narrow(color)) << msg_info("Invalid color code"));\r
\r
#pragma warning(push)\r
\r
+#include <functional>\r
+\r
namespace caspar { namespace core {\r
\r
class decklink_input : public IDeckLinkInputCallback\r
decklink_->GetModelName(&pModelName);\r
model_name_ = std::wstring(pModelName);\r
\r
- graph_ = diagnostics::create_graph(narrow(print()));\r
+ graph_ = diagnostics::create_graph(boost::bind(&decklink_input::print, this));\r
graph_->guide("tick-time", 0.5);\r
graph_->set_color("tick-time", diagnostics::color(0.1f, 0.7f, 0.8f));\r
\r
#include <tbb/parallel_invoke.h>\r
\r
#include <deque>\r
+#include <functional>\r
\r
namespace caspar { namespace core { namespace ffmpeg{\r
\r
const bool loop_;\r
printer parent_printer_;\r
\r
- safe_ptr<diagnostics::graph> graph_;\r
+ std::shared_ptr<diagnostics::graph> graph_;\r
timer perf_timer_;\r
\r
std::unique_ptr<audio_decoder> audio_decoder_;\r
public:\r
explicit ffmpeg_producer(const std::wstring& filename, bool loop) \r
: filename_(filename)\r
- , loop_(loop)\r
- , graph_(diagnostics::create_graph(narrow(print()))) \r
+ , loop_(loop) \r
, last_frame_(draw_frame(draw_frame::empty()))\r
\r
{\r
+ graph_ = diagnostics::create_graph(boost::bind(&ffmpeg_producer::print, this)); \r
graph_->guide("frame-time", 0.5);\r
graph_->set_color("frame-time", diagnostics::color(1.0f, 0.0f, 0.0f));\r
}\r
-\r
- ~ffmpeg_producer()\r
- {\r
- CASPAR_LOG(info) << print() << " stopping.";\r
- }\r
-\r
+ \r
virtual void initialize(const safe_ptr<frame_factory>& frame_factory)\r
{\r
frame_factory_ = frame_factory;\r
- input_.reset(new input(graph_, filename_, loop_, std::bind(&ffmpeg_producer::print, this)));\r
+ input_.reset(new input(safe_ptr<diagnostics::graph>(graph_), filename_, loop_, std::bind(&ffmpeg_producer::print, this)));\r
video_decoder_.reset(input_->get_video_codec_context().get() ? new video_decoder(input_->get_video_codec_context().get(), frame_factory) : nullptr);\r
audio_decoder_.reset(input_->get_audio_codec_context().get() ? new audio_decoder(input_->get_audio_codec_context().get(), frame_factory->get_video_format_desc().fps) : nullptr);\r
}\r
\r
std::wstring print() const\r
{\r
- return (parent_printer_ ? parent_printer_() + L"/" : L"") + L"[async_input]";\r
+ return (parent_printer_ ? parent_printer_() + L"/" : L"") + L"async_input";\r
}\r
};\r
\r
\r
#include <boost/filesystem.hpp>\r
\r
+#include <functional>\r
+\r
namespace caspar { namespace core { namespace flash {\r
\r
bool interlaced(double fps, const video_format_desc& format_desc)\r
const std::wstring filename_; \r
tbb::atomic<int> fps_;\r
\r
- safe_ptr<diagnostics::graph> graph_;\r
+ std::shared_ptr<diagnostics::graph> graph_;\r
\r
safe_ptr<draw_frame> tail_;\r
tbb::concurrent_bounded_queue<safe_ptr<draw_frame>> frame_buffer_;\r
boost::lexical_cast<std::wstring>(fps_) + \r
(interlaced(fps_, format_desc_) ? L"i" : L"p") + L"]"; \r
} \r
-\r
- void set_fps(double fps)\r
- {\r
- int fps100 = static_cast<int>(renderer_->fps()*100.0);\r
- if(fps_.fetch_and_store(fps100) != fps100)\r
- graph_->set_display_name(narrow(print())); \r
- }\r
- \r
+ \r
public:\r
implementation(const std::wstring& filename) \r
- : filename_(filename)\r
- , graph_(diagnostics::create_graph(narrow(print())))\r
+ : filename_(filename) \r
, tail_(draw_frame::empty()) \r
, executor_(print())\r
{ \r
if(!boost::filesystem::exists(filename))\r
BOOST_THROW_EXCEPTION(file_not_found() << boost::errinfo_file_name(narrow(filename))); \r
-\r
+ \r
+ graph_ = diagnostics::create_graph(boost::bind(&implementation::print, this));\r
fps_ = 0;\r
graph_->set_color("output-buffer", diagnostics::color(0.0f, 1.0f, 0.0f)); \r
}\r
do{frame = renderer_->render_frame(frame_buffer_.size() < frame_buffer_.capacity()-2);}\r
while(frame_buffer_.try_push(frame) && frame == draw_frame::empty());\r
graph_->set("output-buffer", static_cast<float>(frame_buffer_.size())/static_cast<float>(frame_buffer_.capacity())); \r
- set_fps(renderer_->fps());\r
+ fps_.fetch_and_store(static_cast<int>(renderer_->fps()*100.0));\r
}\r
catch(...)\r
{\r
{\r
if(!renderer_)\r
{\r
- renderer_.reset(new flash_renderer(graph_, frame_factory_, filename_, [=]{return print();}));\r
+ renderer_.reset(new flash_renderer(safe_ptr<diagnostics::graph>(graph_), frame_factory_, filename_, [=]{return print();}));\r
while(frame_buffer_.try_push(draw_frame::empty())){} \r
}\r
\r
mutable executor executor_;\r
\r
public:\r
- implementation(const safe_ptr<frame_factory>& factory, const output_func& output, const printer& parent_printer) \r
+ implementation(const printer& parent_printer, const safe_ptr<frame_factory>& factory, const output_func& output) \r
: parent_printer_(parent_printer)\r
, factory_(factory)\r
, output_(output)\r
{\r
for(int n = 0; n < frame_producer_device::MAX_LAYER+1; ++n)\r
- layers_.push_back(layer(n, parent_printer_));\r
+ layers_.push_back(layer(n, std::bind(&implementation::print, this)));\r
\r
executor_.start();\r
executor_.begin_invoke([=]{tick();});\r
return layers_.at(index).foreground();\r
});\r
}\r
+\r
+ std::wstring print() const\r
+ {\r
+ return (parent_printer_ ? parent_printer_() + L"/" : L"") + L"producer";\r
+ }\r
};\r
\r
-frame_producer_device::frame_producer_device(const safe_ptr<frame_factory>& factory, const output_func& output, const printer& printer) : impl_(new implementation(factory, output, printer)){}\r
+frame_producer_device::frame_producer_device(const printer& parent_printer, const safe_ptr<frame_factory>& factory, const output_func& output) : impl_(new implementation(parent_printer, factory, output)){}\r
frame_producer_device::frame_producer_device(frame_producer_device&& other) : impl_(std::move(other.impl_)){}\r
void frame_producer_device::load(size_t index, const safe_ptr<frame_producer>& producer, bool play_on_load){impl_->load(index, producer, play_on_load);}\r
void frame_producer_device::preview(size_t index, const safe_ptr<frame_producer>& producer){impl_->preview(index, producer);}\r
\r
typedef std::function<void(const std::vector<safe_ptr<draw_frame>>&)> output_func;\r
\r
- explicit frame_producer_device(const safe_ptr<frame_factory>& factory, const output_func& output, const printer& printer);\r
+ explicit frame_producer_device(const printer& parent_printer, const safe_ptr<frame_factory>& factory, const output_func& output);\r
frame_producer_device(frame_producer_device&& other);\r
\r
void load(size_t index, const safe_ptr<frame_producer>& producer, bool play_on_load = false);\r
#include <mixer/audio/audio_mixer.h>\r
#include <mixer/audio/audio_transform.h>\r
\r
-#include <tbb/recursive_mutex.h>\r
+#include <tbb/spin_mutex.h>\r
\r
namespace caspar { namespace core {\r
\r
{\r
auto name = producer->print();\r
producer = frame_producer::empty();\r
- CASPAR_LOG(info) << L"async_remover[" + boost::lexical_cast<std::wstring>(--count_) + L"] Removed: " << name << L".";\r
+ CASPAR_LOG(info) << name << L" Removed.";\r
}\r
public:\r
\r
void remove(safe_ptr<frame_producer>&& producer)\r
{\r
CASPAR_ASSERT(producer.unique());\r
- CASPAR_LOG(info) << L"async_remover[" + boost::lexical_cast<std::wstring>(++count_) + L"] Removing: " << producer->print() << L".";\r
executor_.begin_invoke(std::bind(&frame_producer_remover::do_remove, this, std::move(producer)));\r
}\r
};\r
\r
frame_producer_remover g_remover;\r
\r
+\r
struct layer::implementation : boost::noncopyable\r
{ \r
- tbb::recursive_mutex mutex_;\r
+ mutable tbb::spin_mutex printer_mutex_;\r
printer parent_printer_;\r
- tbb::atomic<int> index_;\r
-\r
+ int index_;\r
+ \r
safe_ptr<frame_producer> foreground_;\r
safe_ptr<frame_producer> background_;\r
safe_ptr<draw_frame> last_frame_;\r
public:\r
implementation(int index, const printer& parent_printer) \r
: parent_printer_(parent_printer)\r
+ , index_(index)\r
, foreground_(frame_producer::empty())\r
, background_(frame_producer::empty())\r
, last_frame_(draw_frame::empty())\r
- , is_paused_(false)\r
- {\r
- index_ = index;\r
- }\r
+ , is_paused_(false){}\r
\r
void load(const safe_ptr<frame_producer>& frame_producer, bool play_on_load)\r
{ \r
- tbb::recursive_mutex::scoped_lock lock(mutex_);\r
-\r
background_ = frame_producer;\r
is_paused_ = false;\r
if(play_on_load)\r
\r
void preview(const safe_ptr<frame_producer>& frame_producer)\r
{\r
- tbb::recursive_mutex::scoped_lock lock(mutex_);\r
-\r
load(frame_producer, true);\r
receive();\r
pause();\r
}\r
\r
void play()\r
- { \r
- tbb::recursive_mutex::scoped_lock lock(mutex_);\r
- \r
+ { \r
if(!is_paused_) \r
{\r
background_->set_leading_producer(foreground_);\r
foreground_ = background_;\r
- CASPAR_LOG(info) << foreground_->print() << L" Started.";\r
+ CASPAR_LOG(info) << foreground_->print() << L" Activated.";\r
background_ = frame_producer::empty();\r
}\r
is_paused_ = false;\r
\r
void pause()\r
{\r
- tbb::recursive_mutex::scoped_lock lock(mutex_);\r
-\r
is_paused_ = true;\r
}\r
\r
void stop()\r
{\r
- tbb::recursive_mutex::scoped_lock lock(mutex_);\r
-\r
pause();\r
last_frame_ = draw_frame::empty();\r
foreground_ = frame_producer::empty();\r
}\r
\r
void clear()\r
- {\r
- tbb::recursive_mutex::scoped_lock lock(mutex_);\r
- \r
+ { \r
foreground_ = frame_producer::empty();\r
background_ = frame_producer::empty();\r
last_frame_ = draw_frame::empty();\r
\r
safe_ptr<draw_frame> receive()\r
{ \r
- tbb::recursive_mutex::scoped_lock lock(mutex_);\r
-\r
if(is_paused_)\r
{\r
last_frame_->get_audio_transform().set_gain(0.0);\r
\r
auto following = foreground_->get_following_producer();\r
following->set_leading_producer(foreground_);\r
+ following->set_parent_printer(boost::bind(&implementation::print, this));\r
g_remover.remove(std::move(foreground_));\r
foreground_ = following;\r
- CASPAR_LOG(info) << foreground_->print() << L" Started.";\r
+ CASPAR_LOG(info) << foreground_->print() << L" Activated.";\r
\r
last_frame_ = receive();\r
}\r
}\r
catch(...)\r
{\r
- CASPAR_LOG(error) << print() << L"Unhandled Exception: ";\r
+ CASPAR_LOG(error) << print() << L" Unhandled Exception: ";\r
CASPAR_LOG_CURRENT_EXCEPTION();\r
stop();\r
}\r
\r
return last_frame_;\r
}\r
- \r
- void swap(implementation& other)\r
- {\r
- tbb::recursive_mutex::scoped_lock lock(mutex_);\r
- std::swap(foreground_, other.foreground_);\r
- std::swap(background_, other.background_);\r
- std::swap(last_frame_, other.last_frame_);\r
- std::swap(is_paused_, other.is_paused_);\r
- }\r
- \r
+ \r
std::wstring print() const\r
{\r
- return (parent_printer_ ? parent_printer_() + L"/" : L"") + L"layer[" + boost::lexical_cast<std::wstring>(index_) + L"]";\r
+ std::wstring parent_print = L"";\r
+ {\r
+ tbb::spin_mutex::scoped_lock lock(printer_mutex_);\r
+ if(parent_printer_)\r
+ parent_print = parent_printer_() + L"/";\r
+ }\r
+ return parent_print + L"layer[" + boost::lexical_cast<std::wstring>(index_) + L"]";\r
}\r
};\r
\r
-layer::layer(int index, const printer& parent_printer) : impl_(new implementation(index, parent_printer)){}\r
-layer::layer(layer&& other) : impl_(std::move(other.impl_)){}\r
+layer::layer(int index, const printer& parent_printer)\r
+{\r
+ impl_ = new implementation(index, parent_printer);\r
+}\r
+layer::~layer()\r
+{\r
+ if(!impl_)\r
+ return;\r
+\r
+ impl_->clear();\r
+ delete impl_.fetch_and_store(nullptr);\r
+}\r
+layer::layer(layer&& other)\r
+{\r
+ impl_ = other.impl_.fetch_and_store(nullptr);\r
+}\r
layer& layer::operator=(layer&& other)\r
{\r
- impl_ = std::move(other.impl_);\r
+ impl_ = other.impl_.fetch_and_store(nullptr);\r
return *this;\r
}\r
void layer::swap(layer& other)\r
{\r
- impl_->swap(*other.impl_);\r
+ impl_ = other.impl_.compare_and_swap(impl_, other.impl_);\r
+ tbb::spin_mutex::scoped_lock lock(other.impl_->printer_mutex_);\r
+ std::swap(impl_->index_, other.impl_->index_);\r
+ std::swap(impl_->parent_printer_, other.impl_->parent_printer_);\r
}\r
void layer::load(const safe_ptr<frame_producer>& frame_producer, bool play_on_load){return impl_->load(frame_producer, play_on_load);} \r
void layer::preview(const safe_ptr<frame_producer>& frame_producer){return impl_->preview(frame_producer);} \r
{\r
public:\r
layer(int index, const printer& parent_printer = nullptr); // nothrow\r
+ ~layer();\r
layer(layer&& other); // nothrow\r
layer& operator=(layer&& other); // nothrow\r
\r
std::wstring print() const;\r
private:\r
struct implementation;\r
- std::shared_ptr<implementation> impl_;\r
+ tbb::atomic<implementation*> impl_;\r
};\r
\r
}}
\ No newline at end of file
, dest_producer_(dest)\r
, source_producer_(frame_producer::empty())\r
{\r
+ dest_producer_->set_parent_printer(std::bind(&implementation::dest_print, this));\r
frame_buffer_.push_back(draw_frame::empty());\r
}\r
\r
\r
virtual void set_parent_printer(const printer& parent_printer) \r
{\r
- dest_producer_->set_parent_printer(std::bind(&implementation::print, this));\r
parent_printer_ = parent_printer;\r
}\r
\r
void set_leading_producer(const safe_ptr<frame_producer>& producer)\r
{\r
source_producer_ = producer;\r
+ source_producer_->set_parent_printer(std::bind(&implementation::source_print, this));\r
}\r
\r
safe_ptr<draw_frame> receive()\r
\r
std::wstring print() const\r
{\r
- return (parent_printer_ ? parent_printer_() + L"/" : L"") + L"transition[length:" + boost::lexical_cast<std::wstring>(info_.duration) + L"]";\r
+ return (parent_printer_ ? parent_printer_() + L"/" : L"") + L"transition[" + info_.name() + L":" + boost::lexical_cast<std::wstring>(info_.duration) + L"]";\r
}\r
+\r
+ std::wstring source_print() const { return print() + L"/source";}\r
+ std::wstring dest_print() const { return print() + L"/dest";}\r
};\r
\r
transition_producer::transition_producer(transition_producer&& other) : impl_(std::move(other.impl_)){}\r
struct transition_info\r
{\r
transition_info() : type(transition::cut), duration(0), direction(transition_direction::from_left){}\r
+\r
+ std::wstring name() const\r
+ {\r
+ switch(type)\r
+ {\r
+ case transition::cut: return L"cut";\r
+ case transition::mix: return L"mix";\r
+ case transition::push: return L"push";\r
+ case transition::slide: return L"slide";\r
+ case transition::wipe: return L"wipe";\r
+ default: return L"";\r
+ }\r
+ }\r
\r
size_t duration;\r
transition_direction::type direction;\r
#include <common/exception/exceptions.h>\r
#include <common/concurrency/executor.h>\r
#include <common/diagnostics/graph.h>\r
+#include <common/utility/assert.h>\r
#include <common/utility/timer.h>\r
#include <common/gl/gl_check.h>\r
\r
\r
struct frame_mixer_device::implementation : boost::noncopyable\r
{ \r
+ const printer parent_printer_;\r
const video_format_desc format_desc_;\r
\r
safe_ptr<diagnostics::graph> graph_;\r
\r
executor executor_;\r
public:\r
- implementation(const video_format_desc& format_desc, const output_func& output) \r
- : format_desc_(format_desc)\r
+ implementation(const printer& parent_printer, const video_format_desc& format_desc, const output_func& output) \r
+ : parent_printer_(parent_printer)\r
+ , format_desc_(format_desc)\r
, graph_(diagnostics::create_graph(narrow(print())))\r
, image_mixer_(format_desc)\r
, output_(output)\r
- , executor_(L"frame_mixer_device")\r
+ , executor_(print())\r
{\r
graph_->guide("frame-time", 0.5f); \r
graph_->set_color("frame-time", diagnostics::color(1.0f, 0.0f, 0.0f));\r
\r
~implementation()\r
{\r
- CASPAR_LOG(info) << print() << L" Shutting down."; \r
+ executor_.clear();\r
}\r
\r
void send(const std::vector<safe_ptr<draw_frame>>& frames)\r
\r
std::wstring print() const\r
{\r
- return L"Video/Audio Mixer [" + format_desc_.name + L"]";\r
+ return (parent_printer_ ? parent_printer_() + L"/" : L"") + L"mixer";\r
}\r
};\r
\r
-frame_mixer_device::frame_mixer_device(const video_format_desc& format_desc, const output_func& output) : impl_(new implementation(format_desc, output)){}\r
+frame_mixer_device::frame_mixer_device(const printer& parent_printer, const video_format_desc& format_desc, const output_func& output) : impl_(new implementation(parent_printer, format_desc, output)){}\r
frame_mixer_device::frame_mixer_device(frame_mixer_device&& other) : impl_(std::move(other.impl_)){}\r
void frame_mixer_device::send(const std::vector<safe_ptr<draw_frame>>& frames){impl_->send(frames);}\r
const video_format_desc& frame_mixer_device::get_video_format_desc() const { return impl_->format_desc_; }\r
\r
#include "frame_factory.h"\r
\r
+#include "image/image_mixer.h"\r
+#include "audio/audio_mixer.h"\r
+\r
#include "frame/write_frame.h"\r
#include "frame/pixel_format.h"\r
\r
#include <common/memory/safe_ptr.h>\r
+#include <common/utility/printable.h>\r
\r
#include <functional>\r
\r
-#include "image/image_mixer.h"\r
-#include "audio/audio_mixer.h"\r
-\r
namespace caspar { namespace core {\r
\r
struct video_format;\r
public:\r
typedef std::function<void(const safe_ptr<const read_frame>&)> output_func;\r
\r
- frame_mixer_device(const video_format_desc& format_desc, const output_func& output);\r
+ frame_mixer_device(const printer& parent_printer, const video_format_desc& format_desc, const output_func& output);\r
frame_mixer_device(frame_mixer_device&& other); // nothrow\r
\r
void send(const std::vector<safe_ptr<draw_frame>>& frames); // nothrow\r
</bluefish>-->\r
</consumers>\r
</channel>\r
- </channels>\r
+ <channel>\r
+ <videomode>PAL</videomode>\r
+ <consumers>\r
+ <ogl>\r
+ <device>1</device>\r
+ <stretch>uniform</stretch>\r
+ <windowed>true</windowed>\r
+ </ogl>\r
+ </consumers>\r
+ </channel>\r
+</channels>\r
<controllers>\r
<tcp>\r
<port>5250</port>\r
//CASPAR_LOG(debug) << L"Stopped TBB Worker Thread.";\r
}\r
};\r
+\r
+void setup_console_window()\r
+{ \r
+ auto hOut = GetStdHandle(STD_OUTPUT_HANDLE);\r
+\r
+ EnableMenuItem(GetSystemMenu(GetConsoleWindow(), FALSE), SC_CLOSE , MF_GRAYED);\r
+ DrawMenuBar(GetConsoleWindow());\r
+\r
+ auto coord = GetLargestConsoleWindowSize(hOut);\r
+ coord.X /= 2;\r
+\r
+ SetConsoleScreenBufferSize(hOut, coord);\r
+\r
+ SMALL_RECT DisplayArea = {0, 0, 0, 0};\r
+ DisplayArea.Right = coord.X-1;\r
+ DisplayArea.Bottom = coord.Y-1;\r
+ SetConsoleWindowInfo(hOut, TRUE, &DisplayArea);\r
+ \r
+ std::wstringstream str;\r
+ str << "CasparCG Server " << env::version();\r
+ SetConsoleTitle(str.str().c_str());\r
+\r
+ std::wcout << L"Copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\n" << std::endl;\r
+ std::wcout << L"Starting CasparCG Video Playout Server Ver: " << env::version() << std::endl;\r
+}\r
\r
int main(int argc, wchar_t* argv[])\r
{ \r
timeBeginPeriod(1);\r
\r
// Start caspar\r
- std::wstringstream str;\r
- str << "CasparCG " << env::version();\r
- SetConsoleTitle(str.str().c_str());\r
-\r
- std::wcout << L"Copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\n" << std::endl;\r
- std::wcout << L"Starting CasparCG Video Playout Server Ver: " << env::version() << std::endl;\r
\r
- EnableMenuItem(GetSystemMenu(GetConsoleWindow(), FALSE), SC_CLOSE , MF_GRAYED);\r
- DrawMenuBar(GetConsoleWindow());\r
- MoveWindow(GetConsoleWindow(), 800, 0, 800, 1000, true);\r
+ setup_console_window();\r
\r
#ifdef _DEBUG\r
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_CHECK_ALWAYS_DF );\r
<TargetName Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">$(SolutionName)</TargetName>\r
</PropertyGroup>\r
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
- <LinkIncremental>false</LinkIncremental>\r
+ <LinkIncremental>true</LinkIncremental>\r
</PropertyGroup>\r
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
<LinkIncremental>false</LinkIncremental>\r
</PropertyGroup>\r
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Amplify|Win32'">\r
- <LinkIncremental>false</LinkIncremental>\r
+ <LinkIncremental>true</LinkIncremental>\r
</PropertyGroup>\r
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">\r
- <LinkIncremental>false</LinkIncremental>\r
+ <LinkIncremental>true</LinkIncremental>\r
</PropertyGroup>\r
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
<PreBuildEvent>\r
<IgnoreSpecificDefaultLibraries>LIBC.LIB;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\r
<GenerateDebugInformation>true</GenerateDebugInformation>\r
<ProgramDatabaseFile>$(TargetDir)$(TargetName).pdb</ProgramDatabaseFile>\r
- <GenerateMapFile>true</GenerateMapFile>\r
+ <GenerateMapFile>false</GenerateMapFile>\r
<MapFileName>\r
</MapFileName>\r
<SubSystem>Console</SubSystem>\r
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
<IgnoreSpecificDefaultLibraries>LIBC.lib</IgnoreSpecificDefaultLibraries>\r
<GenerateDebugInformation>true</GenerateDebugInformation>\r
- <GenerateMapFile>true</GenerateMapFile>\r
+ <GenerateMapFile>false</GenerateMapFile>\r
<MapExports>true</MapExports>\r
<SubSystem>Console</SubSystem>\r
<OptimizeReferences>\r
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
<IgnoreSpecificDefaultLibraries>LIBC.lib</IgnoreSpecificDefaultLibraries>\r
<GenerateDebugInformation>true</GenerateDebugInformation>\r
- <GenerateMapFile>true</GenerateMapFile>\r
+ <GenerateMapFile>false</GenerateMapFile>\r
<MapExports>true</MapExports>\r
<SubSystem>Console</SubSystem>\r
<OptimizeReferences>\r
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
<IgnoreSpecificDefaultLibraries>LIBC.lib</IgnoreSpecificDefaultLibraries>\r
<GenerateDebugInformation>true</GenerateDebugInformation>\r
- <GenerateMapFile>true</GenerateMapFile>\r
+ <GenerateMapFile>false</GenerateMapFile>\r
<MapExports>true</MapExports>\r
<SubSystem>Console</SubSystem>\r
<OptimizeReferences>\r