]> git.sesse.net Git - casparcg/blob - core/producer/stage.cpp
* started using final keyword on classes where previously sealed or commented final
[casparcg] / core / producer / stage.cpp
1 /*
2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
3 *
4 * This file is part of CasparCG (www.casparcg.com).
5 *
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Robert Nagy, ronag89@gmail.com
20 */
21
22 #include "../StdAfx.h"
23
24 #include "stage.h"
25
26 #include "layer.h"
27
28 #include "../frame/draw_frame.h"
29 #include "../frame/frame_factory.h"
30 #include "../interaction/interaction_aggregator.h"
31
32 #include <common/executor.h>
33 #include <common/future.h>
34 #include <common/diagnostics/graph.h>
35
36 #include <core/frame/frame_transform.h>
37
38 #include <boost/timer.hpp>
39 #include <boost/property_tree/ptree.hpp>
40 #include <boost/range/algorithm_ext.hpp>
41
42 #include <tbb/parallel_for_each.h>
43
44 #include <functional>
45 #include <map>
46 #include <vector>
47 #include <future>
48
49 namespace caspar { namespace core {
50         
51 struct stage::impl : public std::enable_shared_from_this<impl>
52 {                               
53         spl::shared_ptr<diagnostics::graph>                                                     graph_;
54         spl::shared_ptr<monitor::subject>                                                       monitor_subject_;
55         //reactive::basic_subject<std::map<int, class draw_frame>>      frames_subject_;
56         std::map<int, layer>                                                                            layers_;        
57         std::map<int, tweened_transform>                                                        tweens_;
58         interaction_aggregator                                                                          aggregator_;
59         executor                                                                                                        executor_;
60 public:
61         impl(spl::shared_ptr<diagnostics::graph> graph) 
62                 : graph_(std::move(graph))
63                 , monitor_subject_(spl::make_shared<monitor::subject>("/stage"))
64                 , aggregator_([=] (double x, double y) { return collission_detect(x, y); })
65                 , executor_(L"stage")
66         {
67                 graph_->set_color("produce-time", diagnostics::color(0.0f, 1.0f, 0.0f));
68         }
69                 
70         std::map<int, draw_frame> operator()(const struct video_format_desc& format_desc)
71         {               
72                 boost::timer frame_timer;
73
74                 auto frames = executor_.invoke([=]() -> std::map<int, draw_frame>
75                 {
76
77                         std::map<int, class draw_frame> frames;
78                         
79                         try
80                         {                       
81                                 std::vector<int> indices;
82
83                                 for (auto& layer : layers_)     
84                                 {
85                                         frames[layer.first] = draw_frame::empty();      
86                                         indices.push_back(layer.first);
87                                 }
88
89                                 aggregator_.translate_and_send();
90
91                                 tbb::parallel_for_each(indices.begin(), indices.end(), [&](int index)
92                                 {
93                                         draw(index, format_desc, frames);
94                                 });
95                         }
96                         catch(...)
97                         {
98                                 layers_.clear();
99                                 CASPAR_LOG_CURRENT_EXCEPTION();
100                         }       
101                         
102
103                         return frames;
104                 });
105                 
106                 //frames_subject_ << frames;
107                 
108                 graph_->set_value("produce-time", frame_timer.elapsed()*format_desc.fps*0.5);
109                 *monitor_subject_ << monitor::message("/profiler/time") % frame_timer.elapsed() % (1.0/format_desc.fps);
110
111                 return frames;
112         }
113
114         void draw(int index, const video_format_desc& format_desc, std::map<int, draw_frame>& frames)
115         {
116                 auto& layer             = layers_[index];
117                 auto& tween             = tweens_[index];
118                                 
119                 auto frame  = layer.receive(format_desc);                                       
120                 auto frame1 = frame;
121                 frame1.transform() *= tween.fetch_and_tick(1);
122
123                 if(format_desc.field_mode != core::field_mode::progressive)
124                 {                               
125                         auto frame2 = frame;
126                         frame2.transform() *= tween.fetch_and_tick(1);
127                         frame1 = core::draw_frame::interlace(frame1, frame2, format_desc.field_mode);
128                 }
129
130                 frames[index] = frame1;
131         }
132
133         layer& get_layer(int index)
134         {
135                 auto it = layers_.find(index);
136                 if(it == std::end(layers_))
137                 {
138                         it = layers_.insert(std::make_pair(index, layer(index))).first;
139                         it->second.monitor_output().attach_parent(monitor_subject_);
140                 }
141                 return it->second;
142         }
143                 
144         std::future<void> apply_transforms(const std::vector<std::tuple<int, stage::transform_func_t, unsigned int, tweener>>& transforms)
145         {
146                 return executor_.begin_invoke([=]
147                 {
148                         for (auto& transform : transforms)
149                         {
150                                 auto src = tweens_[std::get<0>(transform)].fetch();
151                                 auto dst = std::get<1>(transform)(src);
152                                 tweens_[std::get<0>(transform)] = tweened_transform(src, dst, std::get<2>(transform), std::get<3>(transform));
153                         }
154                 }, task_priority::high_priority);
155         }
156                                                 
157         std::future<void> apply_transform(int index, const stage::transform_func_t& transform, unsigned int mix_duration, const tweener& tween)
158         {
159                 return executor_.begin_invoke([=]
160                 {
161                         auto src = tweens_[index].fetch();
162                         auto dst = transform(src);
163                         tweens_[index] = tweened_transform(src, dst, mix_duration, tween);
164                 }, task_priority::high_priority);
165         }
166
167         std::future<void> clear_transforms(int index)
168         {
169                 return executor_.begin_invoke([=]
170                 {
171                         tweens_.erase(index);
172                 }, task_priority::high_priority);
173         }
174
175         std::future<void> clear_transforms()
176         {
177                 return executor_.begin_invoke([=]
178                 {
179                         tweens_.clear();
180                 }, task_priority::high_priority);
181         }
182                 
183         std::future<void> load(int index, const spl::shared_ptr<frame_producer>& producer, bool preview, const boost::optional<int32_t>& auto_play_delta)
184         {
185                 return executor_.begin_invoke([=]
186                 {
187                         get_layer(index).load(producer, preview, auto_play_delta);                      
188                 }, task_priority::high_priority);
189         }
190
191         std::future<void> pause(int index)
192         {               
193                 return executor_.begin_invoke([=]
194                 {
195                         get_layer(index).pause();
196                 }, task_priority::high_priority);
197         }
198
199         std::future<void> play(int index)
200         {               
201                 return executor_.begin_invoke([=]
202                 {
203                         get_layer(index).play();
204                 }, task_priority::high_priority);
205         }
206
207         std::future<void> stop(int index)
208         {               
209                 return executor_.begin_invoke([=]
210                 {
211                         get_layer(index).stop();
212                 }, task_priority::high_priority);
213         }
214
215         std::future<void> clear(int index)
216         {
217                 return executor_.begin_invoke([=]
218                 {
219                         layers_.erase(index);
220                 }, task_priority::high_priority);
221         }
222                 
223         std::future<void> clear()
224         {
225                 return executor_.begin_invoke([=]
226                 {
227                         layers_.clear();
228                 }, task_priority::high_priority);
229         }       
230                 
231         std::future<void> swap_layers(stage& other)
232         {
233                 auto other_impl = other.impl_;
234
235                 if (other_impl.get() == this)
236                 {
237                         return make_ready_future();
238                 }
239                 
240                 auto func = [=]
241                 {
242                         auto layers                     = layers_ | boost::adaptors::map_values;
243                         auto other_layers       = other_impl->layers_ | boost::adaptors::map_values;
244
245                         for (auto& layer : layers)
246                                 layer.monitor_output().detach_parent();
247                         
248                         for (auto& layer : other_layers)
249                                 layer.monitor_output().detach_parent();
250                         
251                         std::swap(layers_, other_impl->layers_);
252                                                 
253                         for (auto& layer : layers)
254                                 layer.monitor_output().attach_parent(monitor_subject_);
255                         
256                         for (auto& layer : other_layers)
257                                 layer.monitor_output().attach_parent(monitor_subject_);
258                 };              
259
260                 return executor_.begin_invoke([=]
261                 {
262                         other_impl->executor_.invoke(func, task_priority::high_priority);
263                 }, task_priority::high_priority);
264         }
265
266         std::future<void> swap_layer(int index, int other_index)
267         {
268                 return executor_.begin_invoke([=]
269                 {
270                         std::swap(get_layer(index), get_layer(other_index));
271                 }, task_priority::high_priority);
272         }
273
274         std::future<void> swap_layer(int index, int other_index, stage& other)
275         {
276                 auto other_impl = other.impl_;
277
278                 if(other_impl.get() == this)
279                         return swap_layer(index, other_index);
280                 else
281                 {
282                         auto func = [=]
283                         {
284                                 auto& my_layer          = get_layer(index);
285                                 auto& other_layer       = other_impl->get_layer(other_index);
286
287                                 my_layer.monitor_output().detach_parent();
288                                 other_layer.monitor_output().detach_parent();
289
290                                 std::swap(my_layer, other_layer);
291
292                                 my_layer.monitor_output().attach_parent(monitor_subject_);
293                                 other_layer.monitor_output().attach_parent(other_impl->monitor_subject_);
294                         };              
295
296                         return executor_.begin_invoke([=]
297                         {
298                                 other_impl->executor_.invoke(func, task_priority::high_priority);
299                         }, task_priority::high_priority);
300                 }
301         }
302                 
303         std::future<std::shared_ptr<frame_producer>> foreground(int index)
304         {
305                 return executor_.begin_invoke([=]() -> std::shared_ptr<frame_producer>
306                 {
307                         return get_layer(index).foreground();
308                 }, task_priority::high_priority);
309         }
310         
311         std::future<std::shared_ptr<frame_producer>> background(int index)
312         {
313                 return executor_.begin_invoke([=]() -> std::shared_ptr<frame_producer>
314                 {
315                         return get_layer(index).background();
316                 }, task_priority::high_priority);
317         }
318
319         std::future<boost::property_tree::wptree> info()
320         {
321                 return executor_.begin_invoke([this]() -> boost::property_tree::wptree
322                 {
323                         boost::property_tree::wptree info;
324                         for (auto& layer : layers_)                     
325                                 info.add_child(L"layers.layer", layer.second.info())
326                                         .add(L"index", layer.first);    
327                         return info;
328                 }, task_priority::high_priority);
329         }
330
331         std::future<boost::property_tree::wptree> info(int index)
332         {
333                 return executor_.begin_invoke([=]
334                 {
335                         return get_layer(index).info();
336                 }, task_priority::high_priority);
337         }               
338         
339         std::future<std::wstring> call(int index, const std::vector<std::wstring>& params)
340         {
341                 return flatten(executor_.begin_invoke([=]
342                 {
343                         return get_layer(index).foreground()->call(params).share();
344                 }, task_priority::high_priority));
345         }
346
347         void on_interaction(const interaction_event::ptr& event)
348         {
349                 executor_.begin_invoke([=]
350                 {
351                         aggregator_.offer(event);
352                 }, task_priority::high_priority);
353         }
354
355         boost::optional<interaction_target> collission_detect(double x, double y)
356         {
357                 for (auto& layer : layers_ | boost::adaptors::reversed)
358                 {
359                         auto transform = tweens_[layer.first].fetch();
360                         auto translated = translate(x, y, transform);
361
362                         if (translated.first >= 0.0
363                                 && translated.first <= 1.0
364                                 && translated.second >= 0.0
365                                 && translated.second <= 1.0
366                                 && layer.second.collides(translated.first, translated.second))
367                         {
368                                 return std::make_pair(transform, &layer.second);
369                         }
370                 }
371
372                 return boost::optional<interaction_target>();
373         }
374 };
375
376 stage::stage(spl::shared_ptr<diagnostics::graph> graph) : impl_(new impl(std::move(graph))){}
377 std::future<std::wstring> stage::call(int index, const std::vector<std::wstring>& params){return impl_->call(index, params);}
378 std::future<void> stage::apply_transforms(const std::vector<stage::transform_tuple_t>& transforms){ return impl_->apply_transforms(transforms); }
379 std::future<void> stage::apply_transform(int index, const std::function<core::frame_transform(core::frame_transform)>& transform, unsigned int mix_duration, const tweener& tween){ return impl_->apply_transform(index, transform, mix_duration, tween); }
380 std::future<void> stage::clear_transforms(int index){ return impl_->clear_transforms(index); }
381 std::future<void> stage::clear_transforms(){ return impl_->clear_transforms(); }
382 std::future<void> stage::load(int index, const spl::shared_ptr<frame_producer>& producer, bool preview, const boost::optional<int32_t>& auto_play_delta){ return impl_->load(index, producer, preview, auto_play_delta); }
383 std::future<void> stage::pause(int index){ return impl_->pause(index); }
384 std::future<void> stage::play(int index){ return impl_->play(index); }
385 std::future<void> stage::stop(int index){ return impl_->stop(index); }
386 std::future<void> stage::clear(int index){ return impl_->clear(index); }
387 std::future<void> stage::clear(){ return impl_->clear(); }
388 std::future<void> stage::swap_layers(stage& other){ return impl_->swap_layers(other); }
389 std::future<void> stage::swap_layer(int index, int other_index){ return impl_->swap_layer(index, other_index); }
390 std::future<void> stage::swap_layer(int index, int other_index, stage& other){ return impl_->swap_layer(index, other_index, other); }
391 std::future<std::shared_ptr<frame_producer>> stage::foreground(int index) { return impl_->foreground(index); }
392 std::future<std::shared_ptr<frame_producer>> stage::background(int index) { return impl_->background(index); }
393 std::future<boost::property_tree::wptree> stage::info() const{ return impl_->info(); }
394 std::future<boost::property_tree::wptree> stage::info(int index) const{ return impl_->info(index); }
395 std::map<int, class draw_frame> stage::operator()(const video_format_desc& format_desc){return (*impl_)(format_desc);}
396 monitor::subject& stage::monitor_output(){return *impl_->monitor_subject_;}
397 //void stage::subscribe(const frame_observable::observer_ptr& o) {impl_->frames_subject_.subscribe(o);}
398 //void stage::unsubscribe(const frame_observable::observer_ptr& o) {impl_->frames_subject_.unsubscribe(o);}
399 void stage::on_interaction(const interaction_event::ptr& event) { impl_->on_interaction(event); }
400 }}