]> git.sesse.net Git - casparcg/blob - core/producer/frame_producer_device.cpp
2.0.0.2:
[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 "layer.h"\r
6 \r
7 #include "../format/video_format.h"\r
8 #include "../processor/composite_frame.h"\r
9 \r
10 #include "../../common/utility/scope_exit.h"\r
11 \r
12 #include <boost/thread.hpp>\r
13 #include <boost/range/algorithm_ext/erase.hpp>\r
14 #include <boost/range/algorithm.hpp>\r
15 #include <boost/foreach.hpp>\r
16 \r
17 #include <tbb/concurrent_vector.h>\r
18 #include <tbb/parallel_for.h>\r
19 #include <tbb/mutex.h>\r
20         \r
21 namespace caspar { namespace core {\r
22         \r
23 std::vector<gpu_frame_ptr> receives(std::map<int, layer>& layers)\r
24 {       \r
25         std::vector<gpu_frame_ptr> frames(layers.size(), nullptr);\r
26         tbb::parallel_for(tbb::blocked_range<size_t>(0, frames.size()), \r
27         [&](const tbb::blocked_range<size_t>& r)\r
28         {\r
29                 auto it = layers.begin();\r
30                 std::advance(it, r.begin());\r
31                 for(size_t i = r.begin(); i != r.end(); ++i, ++it)\r
32                         frames[i] = it->second.receive();\r
33         });             \r
34         return frames;\r
35 }\r
36 \r
37 struct frame_producer_device::implementation : boost::noncopyable\r
38 {       \r
39         implementation(const frame_processor_device_ptr& frame_processor)  \r
40                 : frame_processor_(frame_processor)\r
41         {\r
42                 render_thread_ = boost::thread([=]{run();});\r
43         }\r
44                         \r
45         ~implementation()\r
46         {\r
47                 is_running_ = false;\r
48                 render_thread_.join();\r
49         }\r
50                 \r
51         void run()\r
52         {               \r
53                 win32_exception::install_handler();\r
54                 \r
55                 is_running_ = true;\r
56                 while(is_running_)\r
57                 {\r
58                         try\r
59                         {       \r
60                                 std::vector<gpu_frame_ptr> frames;\r
61                                 {\r
62                                         tbb::mutex::scoped_lock lock(layers_mutex_);    \r
63                                         frames = receives(layers_);\r
64                                 }                               \r
65                                 frame_processor_->send(std::make_shared<composite_frame>(frames));\r
66                         }\r
67                         catch(...)\r
68                         {\r
69                                 try\r
70                                 {\r
71                                         CASPAR_LOG_CURRENT_EXCEPTION();\r
72                                         layers_.clear();\r
73                                         CASPAR_LOG(error) << "Unexpected exception. Cleared layers in render-device";\r
74                                 }\r
75                                 catch(...){}\r
76                         }\r
77                 }\r
78         }\r
79 \r
80         void load(int render_layer, const frame_producer_ptr& producer, load_option::type option)\r
81         {\r
82                 producer->initialize(frame_processor_);\r
83                 tbb::mutex::scoped_lock lock(layers_mutex_);\r
84                 layers_[render_layer].load(producer, option);\r
85         }\r
86                         \r
87         void pause(int render_layer)\r
88         {               \r
89                 tbb::mutex::scoped_lock lock(layers_mutex_);\r
90                 auto it = layers_.find(render_layer);\r
91                 if(it != layers_.end())\r
92                         it->second.pause();             \r
93         }\r
94 \r
95         void play(int render_layer)\r
96         {               \r
97                 tbb::mutex::scoped_lock lock(layers_mutex_);\r
98                 auto it = layers_.find(render_layer);\r
99                 if(it != layers_.end())\r
100                         it->second.play();              \r
101         }\r
102 \r
103         void stop(int render_layer)\r
104         {               \r
105                 tbb::mutex::scoped_lock lock(layers_mutex_);\r
106                 auto it = layers_.find(render_layer);\r
107                 if(it != layers_.end())\r
108                         it->second.stop();\r
109         }\r
110 \r
111         void clear(int render_layer)\r
112         {\r
113                 tbb::mutex::scoped_lock lock(layers_mutex_);\r
114                 auto it = layers_.find(render_layer);\r
115                 if(it != layers_.end())\r
116                         it->second.clear();             \r
117         }\r
118                 \r
119         void clear()\r
120         {\r
121                 tbb::mutex::scoped_lock lock(layers_mutex_);\r
122                 layers_.clear();\r
123         }               \r
124 \r
125         frame_producer_ptr foreground(int render_layer) const\r
126         {\r
127                 tbb::mutex::scoped_lock lock(layers_mutex_);\r
128                 auto it = layers_.find(render_layer);\r
129                 return it != layers_.end() ? it->second.foreground() : nullptr;\r
130         }\r
131         \r
132         frame_producer_ptr background(int render_layer) const\r
133         {\r
134                 tbb::mutex::scoped_lock lock(layers_mutex_);\r
135                 auto it = layers_.find(render_layer);\r
136                 return it != layers_.end() ? it->second.background() : nullptr;\r
137         }\r
138                                 \r
139         frame_processor_device_ptr frame_processor_;\r
140 \r
141         boost::thread render_thread_;\r
142                                         \r
143         mutable tbb::mutex layers_mutex_;\r
144         std::map<int, layer> layers_;\r
145         \r
146         tbb::atomic<bool> is_running_;          \r
147 };\r
148 \r
149 frame_producer_device::frame_producer_device(const frame_processor_device_ptr& frame_processor) \r
150         : impl_(new implementation(frame_processor)){}\r
151 void frame_producer_device::load(int render_layer, const frame_producer_ptr& producer, load_option::type option){impl_->load(render_layer, producer, option);}\r
152 void frame_producer_device::pause(int render_layer){impl_->pause(render_layer);}\r
153 void frame_producer_device::play(int render_layer){impl_->play(render_layer);}\r
154 void frame_producer_device::stop(int render_layer){impl_->stop(render_layer);}\r
155 void frame_producer_device::clear(int render_layer){impl_->clear(render_layer);}\r
156 void frame_producer_device::clear(){impl_->clear();}\r
157 frame_producer_ptr frame_producer_device::foreground(int render_layer) const {return impl_->foreground(render_layer);}\r
158 frame_producer_ptr frame_producer_device::background(int render_layer) const {return impl_->background(render_layer);}\r
159 }}\r