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
35 implementation(const safe_ptr<frame_factory>& factory, const output_func& output)
\r
39 for(size_t n = 0; n < layers_.size(); ++n)
\r
40 layers_[n] = layer(n);
\r
43 executor_.begin_invoke([=]{tick();});
\r
48 CASPAR_LOG(info) << "Shutting down producer-device.";
\r
55 tbb::spin_mutex::scoped_lock lock(output_mutex_);
\r
59 executor_.begin_invoke([=]{tick();});
\r
62 std::vector<safe_ptr<draw_frame>> draw()
\r
64 std::vector<safe_ptr<draw_frame>> frames(layers_.size(), draw_frame::empty());
\r
65 tbb::parallel_for(tbb::blocked_range<size_t>(0, frames.size(), 1), // Use grain-size = 1.
\r
66 [&](const tbb::blocked_range<size_t>& r)
\r
68 for(size_t i = r.begin(); i != r.end(); ++i)
\r
69 frames[i] = layers_[i].receive();
\r
71 boost::range::remove_erase(frames, draw_frame::eof());
\r
72 boost::range::remove_erase(frames, draw_frame::empty());
\r
76 void load(size_t index, const safe_ptr<frame_producer>& producer, bool play_on_load)
\r
78 check_bounds(index);
\r
79 producer->initialize(factory_);
\r
80 executor_.invoke([&]
\r
82 layers_[index].load(producer, play_on_load);
\r
86 void preview(size_t index, const safe_ptr<frame_producer>& producer)
\r
88 check_bounds(index);
\r
89 producer->initialize(factory_);
\r
90 executor_.invoke([&]
\r
92 layers_[index].preview(producer);
\r
96 void pause(size_t index)
\r
98 check_bounds(index);
\r
99 executor_.invoke([&]
\r
101 layers_[index].pause();
\r
105 void play(size_t index)
\r
107 check_bounds(index);
\r
108 executor_.invoke([&]
\r
110 layers_[index].play();
\r
114 void stop(size_t index)
\r
116 check_bounds(index);
\r
117 executor_.invoke([&]
\r
119 layers_[index].stop();
\r
123 void clear(size_t index)
\r
125 check_bounds(index);
\r
126 executor_.invoke([&]
\r
128 layers_[index] = std::move(layer());
\r
134 executor_.invoke([&]
\r
136 for(auto it = layers_.begin(); it != layers_.end(); ++it)
\r
137 *it = std::move(layer());
\r
141 void swap_layer(size_t index, size_t other_index)
\r
143 check_bounds(index);
\r
144 check_bounds(other_index);
\r
145 executor_.invoke([&]
\r
147 layers_[index].swap(layers_[other_index]);
\r
151 void swap_layer(size_t index, size_t other_index, frame_producer_device& other)
\r
153 check_bounds(index);
\r
154 check_bounds(other_index);
\r
155 executor_.invoke([&]
\r
157 layers_[index].swap(other.impl_->layers_[other_index]);
\r
161 void swap_output(frame_producer_device& other)
\r
163 tbb::spin_mutex::scoped_lock lock1(output_mutex_);
\r
164 tbb::spin_mutex::scoped_lock lock2(other.impl_->output_mutex_);
\r
165 output_.swap(other.impl_->output_);
\r
168 void check_bounds(size_t index) const
\r
170 if(index < 0 || index >= frame_producer_device::MAX_LAYER)
\r
171 BOOST_THROW_EXCEPTION(out_of_range() << arg_name_info("index") << arg_value_info(boost::lexical_cast<std::string>(index)));
\r
174 boost::unique_future<safe_ptr<frame_producer>> foreground(size_t index) const
\r
176 check_bounds(index);
\r
177 return executor_.begin_invoke([=]() -> safe_ptr<frame_producer>
\r
179 return layers_[index].foreground();
\r
184 frame_producer_device::frame_producer_device(const safe_ptr<frame_factory>& factory, const output_func& output) : impl_(new implementation(factory, output)){}
\r
185 frame_producer_device::frame_producer_device(frame_producer_device&& other) : impl_(std::move(other.impl_)){}
\r
186 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
187 void frame_producer_device::preview(size_t index, const safe_ptr<frame_producer>& producer){impl_->preview(index, producer);}
\r
188 void frame_producer_device::pause(size_t index){impl_->pause(index);}
\r
189 void frame_producer_device::play(size_t index){impl_->play(index);}
\r
190 void frame_producer_device::stop(size_t index){impl_->stop(index);}
\r
191 void frame_producer_device::clear(size_t index){impl_->clear(index);}
\r
192 void frame_producer_device::clear(){impl_->clear();}
\r
193 void frame_producer_device::swap_layer(size_t index, size_t other_index){impl_->swap_layer(index, other_index);}
\r
194 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
195 void frame_producer_device::swap_output(frame_producer_device& other){impl_->swap_output(other);}
\r
196 boost::unique_future<safe_ptr<frame_producer>> frame_producer_device::foreground(size_t index) const{ return impl_->foreground(index);}
\r