1 #include "../StdAfx.h"
\r
3 #include "frame_producer_device.h"
\r
5 #include "../mixer/frame/draw_frame.h"
\r
6 #include "../mixer/frame_factory.h"
\r
10 #include <common/concurrency/executor.h>
\r
12 #include <boost/range/algorithm_ext/erase.hpp>
\r
13 #include <boost/lexical_cast.hpp>
\r
15 #include <tbb/parallel_for.h>
\r
16 #include <tbb/spin_mutex.h>
\r
21 namespace caspar { namespace core {
\r
23 struct frame_producer_device::implementation : boost::noncopyable
\r
25 std::array<layer, frame_producer_device::MAX_LAYER> layers_;
\r
27 tbb::spin_mutex output_mutex_;
\r
28 output_func output_;
\r
30 const safe_ptr<frame_factory> factory_;
\r
32 mutable executor executor_;
\r
34 implementation(const safe_ptr<frame_factory>& factory, const output_func& output)
\r
39 executor_.begin_invoke([=]{tick();});
\r
44 CASPAR_LOG(info) << "Shutting down producer-device.";
\r
49 auto frames = draw();
\r
52 tbb::spin_mutex::scoped_lock lock(output_mutex_);
\r
56 executor_.begin_invoke([=]{tick();});
\r
59 std::vector<safe_ptr<draw_frame>> draw()
\r
61 std::vector<safe_ptr<draw_frame>> frames(layers_.size(), draw_frame::empty());
\r
62 tbb::parallel_for(tbb::blocked_range<size_t>(0, frames.size(), 1), // Use grain-size = 1.
\r
63 [&](const tbb::blocked_range<size_t>& r)
\r
65 for(size_t i = r.begin(); i != r.end(); ++i)
\r
67 frames[i] = layers_[i].receive();
\r
68 frames[i]->set_layer_index(i);
\r
71 boost::range::remove_erase(frames, draw_frame::empty());
\r
75 void load(size_t index, const safe_ptr<frame_producer>& producer, bool play_on_load)
\r
77 producer->initialize(factory_);
\r
78 executor_.invoke([&]
\r
80 layers_.at(index).load(producer, play_on_load);
\r
84 void preview(size_t index, const safe_ptr<frame_producer>& producer)
\r
86 producer->initialize(factory_);
\r
87 executor_.invoke([&]
\r
89 layers_.at(index).preview(producer);
\r
93 void pause(size_t index)
\r
95 executor_.invoke([&]
\r
97 layers_.at(index).pause();
\r
101 void play(size_t index)
\r
103 executor_.invoke([&]
\r
105 layers_.at(index).play();
\r
109 void stop(size_t index)
\r
111 executor_.invoke([&]
\r
113 layers_.at(index).stop();
\r
117 void clear(size_t index)
\r
119 executor_.invoke([&]
\r
121 layers_.at(index) = std::move(layer());
\r
127 executor_.invoke([&]
\r
129 for(auto it = layers_.begin(); it != layers_.end(); ++it)
\r
130 *it = std::move(layer());
\r
134 void swap_layer(size_t index, size_t other_index)
\r
136 executor_.invoke([&]
\r
138 layers_.at(index).swap(layers_[other_index]);
\r
142 void swap_layer(size_t index, size_t other_index, frame_producer_device& other)
\r
144 executor_.invoke([&]
\r
146 layers_.at(index).swap(other.impl_->layers_.at(other_index));
\r
150 void swap_output(frame_producer_device& other)
\r
152 if(other.impl_.get() == this) // Avoid deadlock.
\r
155 tbb::spin_mutex::scoped_lock lock1(output_mutex_);
\r
156 tbb::spin_mutex::scoped_lock lock2(other.impl_->output_mutex_);
\r
157 output_.swap(other.impl_->output_);
\r
160 boost::unique_future<safe_ptr<frame_producer>> foreground(size_t index) const
\r
162 return executor_.begin_invoke([=]() -> safe_ptr<frame_producer>
\r
164 return layers_.at(index).foreground();
\r
169 frame_producer_device::frame_producer_device(const safe_ptr<frame_factory>& factory, const output_func& output) : impl_(new implementation(factory, output)){}
\r
170 frame_producer_device::frame_producer_device(frame_producer_device&& other) : impl_(std::move(other.impl_)){}
\r
171 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
172 void frame_producer_device::preview(size_t index, const safe_ptr<frame_producer>& producer){impl_->preview(index, producer);}
\r
173 void frame_producer_device::pause(size_t index){impl_->pause(index);}
\r
174 void frame_producer_device::play(size_t index){impl_->play(index);}
\r
175 void frame_producer_device::stop(size_t index){impl_->stop(index);}
\r
176 void frame_producer_device::clear(size_t index){impl_->clear(index);}
\r
177 void frame_producer_device::clear(){impl_->clear();}
\r
178 void frame_producer_device::swap_layer(size_t index, size_t other_index){impl_->swap_layer(index, other_index);}
\r
179 void frame_producer_device::swap_layer(size_t index, size_t other_index, frame_producer_device& other){impl_->swap_layer(index, other_index, other);}
\r
180 void frame_producer_device::swap_output(frame_producer_device& other){impl_->swap_output(other);}
\r
181 boost::unique_future<safe_ptr<frame_producer>> frame_producer_device::foreground(size_t index) const{ return impl_->foreground(index);}
\r