]> git.sesse.net Git - casparcg/blob - core/producer/frame_producer_device.cpp
17dd86485cdc088a5e5446381d6aa50a43d152fb
[casparcg] / core / producer / frame_producer_device.cpp
1 #include "../StdAfx.h"\r
2 \r
3 #include "frame_producer_device.h"\r
4 \r
5 #include "../mixer/frame/draw_frame.h"\r
6 #include "../mixer/frame_factory.h"\r
7 \r
8 #include "layer.h"\r
9 \r
10 #include <common/concurrency/executor.h>\r
11 \r
12 #include <boost/range/algorithm_ext/erase.hpp>\r
13 #include <boost/lexical_cast.hpp>\r
14 \r
15 #include <tbb/parallel_for.h>\r
16 #include <tbb/spin_mutex.h>\r
17 \r
18 #include <array>\r
19 #include <memory>\r
20 \r
21 namespace caspar { namespace core {\r
22 \r
23 struct frame_producer_device::implementation : boost::noncopyable\r
24 {               \r
25         std::array<layer, frame_producer_device::MAX_LAYER> layers_;            \r
26 \r
27         tbb::spin_mutex output_mutex_;\r
28         output_func output_;\r
29 \r
30         const safe_ptr<frame_factory> factory_;\r
31         \r
32         mutable executor executor_;\r
33 \r
34 public:\r
35         implementation(const safe_ptr<frame_factory>& factory, const output_func& output)  \r
36                 : factory_(factory)\r
37                 , output_(output)\r
38         {\r
39                 for(size_t n = 0; n < layers_.size(); ++n)\r
40                         layers_[n] = layer(n);\r
41 \r
42                 executor_.start();\r
43                 executor_.begin_invoke([=]{tick();});\r
44         }\r
45 \r
46         ~implementation()\r
47         {\r
48                 CASPAR_LOG(info) << "Shutting down producer-device.";\r
49         }\r
50                                         \r
51         void tick()\r
52         {               \r
53                 output_func output;\r
54                 {\r
55                         tbb::spin_mutex::scoped_lock lock(output_mutex_);\r
56                         output = output_;\r
57                 }\r
58                 output(draw());\r
59                 executor_.begin_invoke([=]{tick();});\r
60         }\r
61         \r
62         std::vector<safe_ptr<draw_frame>> draw()\r
63         {       \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
67                 {\r
68                         for(size_t i = r.begin(); i != r.end(); ++i)\r
69                                 frames[i] = layers_[i].receive();\r
70                 });             \r
71                 boost::range::remove_erase(frames, draw_frame::eof());\r
72                 boost::range::remove_erase(frames, draw_frame::empty());\r
73                 return frames;\r
74         }\r
75 \r
76         void load(size_t index, const safe_ptr<frame_producer>& producer, bool play_on_load)\r
77         {\r
78                 check_bounds(index);\r
79                 producer->initialize(factory_);\r
80                 executor_.invoke([&]\r
81                 {\r
82                         layers_[index].load(producer, play_on_load);\r
83                 });\r
84         }\r
85                         \r
86         void preview(size_t index, const safe_ptr<frame_producer>& producer)\r
87         {\r
88                 check_bounds(index);\r
89                 producer->initialize(factory_);\r
90                 executor_.invoke([&]\r
91                 {                       \r
92                         layers_[index].preview(producer);\r
93                 });\r
94         }\r
95 \r
96         void pause(size_t index)\r
97         {               \r
98                 check_bounds(index);\r
99                 executor_.invoke([&]\r
100                 {\r
101                         layers_[index].pause();\r
102                 });\r
103         }\r
104 \r
105         void play(size_t index)\r
106         {               \r
107                 check_bounds(index);\r
108                 executor_.invoke([&]\r
109                 {\r
110                         layers_[index].play();\r
111                 });\r
112         }\r
113 \r
114         void stop(size_t index)\r
115         {               \r
116                 check_bounds(index);\r
117                 executor_.invoke([&]\r
118                 {\r
119                         layers_[index].stop();\r
120                 });\r
121         }\r
122 \r
123         void clear(size_t index)\r
124         {\r
125                 check_bounds(index);\r
126                 executor_.invoke([&]\r
127                 {\r
128                         layers_[index] = std::move(layer());\r
129                 });\r
130         }\r
131                 \r
132         void clear()\r
133         {\r
134                 executor_.invoke([&]\r
135                 {\r
136                         for(auto it = layers_.begin(); it != layers_.end(); ++it)\r
137                                 *it = std::move(layer());\r
138                 });\r
139         }       \r
140         \r
141         void swap_layer(size_t index, size_t other_index)\r
142         {\r
143                 check_bounds(index);\r
144                 check_bounds(other_index);\r
145                 executor_.invoke([&]\r
146                 {\r
147                         layers_[index].swap(layers_[other_index]);\r
148                 });\r
149         }\r
150 \r
151         void swap_layer(size_t index, size_t other_index, frame_producer_device& other)\r
152         {\r
153                 check_bounds(index);\r
154                 check_bounds(other_index);\r
155                 executor_.invoke([&]\r
156                 {\r
157                         layers_[index].swap(other.impl_->layers_[other_index]);\r
158                 });\r
159         }\r
160 \r
161         void swap_output(frame_producer_device& other)\r
162         {\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
166         }\r
167 \r
168         void check_bounds(size_t index) const\r
169         {\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
172         }\r
173         \r
174         boost::unique_future<safe_ptr<frame_producer>> foreground(size_t index) const\r
175         {\r
176                 check_bounds(index);\r
177                 return executor_.begin_invoke([=]() -> safe_ptr<frame_producer>\r
178                 {                       \r
179                         return layers_[index].foreground();\r
180                 });\r
181         }\r
182 };\r
183 \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
197 }}