1 #include "../StdAfx.h"
\r
3 #include "frame_producer_device.h"
\r
5 #include <core/producer/frame/basic_frame.h>
\r
6 #include <core/producer/frame/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/mutex.h>
\r
22 namespace caspar { namespace core {
\r
24 struct frame_producer_device::implementation : boost::noncopyable
\r
26 std::map<int, layer> layers_;
\r
28 const video_format_desc format_desc_;
\r
32 mutable executor executor_;
\r
34 implementation(const video_format_desc& format_desc)
\r
35 : format_desc_(format_desc)
\r
36 , executor_(L"frame_producer_device")
\r
43 CASPAR_LOG(info) << "Shutting down producer-device.";
\r
46 boost::signals2::connection connect(const output_t::slot_type& subscriber)
\r
48 return executor_.invoke([&]() -> boost::signals2::connection
\r
51 executor_.begin_invoke([=]{tick();});
\r
52 return output_.connect(subscriber);
\r
62 executor_.begin_invoke([=]{tick();});
\r
65 layer& get_layer(int index)
\r
67 auto it = layers_.find(index);
\r
68 if(it == layers_.end())
\r
69 it = layers_.insert(std::make_pair(index, layer(index))).first;
\r
73 std::vector<safe_ptr<basic_frame>> draw()
\r
75 std::vector<safe_ptr<basic_frame>> frames(layers_.size(), basic_frame::empty());
\r
76 tbb::parallel_for(tbb::blocked_range<size_t>(0, frames.size(), 1), [&](const tbb::blocked_range<size_t>& r)
\r
78 auto it = layers_.begin();
\r
79 std::advance(it, r.begin());
\r
80 for(size_t i = r.begin(); i != r.end(); ++i, ++it)
\r
82 frames[i] = it->second.receive();
\r
83 frames[i]->set_layer_index(it->first);
\r
86 boost::range::remove_erase(frames, basic_frame::empty());
\r
87 boost::range::remove_erase(frames, basic_frame::eof());
\r
91 void load(int index, const safe_ptr<frame_producer>& producer, bool play_on_load, bool preview)
\r
93 executor_.invoke([&]{get_layer(index).load(producer, play_on_load, preview);});
\r
96 void pause(int index)
\r
98 executor_.invoke([&]{get_layer(index).pause();});
\r
101 void play(int index)
\r
103 executor_.invoke([&]{get_layer(index).play();});
\r
106 void stop(int index)
\r
108 executor_.invoke([&]{get_layer(index).stop();});
\r
111 void clear(int index)
\r
113 executor_.invoke([&]{layers_.erase(index);});
\r
118 executor_.invoke([&]{layers_.clear();});
\r
121 void swap_layer(int index, size_t other_index)
\r
123 executor_.invoke([&]
\r
125 get_layer(index).swap(layers_[other_index]);
\r
129 void swap_layer(int index, size_t other_index, frame_producer_device& other)
\r
131 if(other.impl_.get() == this)
\r
132 swap_layer(index, other_index);
\r
135 if(format_desc_ != other.impl_->format_desc_)
\r
136 BOOST_THROW_EXCEPTION(invalid_operation() << msg_info("Cannot swap between channels with different formats."));
\r
140 get_layer(index).swap(other.impl_->layers_.at(other_index));
\r
142 CASPAR_LOG(info) << print() << L" Swapped layer " << index << L" with " << other.impl_->print() << L" layer " << other_index << L".";
\r
145 executor_.invoke([&]{other.impl_->executor_.invoke(func);});
\r
149 void swap(frame_producer_device& other)
\r
151 if(other.impl_.get() == this)
\r
154 if(format_desc_ != other.impl_->format_desc_)
\r
155 BOOST_THROW_EXCEPTION(invalid_operation() << msg_info("Cannot swap between channels with different formats."));
\r
159 std::set<int> my_indices;
\r
160 BOOST_FOREACH(auto& pair, layers_)
\r
161 my_indices.insert(pair.first);
\r
163 std::set<int> other_indicies;
\r
164 BOOST_FOREACH(auto& pair, other.impl_->layers_)
\r
165 other_indicies.insert(pair.first);
\r
167 std::vector<int> indices;
\r
168 std::set_union(my_indices.begin(), my_indices.end(), other_indicies.begin(), other_indicies.end(), std::back_inserter(indices));
\r
170 BOOST_FOREACH(auto index, indices)
\r
171 get_layer(index).swap(other.impl_->get_layer(index));
\r
173 CASPAR_LOG(info) << print() << L" Swapped layers with " << other.impl_->print() << L".";
\r
176 executor_.invoke([&]{other.impl_->executor_.invoke(func);});
\r
179 boost::unique_future<safe_ptr<frame_producer>> foreground(int index) const
\r
181 return executor_.begin_invoke([=]() mutable -> safe_ptr<frame_producer>
\r
183 auto it = layers_.find(index);
\r
184 return it != layers_.end() ? it->second.foreground() : frame_producer::empty();
\r
188 std::wstring print() const
\r
190 return L"frame_producer_device";
\r
194 frame_producer_device::frame_producer_device(const video_format_desc& format_desc) : impl_(new implementation(format_desc)){}
\r
195 frame_producer_device::frame_producer_device(frame_producer_device&& other) : impl_(std::move(other.impl_)){}
\r
196 boost::signals2::connection frame_producer_device::connect(const output_t::slot_type& subscriber){return impl_->connect(subscriber);}
\r
197 void frame_producer_device::swap(frame_producer_device& other){impl_->swap(other);}
\r
198 void frame_producer_device::load(int index, const safe_ptr<frame_producer>& producer, bool play_on_load, bool preview){impl_->load(index, producer, play_on_load, preview);}
\r
199 void frame_producer_device::pause(int index){impl_->pause(index);}
\r
200 void frame_producer_device::play(int index){impl_->play(index);}
\r
201 void frame_producer_device::stop(int index){impl_->stop(index);}
\r
202 void frame_producer_device::clear(int index){impl_->clear(index);}
\r
203 void frame_producer_device::clear(){impl_->clear();}
\r
204 void frame_producer_device::swap_layer(int index, size_t other_index){impl_->swap_layer(index, other_index);}
\r
205 void frame_producer_device::swap_layer(int index, size_t other_index, frame_producer_device& other){impl_->swap_layer(index, other_index, other);}
\r
206 boost::unique_future<safe_ptr<frame_producer>> frame_producer_device::foreground(size_t index) const{ return impl_->foreground(index);}
\r