, mixer_(new mixer::frame_mixer_device(format_desc))\r
, producer_(new frame_producer_device(format_desc_)) \r
, mixer_connection_(mixer_->connect([=](const safe_ptr<const read_frame>& frame){consumer_->send(frame);}))\r
- , producer_connection_(producer_->connect([=](const std::vector<safe_ptr<basic_frame>>& frames){mixer_->send(frames);}))\r
+ , producer_connection_(producer_->connect([=](const std::map<int, safe_ptr<basic_frame>>& frames){mixer_->send(frames);}))\r
{}\r
\r
std::wstring print() const\r
producer_ = make_safe<frame_producer_device>(format_desc_);\r
\r
mixer_connection_ = mixer_->connect([=](const safe_ptr<const read_frame>& frame){consumer_->send(frame);});\r
- producer_connection_ = producer_->connect([=](const std::vector<safe_ptr<basic_frame>>& frames){mixer_->send(frames);});\r
+ producer_connection_ = producer_->connect([=](const std::map<int, safe_ptr<basic_frame>>& frames){mixer_->send(frames);});\r
}\r
};\r
\r
\r
image_transform image_transform_; \r
audio_transform audio_transform_;\r
-\r
- int index_;\r
-\r
+ \r
public:\r
implementation(const std::vector<safe_ptr<basic_frame>>& frames) \r
- : frames_(frames)\r
- , index_(std::numeric_limits<int>::min()) {}\r
+ : frames_(frames) {}\r
implementation(std::vector<safe_ptr<basic_frame>>&& frames) \r
- : frames_(std::move(frames))\r
- , index_(std::numeric_limits<int>::min()) {}\r
+ : frames_(std::move(frames)){}\r
\r
void accept(const basic_frame& self, frame_visitor& visitor)\r
{\r
frames.push_back(my_frame2);\r
return make_safe<basic_frame>(frames);\r
}\r
-\r
-void basic_frame::set_layer_index(int index) { impl_->index_ = index; }\r
-int basic_frame::get_layer_index() const { return impl_->index_; }\r
\r
}}
\ No newline at end of file
}\r
\r
virtual void accept(frame_visitor& visitor);\r
-\r
- void set_layer_index(int index);\r
- int get_layer_index() const;\r
private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
\r
#include <tbb/parallel_for.h>\r
#include <tbb/mutex.h>\r
+#include <tbb/combinable.h>\r
\r
#include <array>\r
#include <memory>\r
executor_.begin_invoke([=]{tick();});\r
}\r
\r
- std::vector<safe_ptr<basic_frame>> draw()\r
+ std::map<int, safe_ptr<basic_frame>> draw()\r
{ \r
- std::vector<safe_ptr<basic_frame>> frames(layers_.size(), basic_frame::empty());\r
- tbb::parallel_for(tbb::blocked_range<size_t>(0, frames.size(), 1), [&](const tbb::blocked_range<size_t>& r)\r
+ tbb::combinable<std::map<int, safe_ptr<basic_frame>>> frames;\r
+\r
+ tbb::parallel_for_each(layers_.begin(), layers_.end(), [&](decltype(*layers_.begin())& pair)\r
{\r
- auto it = layers_.begin();\r
- std::advance(it, r.begin());\r
- for(size_t i = r.begin(); i != r.end(); ++i, ++it)\r
- {\r
- frames[i] = it->second.receive();\r
- frames[i]->set_layer_index(it->first);\r
- }\r
- }); \r
- return frames;\r
+ auto frame = pair.second.receive();\r
+ if(frame != basic_frame::empty() && frame != basic_frame::eof())\r
+ frames.local()[pair.first] = frame; \r
+ });\r
+\r
+ std::map<int, safe_ptr<basic_frame>> result;\r
+ frames.combine_each([&](const std::map<int, safe_ptr<basic_frame>>& map)\r
+ {\r
+ result.insert(map.begin(), map.end());\r
+ });\r
+\r
+ return result;\r
}\r
\r
void load(int index, const safe_ptr<frame_producer>& producer, bool preview)\r
\r
auto func = [&]\r
{\r
- layers_[index].swap(other.impl_->layers_.at(other_index)); \r
+ layers_[index].swap(other.impl_->layers_[other_index]); \r
\r
CASPAR_LOG(info) << print() << L" Swapped layer " << index << L" with " << other.impl_->print() << L" layer " << other_index << L"."; \r
};\r
\r
auto func = [&]\r
{\r
- auto sel_first = [](const decltype(*layers_.begin())& pair){return pair.first;};\r
+ auto sel_first = [](const std::pair<int, layer>& pair){return pair.first;};\r
\r
std::set<int> indices;\r
std::transform(layers_.begin(), layers_.end(), std::inserter(indices, indices.begin()), sel_first);\r
executor_.invoke([&]{other.impl_->executor_.invoke(func);});\r
}\r
\r
- boost::unique_future<safe_ptr<frame_producer>> foreground(int index) const\r
+ boost::unique_future<safe_ptr<frame_producer>> foreground(int index)\r
{\r
- return executor_.begin_invoke([=]() mutable -> safe_ptr<frame_producer>\r
+ return executor_.begin_invoke([=]\r
{ \r
- auto it = layers_.find(index);\r
- return it != layers_.end() ? it->second.foreground() : frame_producer::empty();\r
+ return layers_[index].foreground();\r
});\r
}\r
\r
void frame_producer_device::clear(){impl_->clear();}\r
void frame_producer_device::swap_layer(int index, size_t other_index){impl_->swap_layer(index, other_index);}\r
void frame_producer_device::swap_layer(int index, size_t other_index, frame_producer_device& other){impl_->swap_layer(index, other_index, other);}\r
-boost::unique_future<safe_ptr<frame_producer>> frame_producer_device::foreground(size_t index) const{ return impl_->foreground(index);}\r
+boost::unique_future<safe_ptr<frame_producer>> frame_producer_device::foreground(size_t index) { return impl_->foreground(index);}\r
}}
\ No newline at end of file
class frame_producer_device : boost::noncopyable\r
{\r
public:\r
- typedef boost::signals2::signal<void(const std::vector<safe_ptr<basic_frame>>&)> output_t;\r
+ typedef boost::signals2::signal<void(const std::map<int, safe_ptr<basic_frame>>&)> output_t;\r
\r
boost::signals2::connection connect(const output_t::slot_type& subscriber);\r
\r
void clear(); \r
void swap_layer(int index, size_t other_index);\r
void swap_layer(int index, size_t other_index, frame_producer_device& other);\r
- boost::unique_future<safe_ptr<frame_producer>> foreground(size_t index) const;\r
+ boost::unique_future<safe_ptr<frame_producer>> foreground(size_t index);\r
\r
private:\r
struct implementation;\r
\r
namespace caspar { namespace core {\r
\r
-struct layer::implementation : boost::noncopyable\r
+struct layer::implementation\r
{ \r
safe_ptr<frame_producer> foreground_;\r
safe_ptr<frame_producer> background_;\r
, last_frame_(basic_frame::empty())\r
, is_paused_(false){}\r
\r
- void pause() \r
- {\r
- is_paused_ = true; \r
- }\r
-\r
- void resume()\r
- {\r
- is_paused_ = false;\r
- }\r
+ void pause(){is_paused_ = true;}\r
+ void resume(){is_paused_ = false;}\r
\r
void load(const safe_ptr<frame_producer>& producer, bool preview)\r
{ \r
impl_ = std::move(other.impl_);\r
return *this;\r
}\r
+layer::layer(const layer& other) : impl_(new implementation(*other.impl_)){}\r
+layer& layer::operator=(const layer& other)\r
+{\r
+ layer tmp(other);\r
+ tmp.swap(*this);\r
+ return *this;\r
+}\r
void layer::swap(layer& other)\r
{ \r
impl_.swap(other.impl_);\r
class frame_producer;\r
class basic_frame;\r
\r
-class layer : boost::noncopyable\r
+class layer //: boost::noncopyable\r
{\r
public:\r
layer(); // nothrow\r
layer(layer&& other); // nothrow\r
layer& operator=(layer&& other); // nothrow\r
+ layer(const layer&);\r
+ layer& operator=(const layer&);\r
\r
void swap(layer& other); // nothrow \r
\r
return output_.connect(subscriber);\r
}\r
\r
- boost::unique_future<safe_ptr<const host_buffer>> mix_image(std::vector<safe_ptr<core::basic_frame>> frames)\r
- {\r
- frames.erase(std::remove(frames.begin(), frames.end(), core::basic_frame::empty()), frames.end());\r
- frames.erase(std::remove(frames.begin(), frames.end(), core::basic_frame::eof()), frames.end());\r
- \r
+ boost::unique_future<safe_ptr<const host_buffer>> mix_image(std::map<int, safe_ptr<core::basic_frame>> frames)\r
+ { \r
auto& root_image_transform = boost::fusion::at_key<core::image_transform>(root_transforms_);\r
auto& image_transforms = boost::fusion::at_key<core::image_transform>(transforms_);\r
\r
{\r
if(format_desc_.mode != core::video_mode::progressive)\r
{\r
- auto frame1 = make_safe<core::basic_frame>(frame);\r
- auto frame2 = make_safe<core::basic_frame>(frame);\r
+ auto frame1 = make_safe<core::basic_frame>(frame.second);\r
+ auto frame2 = make_safe<core::basic_frame>(frame.second);\r
\r
- frame1->get_image_transform() = root_image_transform.fetch_and_tick(1)*image_transforms[frame->get_layer_index()].fetch_and_tick(1);\r
- frame2->get_image_transform() = root_image_transform.fetch_and_tick(1)*image_transforms[frame->get_layer_index()].fetch_and_tick(1);\r
+ frame1->get_image_transform() = root_image_transform.fetch_and_tick(1)*image_transforms[frame.first].fetch_and_tick(1);\r
+ frame2->get_image_transform() = root_image_transform.fetch_and_tick(1)*image_transforms[frame.first].fetch_and_tick(1);\r
\r
if(frame1->get_image_transform() != frame2->get_image_transform())\r
core::basic_frame::interlace(frame1, frame2, format_desc_.mode)->accept(image_mixer_);\r
}\r
else\r
{\r
- auto frame1 = make_safe<core::basic_frame>(frame);\r
- frame1->get_image_transform() = root_image_transform.fetch_and_tick(1)*image_transforms[frame->get_layer_index()].fetch_and_tick(1);\r
+ auto frame1 = make_safe<core::basic_frame>(frame.second);\r
+ frame1->get_image_transform() = root_image_transform.fetch_and_tick(1)*image_transforms[frame.first].fetch_and_tick(1);\r
frame1->accept(image_mixer_);\r
}\r
}\r
return std::move(image);\r
}\r
\r
- std::vector<short> mix_audio(const std::vector<safe_ptr<core::basic_frame>>& frames)\r
+ std::vector<short> mix_audio(const std::map<int, safe_ptr<core::basic_frame>>& frames)\r
{\r
auto& root_audio_transform = boost::fusion::at_key<core::audio_transform>(root_transforms_);\r
auto& audio_transforms = boost::fusion::at_key<core::audio_transform>(transforms_);\r
{\r
int num = format_desc_.mode == core::video_mode::progressive ? 1 : 2;\r
\r
- auto frame1 = make_safe<core::basic_frame>(frame);\r
- frame1->get_audio_transform() = root_audio_transform.fetch_and_tick(num)*audio_transforms[frame->get_layer_index()].fetch_and_tick(num);\r
+ auto frame1 = make_safe<core::basic_frame>(frame.second);\r
+ frame1->get_audio_transform() = root_audio_transform.fetch_and_tick(num)*audio_transforms[frame.first].fetch_and_tick(num);\r
frame1->accept(audio_mixer_);\r
}\r
audio_mixer_.end_pass();\r
return audio;\r
}\r
\r
- void send(const std::vector<safe_ptr<core::basic_frame>>& frames)\r
+ void send(const std::map<int, safe_ptr<core::basic_frame>>& frames)\r
{ \r
executor_.begin_invoke([=]\r
{ \r
frame_mixer_device::frame_mixer_device(const core::video_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
frame_mixer_device::frame_mixer_device(frame_mixer_device&& other) : impl_(std::move(other.impl_)){}\r
boost::signals2::connection frame_mixer_device::connect(const output_t::slot_type& subscriber){return impl_->connect(subscriber);}\r
-void frame_mixer_device::send(const std::vector<safe_ptr<core::basic_frame>>& frames){impl_->send(frames);}\r
+void frame_mixer_device::send(const std::map<int, safe_ptr<core::basic_frame>>& frames){impl_->send(frames);}\r
const core::video_format_desc& frame_mixer_device::get_video_format_desc() const { return impl_->format_desc_; }\r
safe_ptr<core::write_frame> frame_mixer_device::create_frame(void* tag, const core::pixel_format_desc& desc){ return impl_->create_frame(tag, desc); } \r
safe_ptr<core::write_frame> frame_mixer_device::create_frame(void* tag, size_t width, size_t height, core::pixel_format::type pix_fmt)\r
frame_mixer_device(const core::video_format_desc& format_desc);\r
frame_mixer_device(frame_mixer_device&& other); // nothrow\r
\r
- void send(const std::vector<safe_ptr<core::basic_frame>>& frames); // nothrow\r
+ void send(const std::map<int, safe_ptr<core::basic_frame>>& frames); // nothrow\r
\r
safe_ptr<core::write_frame> create_frame(void* tag, const core::pixel_format_desc& desc); \r
safe_ptr<core::write_frame> create_frame(void* tag, size_t width, size_t height, core::pixel_format::type pix_fmt = core::pixel_format::bgra); \r
safe_ptr<core::frame_factory> factory = channel->mixer();\r
auto producer = make_safe<cg_producer>(factory); \r
channel->producer()->load(render_layer, producer, true); \r
+ channel->producer()->play(render_layer);\r
return producer;\r
}\r
}\r
is_running = wcmd != L"exit" && wcmd != L"q";\r
if(wcmd.substr(0, 2) == L"12")\r
{\r
- wcmd = L"LOADBG 1-1 A LOOP AUTOPLAY\r\n";\r
+ wcmd = L"LOADBG 1-1 A LOOP \r\nPLAY 1-1\r\n";\r
amcp.Parse(wcmd.c_str(), wcmd.length(), dummy);\r
- wcmd = L"LOADBG 1-2 DV LOOP AUTOPLAY\r\n";\r
+ wcmd = L"LOADBG 1-2 DV LOOP AUTOPLAY\r\nnPLAY 1-1\r\n";\r
amcp.Parse(wcmd.c_str(), wcmd.length(), dummy);\r
wcmd = L"MIXER 1-1 VIDEO FIX_RECT 0.0 0.0 0.5 0.5\r\n";\r
amcp.Parse(wcmd.c_str(), wcmd.length(), dummy);\r
if(wcmd.substr(0, 2) == L"11")\r
wcmd = L"MIXER 1-1 VIDEO FIX_RECT 0.4 0.4 0.5 0.5";\r
else if(wcmd.substr(0, 1) == L"1")\r
- wcmd = L"LOADBG 1-1 " + wcmd.substr(1, wcmd.length()-1) + L" SLIDE 100 LOOP AUTOPLAY";\r
+ wcmd = L"LOADBG 1-1 " + wcmd.substr(1, wcmd.length()-1) + L" SLIDE 100 LOOP \r\nPLAY 1-1";\r
else if(wcmd.substr(0, 1) == L"2")\r
- wcmd = L"LOADBG 1-1 " + wcmd.substr(1, wcmd.length()-1) + L" PUSH 100 LOOP AUTOPLAY";\r
+ wcmd = L"LOADBG 1-1 " + wcmd.substr(1, wcmd.length()-1) + L" PUSH 100 LOOP \r\nPLAY 1-1";\r
else if(wcmd.substr(0, 1) == L"3")\r
- wcmd = L"LOADBG 1-1 " + wcmd.substr(1, wcmd.length()-1) + L" MIX 100 LOOP AUTOPLAY";\r
+ wcmd = L"LOADBG 1-1 " + wcmd.substr(1, wcmd.length()-1) + L" MIX 100 LOOP \r\nPLAY 1-1";\r
else if(wcmd.substr(0, 1) == L"4")\r
- wcmd = L"LOADBG 1-1 " + wcmd.substr(1, wcmd.length()-1) + L" WIPE 100 LOOP AUTOPLAY";\r
+ wcmd = L"LOADBG 1-1 " + wcmd.substr(1, wcmd.length()-1) + L" WIPE 100 LOOP \r\nPLAY 1-1";\r
else if(wcmd.substr(0, 1) == L"5")\r
- wcmd = L"LOADBG 1-2 " + wcmd.substr(1, wcmd.length()-1) + L" LOOP AUTOPLAY";\r
+ wcmd = L"LOADBG 1-2 " + wcmd.substr(1, wcmd.length()-1) + L" LOOP \r\nPLAY 1-2";\r
else if(wcmd.substr(0, 1) == L"6")\r
wcmd = L"CG 1-2 ADD 1 BBTELEFONARE 1";\r
else if(wcmd.substr(0, 1) == L"7")\r