]> git.sesse.net Git - casparcg/blob - core/processor/frame_processor_device.cpp
ea3d2237bda65b3a1a7aae26cbfbd1cf721f7646
[casparcg] / core / processor / frame_processor_device.cpp
1 #include "../StdAfx.h"\r
2 \r
3 #include "frame_processor_device.h"\r
4 \r
5 #include "frame_renderer.h"\r
6 #include "frame.h"\r
7 #include "composite_frame.h"\r
8 \r
9 #include "../video/video_format.h"\r
10 \r
11 #include "../../common/exception/exceptions.h"\r
12 #include "../../common/concurrency/executor.h"\r
13 #include "../../common/gl/utility.h"\r
14 \r
15 #include <Glee.h>\r
16 #include <SFML/Window.hpp>\r
17 \r
18 #include <tbb/concurrent_queue.h>\r
19 #include <tbb/concurrent_unordered_map.h>\r
20 #include <tbb/concurrent_vector.h>\r
21 \r
22 #include <boost/range/algorithm.hpp>\r
23 #include <boost/thread.hpp>\r
24 \r
25 #include <functional>\r
26 \r
27 namespace caspar { namespace core {\r
28         \r
29 struct frame_processor_device::implementation : boost::noncopyable\r
30 {       \r
31         implementation(frame_processor_device* self, const video_format_desc& format_desc) \r
32                 : fmt_(format_desc)\r
33         {               \r
34                 boost::promise<frame_ptr> promise;\r
35                 active_frame_ = promise.get_future();\r
36                 promise.set_value(nullptr);\r
37 \r
38                 input_.set_capacity(2);\r
39                 output_.set_capacity(2);\r
40                 executor_.start();\r
41                 executor_.invoke([=]\r
42                 {\r
43                         ogl_context_.reset(new sf::Context());\r
44                         ogl_context_->SetActive(true);\r
45                         GL(glEnable(GL_POLYGON_STIPPLE));\r
46                         GL(glEnable(GL_TEXTURE_2D));\r
47                         GL(glEnable(GL_BLEND));\r
48                         GL(glDisable(GL_DEPTH_TEST));\r
49                         GL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));                  \r
50                         GL(glClearColor(0.0, 0.0, 0.0, 0.0));\r
51                         GL(glViewport(0, 0, format_desc.width, format_desc.height));\r
52                         glLoadIdentity();   \r
53 \r
54                         renderer_ = std::make_shared<frame_renderer>(*self, format_desc);\r
55                 });\r
56         }\r
57 \r
58         ~implementation()\r
59         {\r
60                 executor_.stop();\r
61         }\r
62                                         \r
63         frame_ptr create_frame(const pixel_format_desc& desc, void* tag)\r
64         {\r
65                 size_t key = reinterpret_cast<size_t>(tag);\r
66                 auto& pool = writing_pools_[key];\r
67                 \r
68                 frame_ptr my_frame;\r
69                 if(!pool.try_pop(my_frame))\r
70                 {\r
71                         my_frame = executor_.invoke([&]\r
72                         {\r
73                                 return std::shared_ptr<frame>(new frame(desc));\r
74                         });\r
75                 }\r
76                 \r
77                 auto destructor = [=]\r
78                 {\r
79                         my_frame->reset();\r
80                         writing_pools_[key].push(my_frame);\r
81                 };\r
82 \r
83                 return frame_ptr(my_frame.get(), [=](frame*)                                                    \r
84                 {\r
85                         executor_.begin_invoke(destructor);\r
86                 });\r
87         }\r
88 \r
89         void release_tag(void* tag)\r
90         {\r
91                 writing_pools_[reinterpret_cast<size_t>(tag)].clear();\r
92         }\r
93         \r
94         void send(const frame_ptr& input_frame)\r
95         {                       \r
96                 input_.push(input_frame);\r
97                 executor_.begin_invoke([=]\r
98                 {\r
99                         try\r
100                         {\r
101                                 frame_ptr output_frame;\r
102                                 input_.pop(output_frame);\r
103                                 output_.push(renderer_->render(output_frame));\r
104                         }\r
105                         catch(...)\r
106                         {\r
107                                 CASPAR_LOG_CURRENT_EXCEPTION();\r
108                         }\r
109                 });     \r
110         }\r
111 \r
112         void receive(frame_ptr& output_frame)\r
113         {\r
114                 output_.pop(output_frame);\r
115         }\r
116 \r
117         bool try_receive(frame_ptr& output_frame)\r
118         {\r
119                 return output_.try_pop(output_frame);\r
120         }\r
121         \r
122         video_format_desc fmt_;\r
123                                 \r
124         typedef tbb::concurrent_bounded_queue<frame_ptr> frame_queue;\r
125         tbb::concurrent_unordered_map<size_t, frame_queue> writing_pools_;\r
126         frame_queue reading_pool_;      \r
127                                 \r
128         std::unique_ptr<sf::Context> ogl_context_;\r
129 \r
130         boost::unique_future<frame_ptr> active_frame_;\r
131         \r
132         common::executor executor_;\r
133         \r
134         frame_queue input_;\r
135         frame_queue output_;    \r
136 \r
137         frame_renderer_ptr renderer_;\r
138 };\r
139         \r
140 #if defined(_MSC_VER)\r
141 #pragma warning (disable : 4355) // 'this' : used in base member initializer list\r
142 #endif\r
143 \r
144 frame_processor_device::frame_processor_device(const video_format_desc& format_desc) \r
145         : impl_(new implementation(this, format_desc)){}\r
146 frame_ptr frame_processor_device::create_frame(const  pixel_format_desc& desc, void* tag){return impl_->create_frame(desc, tag);}\r
147 void frame_processor_device::release_tag(void* tag){impl_->release_tag(tag);}\r
148 void frame_processor_device::send(const frame_ptr& frame){impl_->send(frame);}\r
149 void frame_processor_device::receive(frame_ptr& frame){impl_->receive(frame);}\r
150 bool frame_processor_device::try_receive(frame_ptr& frame){return impl_->try_receive(frame);}\r
151 const video_format_desc frame_processor_device::get_video_format_desc() const { return impl_->fmt_;}\r
152 frame_ptr frame_processor_device::create_frame(size_t width, size_t height, void* tag)\r
153 {\r
154         pixel_format_desc desc;\r
155         desc.pix_fmt = pixel_format::bgra;\r
156         desc.planes[0] = pixel_format_desc::plane(width, height, 4);\r
157         return create_frame(desc, tag);\r
158 }\r
159                         \r
160 frame_ptr frame_processor_device::create_frame(void* tag)\r
161 {\r
162         pixel_format_desc desc;\r
163         desc.pix_fmt = pixel_format::bgra;\r
164         desc.planes[0] = pixel_format_desc::plane(get_video_format_desc().width, get_video_format_desc().height, 4);\r
165         return create_frame(desc, tag);\r
166 }\r
167 }}