\r
#include <core/consumer/frame/read_frame.h>\r
\r
-#include <common/concurrency/executor.h>\r
+#include <common/concurrency/com_context.h>\r
#include <common/diagnostics/graph.h>\r
#include <common/exception/exceptions.h>\r
#include <common/memory/memcpy.h>\r
, latency(default_latency){}\r
};\r
\r
-struct decklink_output : public IDeckLinkVideoOutputCallback, public IDeckLinkAudioOutputCallback, boost::noncopyable\r
+struct decklink_consumer : public IDeckLinkVideoOutputCallback, public IDeckLinkAudioOutputCallback, boost::noncopyable\r
{ \r
static const size_t BUFFER_SIZE = 4;\r
- \r
- struct co_init\r
- {\r
- co_init(){CoInitialize(nullptr);}\r
- ~co_init(){CoUninitialize();}\r
- } co_;\r
- \r
+ \r
const configuration config_;\r
\r
CComPtr<IDeckLink> decklink_;\r
boost::timer tick_timer_;\r
\r
public:\r
- decklink_output(const configuration& config, const core::video_format_desc& format_desc) \r
+ decklink_consumer(const configuration& config, const core::video_format_desc& format_desc) \r
: config_(config)\r
, decklink_(get_device(config.device_index))\r
, output_(decklink_)\r
CASPAR_LOG(info) << print() << L" Successfully initialized for " << format_desc_.name; \r
}\r
\r
- ~decklink_output()\r
+ ~decklink_consumer()\r
{ \r
is_running_ = false;\r
video_frame_buffer_.clear();\r
}\r
};\r
\r
-struct decklink_consumer : public core::frame_consumer\r
+struct decklink_consumer_proxy : public core::frame_consumer\r
{\r
- std::unique_ptr<decklink_output> input_;\r
- configuration config_;\r
+ const configuration config_;\r
\r
- executor executor_;\r
+ com_context<decklink_consumer> context_;\r
public:\r
\r
- decklink_consumer(const configuration& config)\r
+ decklink_consumer_proxy(const configuration& config)\r
: config_(config)\r
- , executor_(L"decklink_consumer[" + boost::lexical_cast<std::wstring>(config.device_index) + L"]", true){}\r
-\r
- ~decklink_consumer()\r
- {\r
- executor_.invoke([&]\r
- {\r
- input_ = nullptr;\r
- });\r
- }\r
-\r
+ , context_(L"decklink_consumer[" + boost::lexical_cast<std::wstring>(config.device_index) + L"]"){}\r
+ \r
void initialize(const core::video_format_desc& format_desc)\r
{\r
- executor_.invoke([&]\r
- {\r
- input_.reset(new decklink_output(config_, format_desc));\r
- });\r
+ context_.reset([&]{return new decklink_consumer(config_, format_desc);});\r
}\r
\r
void send(const safe_ptr<const core::read_frame>& frame)\r
{\r
- input_->send(frame);\r
+ context_->send(frame);\r
}\r
\r
std::wstring print() const\r
{\r
- return input_->print();\r
+ return context_->print();\r
}\r
}; \r
\r
if(params.size() > 1)\r
config.device_index = lexical_cast_or_default<int>(params[1], config.device_index);\r
\r
- auto it = std::find(params.begin(), params.end(), L"INTERNAL_KEY");\r
- if(it != params.end())\r
+ if(std::find(params.begin(), params.end(), L"INTERNAL_KEY") != params.end())\r
config.keyer = internal_key;\r
- else\r
- {\r
- auto it = std::find(params.begin(), params.end(), L"EXTERNAL_KEY");\r
- if(it != params.end())\r
- config.keyer = external_key;\r
- }\r
+ else if(std::find(params.begin(), params.end(), L"EXTERNAL_KEY") != params.end())\r
+ config.keyer = external_key;\r
+ \r
+ if(std::find(params.begin(), params.end(), L"LOW_LATENCY") != params.end())\r
+ config.latency = low_latency;\r
+ else if(std::find(params.begin(), params.end(), L"NORMAL_LATENCY") != params.end())\r
+ config.latency = normal_latency;\r
\r
config.embedded_audio = std::find(params.begin(), params.end(), L"EMBEDDED_AUDIO") != params.end();\r
\r
- return make_safe<decklink_consumer>(config);\r
+ return make_safe<decklink_consumer_proxy>(config);\r
}\r
\r
-safe_ptr<core::frame_consumer> create_decklink_consumer_ptree(const boost::property_tree::ptree& ptree) \r
+safe_ptr<core::frame_consumer> create_decklink_consumer(const boost::property_tree::ptree& ptree) \r
{\r
configuration config;\r
\r
config.device_index = ptree.get("device", 0);\r
config.embedded_audio = ptree.get("embedded-audio", false);\r
\r
- return make_safe<decklink_consumer>(config);\r
+ return make_safe<decklink_consumer_proxy>(config);\r
}\r
\r
}
\ No newline at end of file
#include <core/producer/frame/write_frame.h>\r
\r
#include <common/env.h>\r
-#include <common/concurrency/executor.h>\r
+#include <common/concurrency/com_context.h>\r
#include <common/diagnostics/graph.h>\r
#include <common/memory/memcpy.h>\r
#include <common/memory/memclr.h>\r
namespace caspar {\r
\r
class flash_renderer\r
-{\r
- struct co_init\r
- {\r
- co_init(){CoInitialize(nullptr);}\r
- ~co_init(){CoUninitialize();}\r
- } co_;\r
- \r
+{ \r
const std::wstring filename_;\r
const core::video_format_desc format_desc_;\r
\r
- std::shared_ptr<core::frame_factory> frame_factory_;\r
+ const std::shared_ptr<core::frame_factory> frame_factory_;\r
\r
BYTE* bmp_data_; \r
std::shared_ptr<void> hdc_;\r
if(FAILED(CComObject<caspar::flash::FlashAxContainer>::CreateInstance(&ax_)))\r
BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Failed to create FlashAxContainer"));\r
\r
- ax_->set_print([this]{return L"";});\r
+ ax_->set_print([this]{return L"flash_renderer";});\r
\r
if(FAILED(ax_->CreateAxControl()))\r
BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Failed to Create FlashAxControl"));\r
return core::basic_frame::empty(); \r
\r
if(!has_underflow) \r
- timer_.tick(frame_time); \r
+ timer_.tick(frame_time); // This will block the thread.\r
else\r
graph_->add_tag("underflow");\r
\r
struct flash_producer : public core::frame_producer\r
{ \r
const std::wstring filename_; \r
+ const safe_ptr<core::frame_factory> frame_factory_;\r
+\r
tbb::atomic<int> fps_;\r
- bool underfow_;\r
\r
std::shared_ptr<diagnostics::graph> graph_;\r
\r
safe_ptr<core::basic_frame> tail_;\r
tbb::concurrent_bounded_queue<safe_ptr<core::basic_frame>> frame_buffer_;\r
-\r
- std::shared_ptr<flash_renderer> renderer_;\r
- safe_ptr<core::frame_factory> frame_factory_;\r
- const core::video_format_desc format_desc_;\r
- \r
- executor executor_;\r
- \r
+ \r
+ com_context<flash_renderer> context_; \r
public:\r
flash_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::wstring& filename) \r
: filename_(filename) \r
- , tail_(core::basic_frame::empty()) \r
, frame_factory_(frame_factory)\r
- , format_desc_(frame_factory->get_video_format_desc())\r
- , executor_(L"flash_producer", true)\r
+ , tail_(core::basic_frame::empty()) \r
+ , context_(L"flash_producer")\r
{ \r
if(!boost::filesystem::exists(filename))\r
BOOST_THROW_EXCEPTION(file_not_found() << boost::errinfo_file_name(narrow(filename))); \r
\r
- frame_buffer_.set_capacity(2);\r
+ fps_ = 0;\r
+\r
graph_ = diagnostics::create_graph([this]{return print();});\r
graph_->set_color("output-buffer", diagnostics::color(0.0f, 1.0f, 0.0f));\r
\r
- executor_.begin_invoke([=]\r
- {\r
- init_renderer();\r
- });\r
- \r
- fps_ = 0;\r
+ frame_buffer_.set_capacity(2);\r
+\r
+ initialize(); \r
}\r
\r
~flash_producer()\r
{\r
- executor_.clear();\r
frame_buffer_.clear();\r
- executor_.invoke([=]\r
- {\r
- renderer_ = nullptr;\r
- }); \r
}\r
\r
// frame_producer\r
virtual safe_ptr<core::basic_frame> receive()\r
{ \r
graph_->set_value("output-buffer", static_cast<float>(frame_buffer_.size())/static_cast<float>(frame_buffer_.capacity()));\r
- if(!frame_buffer_.try_pop(tail_))\r
- return tail_;\r
- \r
+\r
+ frame_buffer_.try_pop(tail_); \r
return tail_;\r
}\r
\r
virtual void param(const std::wstring& param) \r
{ \r
- executor_.begin_invoke([=]\r
+ context_.begin_invoke([=]\r
{\r
- if(!renderer_)\r
- init_renderer();\r
+ if(!context_.get())\r
+ initialize();\r
\r
try\r
{\r
- renderer_->param(param); \r
+ context_->param(param); \r
}\r
catch(...)\r
{\r
CASPAR_LOG_CURRENT_EXCEPTION();\r
- renderer_ = nullptr;\r
+ context_.reset(nullptr);\r
+ frame_buffer_.push(core::basic_frame::empty());\r
}\r
});\r
}\r
\r
// flash_producer\r
\r
- void init_renderer()\r
+ void initialize()\r
{\r
- renderer_.reset(new flash_renderer(safe_ptr<diagnostics::graph>(graph_), frame_factory_, filename_));\r
+ context_.reset([&]{return new flash_renderer(safe_ptr<diagnostics::graph>(graph_), frame_factory_, filename_);});\r
while(frame_buffer_.try_push(core::basic_frame::empty())){} \r
- executor_.begin_invoke([=]\r
- {\r
- render(renderer_);\r
- }); \r
+ render(context_.get());\r
}\r
\r
- void render(const std::shared_ptr<flash_renderer>& renderer)\r
- {\r
- if(renderer_ != renderer) // Make sure the recursive calls are only for a specific instance.\r
+ void render(const flash_renderer* renderer)\r
+ { \r
+ context_.begin_invoke([=]\r
{\r
- frame_buffer_.push(core::basic_frame::empty());\r
- return;\r
- }\r
+ if(context_.get() != renderer) // Since initialize will start a new recursive call make sure the recursive calls are only for a specific instance.\r
+ return;\r
\r
- try\r
- { \r
- auto frame = core::basic_frame::empty();\r
- if(abs(renderer_->fps()/2.0 - format_desc_.fps) < 0.1) //flash 50, format 50i\r
- {\r
- auto frame1 = renderer_->render_frame(frame_buffer_.size() < frame_buffer_.capacity());\r
- auto frame2 = renderer_->render_frame(frame_buffer_.size() < frame_buffer_.capacity());\r
- frame_buffer_.push(core::basic_frame::interlace(frame1, frame2, format_desc_.mode));\r
- frame = frame2;\r
- }\r
- else if(abs(renderer_->fps()- format_desc_.fps/2.0 ) < 0.1) //flash 25, format 50p\r
- {\r
- frame = renderer_->render_frame(frame_buffer_.size() < frame_buffer_.capacity());\r
- frame_buffer_.push(frame);\r
- frame_buffer_.push(frame);\r
+ try\r
+ { \r
+ const auto& format_desc = frame_factory_->get_video_format_desc();\r
+ auto frame = core::basic_frame::empty();\r
+ if(abs(context_->fps()/2.0 - format_desc.fps) < 0.1) // flash 50fps, format 50i\r
+ {\r
+ auto frame1 = context_->render_frame(frame_buffer_.size() < frame_buffer_.capacity());\r
+ auto frame2 = context_->render_frame(frame_buffer_.size() < frame_buffer_.capacity());\r
+ frame_buffer_.push(core::basic_frame::interlace(frame1, frame2, format_desc.mode));\r
+ frame = frame2;\r
+ }\r
+ else if(abs(context_->fps()- format_desc.fps/2.0 ) < 0.1) // flash 25fps, format 50p\r
+ {\r
+ frame = context_->render_frame(frame_buffer_.size() < frame_buffer_.capacity());\r
+ frame_buffer_.push(frame);\r
+ frame_buffer_.push(frame);\r
+ }\r
+ else //if(abs(renderer_->fps() - format_desc_.fps) < 0.1) // flash 25fps, format 50i or flash 50fps, format 50p\r
+ {\r
+ frame = context_->render_frame(frame_buffer_.size() < frame_buffer_.capacity());\r
+ frame_buffer_.push(frame);\r
+ }\r
+\r
+ graph_->set_value("output-buffer", static_cast<float>(frame_buffer_.size())/static_cast<float>(frame_buffer_.capacity())); \r
+ fps_.fetch_and_store(static_cast<int>(context_->fps()*100.0));\r
+\r
+ render(renderer);\r
}\r
- else //if(abs(renderer_->fps() - format_desc_.fps) < 0.1) // flash 25, format 50i or flash 50, format 50p\r
+ catch(...)\r
{\r
- frame = renderer_->render_frame(frame_buffer_.size() < frame_buffer_.capacity());\r
- frame_buffer_.push(frame);\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ context_.reset(nullptr);\r
+ frame_buffer_.push(core::basic_frame::empty());\r
}\r
-\r
- graph_->set_value("output-buffer", static_cast<float>(frame_buffer_.size())/static_cast<float>(frame_buffer_.capacity())); \r
- fps_.fetch_and_store(static_cast<int>(renderer_->fps()*100.0));\r
-\r
- executor_.begin_invoke([=]\r
- {\r
- render(renderer);\r
- }); \r
- }\r
- catch(...)\r
- {\r
- CASPAR_LOG_CURRENT_EXCEPTION();\r
- renderer_ = nullptr;\r
- }\r
+ });\r
}\r
};\r
\r