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