]> 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<frame_ptr> render_frames(std::map<int, layer>& layers)\r
24 {       \r
25         std::vector<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.render_frame();\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                 frame_processor_->clear();\r
49                 render_thread_.join();\r
50         }\r
51                 \r
52         void run()\r
53         {               \r
54                 win32_exception::install_handler();\r
55                 \r
56                 is_running_ = true;\r
57                 while(is_running_)\r
58                 {\r
59                         try\r
60                         {       \r
61                                 std::vector<frame_ptr> frames;\r
62                                 {\r
63                                         tbb::mutex::scoped_lock lock(layers_mutex_);    \r
64                                         frames = render_frames(layers_);\r
65                                 }                               \r
66                                 frame_processor_->send(std::make_shared<composite_frame>(frames));\r
67                         }\r
68                         catch(...)\r
69                         {\r
70                                 try\r
71                                 {\r
72                                         CASPAR_LOG_CURRENT_EXCEPTION();\r
73                                         layers_.clear();\r
74                                         CASPAR_LOG(error) << "Unexpected exception. Cleared layers in render-device";\r
75                                 }\r
76                                 catch(...){}\r
77                         }\r
78                 }\r
79         }\r
80 \r
81         void load(int render_layer, const frame_producer_ptr& producer, load_option::type option)\r
82         {\r
83                 producer->initialize(frame_processor_);\r
84                 tbb::mutex::scoped_lock lock(layers_mutex_);\r
85                 layers_[render_layer].load(producer, option);\r
86         }\r
87                         \r
88         void pause(int render_layer)\r
89         {               \r
90                 tbb::mutex::scoped_lock lock(layers_mutex_);\r
91                 auto it = layers_.find(render_layer);\r
92                 if(it != layers_.end())\r
93                         it->second.pause();             \r
94         }\r
95 \r
96         void play(int render_layer)\r
97         {               \r
98                 tbb::mutex::scoped_lock lock(layers_mutex_);\r
99                 auto it = layers_.find(render_layer);\r
100                 if(it != layers_.end())\r
101                         it->second.play();              \r
102         }\r
103 \r
104         void stop(int render_layer)\r
105         {               \r
106                 tbb::mutex::scoped_lock lock(layers_mutex_);\r
107                 auto it = layers_.find(render_layer);\r
108                 if(it != layers_.end())\r
109                         it->second.stop();\r
110         }\r
111 \r
112         void clear(int render_layer)\r
113         {\r
114                 tbb::mutex::scoped_lock lock(layers_mutex_);\r
115                 auto it = layers_.find(render_layer);\r
116                 if(it != layers_.end())\r
117                         it->second.clear();             \r
118         }\r
119                 \r
120         void clear()\r
121         {\r
122                 tbb::mutex::scoped_lock lock(layers_mutex_);\r
123                 layers_.clear();\r
124         }               \r
125 \r
126         frame_producer_ptr foreground(int render_layer) const\r
127         {\r
128                 tbb::mutex::scoped_lock lock(layers_mutex_);\r
129                 auto it = layers_.find(render_layer);\r
130                 return it != layers_.end() ? it->second.foreground() : nullptr;\r
131         }\r
132         \r
133         frame_producer_ptr background(int render_layer) const\r
134         {\r
135                 tbb::mutex::scoped_lock lock(layers_mutex_);\r
136                 auto it = layers_.find(render_layer);\r
137                 return it != layers_.end() ? it->second.background() : nullptr;\r
138         }\r
139                                 \r
140         frame_processor_device_ptr frame_processor_;\r
141 \r
142         boost::thread render_thread_;\r
143                                         \r
144         mutable tbb::mutex layers_mutex_;\r
145         std::map<int, layer> layers_;\r
146         \r
147         tbb::atomic<bool> is_running_;          \r
148 };\r
149 \r
150 frame_producer_device::frame_producer_device(const frame_processor_device_ptr& frame_processor) \r
151         : impl_(new implementation(frame_processor)){}\r
152 void frame_producer_device::load(int render_layer, const frame_producer_ptr& producer, load_option::type option){impl_->load(render_layer, producer, option);}\r
153 void frame_producer_device::pause(int render_layer){impl_->pause(render_layer);}\r
154 void frame_producer_device::play(int render_layer){impl_->play(render_layer);}\r
155 void frame_producer_device::stop(int render_layer){impl_->stop(render_layer);}\r
156 void frame_producer_device::clear(int render_layer){impl_->clear(render_layer);}\r
157 void frame_producer_device::clear(){impl_->clear();}\r
158 frame_producer_ptr frame_producer_device::foreground(int render_layer) const {return impl_->foreground(render_layer);}\r
159 frame_producer_ptr frame_producer_device::background(int render_layer) const {return impl_->background(render_layer);}\r
160 }}\r