]> git.sesse.net Git - casparcg/blob - core/channel.cpp
9d6a469a9e43026aea6afb4c752656995667ffb5
[casparcg] / core / channel.cpp
1 #include "StdAfx.h"\r
2 \r
3 #include "channel.h"\r
4 \r
5 #include "consumer/frame_consumer_device.h"\r
6 \r
7 #include "processor/draw_frame.h"\r
8 #include "processor/frame_processor_device.h"\r
9 \r
10 #include "producer/layer.h"\r
11 \r
12 #include <common/concurrency/executor.h>\r
13 \r
14 #include <boost/range/algorithm_ext/erase.hpp>\r
15 \r
16 #include <tbb/parallel_for.h>\r
17 \r
18 #include <map>\r
19 #include <memory>\r
20 \r
21 namespace caspar { namespace core {\r
22 \r
23 struct channel::implementation : boost::noncopyable\r
24 {                                       \r
25         const safe_ptr<frame_processor_device> processor_device_;\r
26         frame_consumer_device consumer_device_;\r
27                                                 \r
28         std::map<int, layer> layers_;           \r
29 \r
30         const video_format_desc format_desc_;\r
31 \r
32         mutable executor executor_;\r
33 \r
34 public:\r
35         implementation(const video_format_desc& format_desc)  \r
36                 : format_desc_(format_desc)\r
37                 , processor_device_(frame_processor_device(format_desc))\r
38                 , consumer_device_(format_desc)\r
39         {\r
40                 executor_.start();\r
41                 executor_.begin_invoke([=]{tick();});\r
42         }\r
43                                         \r
44         void tick()\r
45         {               \r
46                 auto drawed_frame = draw();\r
47                 auto processed_frame = processor_device_->process(std::move(drawed_frame));\r
48                 consumer_device_.consume(std::move(processed_frame));\r
49 \r
50                 executor_.begin_invoke([=]{tick();});\r
51         }\r
52         \r
53         safe_ptr<draw_frame> draw()\r
54         {       \r
55                 std::vector<safe_ptr<draw_frame>> frames(layers_.size(), draw_frame::empty());\r
56                 tbb::parallel_for(tbb::blocked_range<size_t>(0, frames.size()), \r
57                 [&](const tbb::blocked_range<size_t>& r)\r
58                 {\r
59                         auto it = layers_.begin();\r
60                         std::advance(it, r.begin());\r
61                         for(size_t i = r.begin(); i != r.end(); ++i, ++it)\r
62                                 frames[i] = it->second.receive();\r
63                 });             \r
64                 boost::range::remove_erase(frames, draw_frame::eof());\r
65                 boost::range::remove_erase(frames, draw_frame::empty());\r
66                 return draw_frame(frames);\r
67         }\r
68 \r
69         void add(int index, const safe_ptr<frame_consumer>& consumer)\r
70         {\r
71                 consumer_device_.add(index, consumer);\r
72         }\r
73         \r
74         void remove(int index)\r
75         {\r
76                 consumer_device_.remove(index);\r
77         }\r
78 \r
79         void load(int index, const safe_ptr<frame_producer>& producer, bool play_on_load)\r
80         {\r
81                 CASPAR_LOG(trace) << executor_.size();\r
82                 producer->initialize(processor_device_);\r
83                 executor_.begin_invoke([=]\r
84                 {\r
85                         auto it = layers_.insert(std::make_pair(index, layer(index))).first;\r
86                         it->second.load(producer, play_on_load);\r
87                 });\r
88         }\r
89                         \r
90         void preview(int index, const safe_ptr<frame_producer>& producer)\r
91         {\r
92                 producer->initialize(processor_device_);\r
93                 executor_.begin_invoke([=]\r
94                 {\r
95                         auto it = layers_.insert(std::make_pair(index, layer(index))).first;\r
96                         it->second.preview(producer);\r
97                 });\r
98         }\r
99 \r
100         void pause(int index)\r
101         {               \r
102                 executor_.begin_invoke([=]\r
103                 {                       \r
104                         auto it = layers_.find(index);\r
105                         if(it != layers_.end())\r
106                                 it->second.pause();             \r
107                 });\r
108         }\r
109 \r
110         void play(int index)\r
111         {               \r
112                 executor_.begin_invoke([=]\r
113                 {\r
114                         auto it = layers_.find(index);\r
115                         if(it != layers_.end())\r
116                                 it->second.play();\r
117                 });\r
118         }\r
119 \r
120         void stop(int index)\r
121         {               \r
122                 executor_.begin_invoke([=]\r
123                 {\r
124                         auto it = layers_.find(index);\r
125                         if(it != layers_.end())\r
126                         {\r
127                                 it->second.stop();      \r
128                                 if(it->second.empty())\r
129                                         layers_.erase(it);\r
130                         }\r
131                 });\r
132         }\r
133 \r
134         void clear(int index)\r
135         {\r
136                 executor_.begin_invoke([=]\r
137                 {                       \r
138                         auto it = layers_.find(index);\r
139                         if(it != layers_.end())\r
140                         {\r
141                                 it->second.clear();             \r
142                                 layers_.erase(it);\r
143                         }\r
144                 });\r
145         }\r
146                 \r
147         void clear()\r
148         {\r
149                 executor_.begin_invoke([=]\r
150                 {                       \r
151                         layers_.clear();\r
152                 });\r
153         }               \r
154 \r
155         boost::unique_future<safe_ptr<frame_producer>> foreground(int index) const\r
156         {\r
157                 return executor_.begin_invoke([=]() -> safe_ptr<frame_producer>\r
158                 {                       \r
159                         auto it = layers_.find(index);\r
160                         return it != layers_.end() ? it->second.foreground() : frame_producer::empty();\r
161                 });\r
162         }\r
163         \r
164         boost::unique_future<safe_ptr<frame_producer>> background(int index) const\r
165         {\r
166                 return executor_.begin_invoke([=]() -> safe_ptr<frame_producer>\r
167                 {\r
168                         auto it = layers_.find(index);\r
169                         return it != layers_.end() ? it->second.background() : frame_producer::empty();\r
170                 });\r
171         };\r
172 };\r
173 \r
174 channel::channel(channel&& other) : impl_(std::move(other.impl_)){}\r
175 channel::channel(const video_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
176 void channel::add(int index, const safe_ptr<frame_consumer>& consumer){impl_->add(index, consumer);}\r
177 void channel::remove(int index){impl_->remove(index);}\r
178 void channel::load(int index, const safe_ptr<frame_producer>& producer, bool play_on_load){impl_->load(index, producer, play_on_load);}\r
179 void channel::preview(int index, const safe_ptr<frame_producer>& producer){impl_->preview(index, producer);}\r
180 void channel::pause(int index){impl_->pause(index);}\r
181 void channel::play(int index){impl_->play(index);}\r
182 void channel::stop(int index){impl_->stop(index);}\r
183 void channel::clear(int index){impl_->clear(index);}\r
184 void channel::clear(){impl_->clear();}\r
185 boost::unique_future<safe_ptr<frame_producer>> channel::foreground(int index) const{    return impl_->foreground(index);}\r
186 boost::unique_future<safe_ptr<frame_producer>> channel::background(int index) const{return impl_->background(index);}\r
187 const video_format_desc& channel::get_video_format_desc() const{        return impl_->format_desc_;}\r
188 \r
189 }}