tbb::concurrent_bounded_queue<std::function<void()>> execution_queue_;\r
public:\r
\r
- explicit executor(const std::wstring& name) : name_(narrow(name))\r
+ explicit executor(const std::wstring& name, bool auto_start = false) : name_(narrow(name))\r
{\r
is_running_ = false;\r
+ if(auto_start)\r
+ start();\r
}\r
\r
virtual ~executor()\r
std::vector<const producer_factory_t> p_factories;\r
tbb::spin_rw_mutex p_factories_mutex;\r
\r
-safe_ptr<basic_frame> receive(safe_ptr<frame_producer>& producer)\r
-{\r
+safe_ptr<basic_frame> receive_and_follow(safe_ptr<frame_producer>& producer)\r
+{ \r
+ if(producer == frame_producer::empty())\r
+ return basic_frame::eof();\r
+\r
auto frame = basic_frame::eof();\r
try\r
{\r
{\r
try\r
{\r
+ // Producer will be removed since frame == basic_frame::eof.\r
CASPAR_LOG_CURRENT_EXCEPTION();\r
CASPAR_LOG(warning) << producer->print() << " Failed to receive frame. Removing producer.";\r
}\r
if(frame == basic_frame::eof())\r
{\r
auto following = producer->get_following_producer();\r
- if(following == frame_producer::empty())\r
- producer = frame_producer::eof();\r
- else\r
- {\r
- following->set_leading_producer(producer);\r
- producer = std::move(following);\r
- return receive(producer);\r
- }\r
+ following->set_leading_producer(producer);\r
+ producer = std::move(following); \r
+\r
+ return receive_and_follow(producer);\r
}\r
return frame;\r
}\r
virtual ~frame_producer(){} \r
\r
virtual safe_ptr<basic_frame> receive() = 0;\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>& /*producer*/) {} // nothrow\r
+ virtual std::wstring print() const = 0; // nothrow\r
+\r
virtual void param(const std::wstring&){}\r
\r
- virtual std::wstring print() const = 0;\r
- \r
- static const safe_ptr<frame_producer>& empty() // nothrow\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>& /*producer*/) {} // nothrow\r
+ \r
+ static const safe_ptr<frame_producer>& empty() // nothrow\r
{\r
struct empty_frame_producer : public frame_producer\r
{\r
static safe_ptr<frame_producer> producer = make_safe<empty_frame_producer>();\r
return producer;\r
} \r
-\r
- static const safe_ptr<frame_producer>& eof() // nothrow\r
- {\r
- struct eof_frame_producer : public frame_producer\r
- {\r
- virtual safe_ptr<basic_frame> receive(){return basic_frame::eof();}\r
- virtual void set_frame_factory(const safe_ptr<frame_factory>&){}\r
- virtual std::wstring print() const { return L"eof";}\r
- };\r
- static safe_ptr<frame_producer> producer = make_safe<eof_frame_producer>();\r
- return producer;\r
- }\r
};\r
\r
-safe_ptr<basic_frame> receive(safe_ptr<frame_producer>& producer);\r
+safe_ptr<basic_frame> receive_and_follow(safe_ptr<frame_producer>& producer);\r
\r
std::wostream& operator<<(std::wostream& out, const frame_producer& producer);\r
std::wostream& operator<<(std::wostream& out, const safe_ptr<const frame_producer>& producer);\r
if(is_paused_) \r
last_frame_->get_audio_transform().set_has_audio(false); \r
else\r
- last_frame_ = core::receive(foreground_);\r
+ last_frame_ = receive_and_follow(foreground_);\r
\r
return last_frame_;\r
}\r
}\r
void layer::swap(layer& other)\r
{ \r
- std::swap(impl_->foreground_, other.impl_->foreground_);\r
- std::swap(impl_->background_, other.impl_->background_);\r
- std::swap(impl_->last_frame_, other.impl_->last_frame_);\r
+ impl_->foreground_.swap(other.impl_->foreground_);\r
+ impl_->background_.swap(other.impl_->background_);\r
+ impl_->last_frame_.swap(other.impl_->last_frame_);\r
std::swap(impl_->is_paused_ , other.impl_->is_paused_ );\r
}\r
void layer::load(const safe_ptr<frame_producer>& frame_producer, bool play_on_load, bool preview){return impl_->load(frame_producer, play_on_load, preview);} \r
struct transition_producer : public frame_producer\r
{ \r
const video_format_desc format_desc_;\r
- unsigned short current_frame_;\r
+ uint32_t current_frame_;\r
\r
const transition_info info_;\r
\r
safe_ptr<frame_producer> dest_producer_;\r
safe_ptr<frame_producer> source_producer_;\r
- \r
- std::vector<safe_ptr<basic_frame>> frame_buffer_;\r
- \r
+ \r
transition_producer(const video_format_desc& format_desc, const safe_ptr<frame_producer>& dest, const transition_info& info) \r
: format_desc_(format_desc)\r
, current_frame_(0)\r
, info_(info)\r
, dest_producer_(dest)\r
- , source_producer_(frame_producer::empty())\r
- {\r
- frame_buffer_.push_back(basic_frame::empty());\r
- }\r
+ , source_producer_(frame_producer::empty()){}\r
\r
safe_ptr<frame_producer> get_following_producer() const\r
{\r
\r
tbb::parallel_invoke\r
(\r
- [&]{dest = core::receive(dest_producer_);},\r
- [&]{source = core::receive(source_producer_);}\r
+ [&]{dest = receive_and_follow(dest_producer_);},\r
+ [&]{source = receive_and_follow(source_producer_);}\r
);\r
\r
return compose(dest, source);\r
return basic_frame::eof();\r
\r
if(info_.type == transition::cut) \r
- return src_frame != basic_frame::eof() ? src_frame : basic_frame::empty();\r
+ return src_frame;\r
\r
double delta1 = info_.tweener(current_frame_*2-1, 0.0, 1.0, info_.duration*2);\r
double delta2 = info_.tweener(current_frame_*2, 0.0, 1.0, info_.duration*2); \r
{\r
return L"transition[" + transition::print(info_.type) + 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
safe_ptr<frame_producer> create_transition_producer(const video_format_desc& format_desc, const safe_ptr<frame_producer>& destination, const transition_info& info)\r
explicit decklink_producer(const safe_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, size_t device_index)\r
: format_desc_(format_desc) \r
, device_index_(device_index)\r
- , executor_(L"decklink_producer")\r
+ , executor_(L"decklink_producer", true)\r
{\r
- executor_.start();\r
executor_.invoke([=]\r
{\r
input_.reset(new decklink_input(format_desc_, device_index_, frame_factory));\r