]> git.sesse.net Git - casparcg/blob - core/processor/frame.cpp
a4dd0406fd6ce802188a778f64eaea2aed5a00df
[casparcg] / core / processor / frame.cpp
1 #include "../StdAfx.h"\r
2 \r
3 #include "frame.h"\r
4 #include "../format/pixel_format.h"\r
5 #include "../../common/utility/memory.h"\r
6 #include "../../common/gl/utility.h"\r
7 #include "../../common/gl/pixel_buffer_object.h"\r
8 \r
9 #include <boost/range/algorithm.hpp>\r
10 \r
11 namespace caspar { namespace core {\r
12         \r
13 struct rectangle\r
14 {\r
15         rectangle(double left, double top, double right, double bottom)\r
16                 : left(left), top(top), right(right), bottom(bottom)\r
17         {}\r
18         double left;\r
19         double top;\r
20         double right;\r
21         double bottom;\r
22 };\r
23 \r
24 GLubyte progressive_pattern[] = {\r
25         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
26         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
27         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
28         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
29         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
30         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
31         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
32         0xff, 0xff, 0xFF, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\r
33         \r
34 GLubyte upper_pattern[] = {\r
35         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
36         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
37         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
38         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
39         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
40         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
41         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
42         0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00};\r
43                 \r
44 GLubyte lower_pattern[] = {\r
45         0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, \r
46         0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, \r
47         0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, \r
48         0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,\r
49         0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,\r
50         0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,\r
51         0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,\r
52         0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff};\r
53                                                                                                                                                                                                                                                                                                                 \r
54 struct frame::implementation : boost::noncopyable\r
55 {\r
56         implementation(size_t width, size_t height)\r
57                 : alpha_(1.0f), x_(0.0f), y_(0.0f), update_fmt_(video_update_format::progressive), texcoords_(0.0, 1.0, 1.0, 0.0), pixel_data_(4, nullptr)\r
58         {       \r
59                 desc_.planes[0] = pixel_format_desc::plane(width, height, 4);\r
60                 desc_.pix_fmt = pixel_format::bgra;\r
61                 pixel_data_.resize(4, 0);\r
62                 if(width >= 2 && height >= 2)\r
63                 {\r
64                         pbo_.push_back(std::make_shared<common::gl::pixel_buffer_object>(width, height, GL_BGRA));\r
65                         end_write();\r
66                 }\r
67         }\r
68 \r
69         implementation(const pixel_format_desc& desc)\r
70                 : alpha_(1.0f), x_(0.0f), y_(0.0f), update_fmt_(video_update_format::progressive), texcoords_(0.0, 1.0, 1.0, 0.0), pixel_data_(4, nullptr)\r
71         {                       \r
72                 desc_ = desc;\r
73 \r
74                 for(size_t n = 0; n < desc_.planes.size(); ++n)\r
75                 {\r
76                         if(desc_.planes[n].size == 0)\r
77                                 break;\r
78 \r
79                         GLuint format = [&]() -> GLuint\r
80                         {\r
81                                 switch(desc_.planes[n].channels)\r
82                                 {\r
83                                 case 1: return GL_LUMINANCE;\r
84                                 case 2: return GL_LUMINANCE_ALPHA;\r
85                                 case 3: return GL_BGR;\r
86                                 case 4: return GL_BGRA;\r
87                                 default: BOOST_THROW_EXCEPTION(out_of_range() << msg_info("1-4 channels are supported") << arg_name_info("desc.planes.channels")); \r
88                                 }\r
89                         }();\r
90 \r
91                         pbo_.push_back(std::make_shared<common::gl::pixel_buffer_object>(desc_.planes[n].width, desc_.planes[n].height, format));\r
92                 }\r
93                 end_write();\r
94         }\r
95         \r
96         void begin_write()\r
97         {\r
98                 pixel_data_ = std::vector<void*>(4, 0);\r
99                 boost::range::for_each(pbo_, std::mem_fn(&common::gl::pixel_buffer_object::begin_write));\r
100         }\r
101 \r
102         void end_write()\r
103         {\r
104                 boost::range::transform(pbo_, pixel_data_.begin(), std::mem_fn(&common::gl::pixel_buffer_object::end_write));\r
105         }\r
106         \r
107         void begin_read()\r
108         {       \r
109                 pixel_data_ = std::vector<void*>(4, 0);\r
110                 boost::range::for_each(pbo_, std::mem_fn(&common::gl::pixel_buffer_object::begin_read));\r
111         }\r
112 \r
113         void end_read()\r
114         {\r
115                 boost::range::transform(pbo_, pixel_data_.begin(), std::mem_fn(&common::gl::pixel_buffer_object::end_read));\r
116         }\r
117 \r
118         void draw(const frame_shader_ptr& shader)\r
119         {\r
120                 shader->use(desc_);\r
121                 glPushMatrix();\r
122                 glTranslated(x_*2.0, y_*2.0, 0.0);\r
123                 glColor4d(1.0, 1.0, 1.0, alpha_);\r
124 \r
125                 if(update_fmt_ == video_update_format::progressive)\r
126                         glPolygonStipple(progressive_pattern);\r
127                 else if(update_fmt_ == video_update_format::upper)\r
128                         glPolygonStipple(upper_pattern);\r
129                 else if(update_fmt_ == video_update_format::lower)\r
130                         glPolygonStipple(lower_pattern);\r
131 \r
132                 for(size_t n = 0; n < pbo_.size(); ++n)\r
133                 {\r
134                         glActiveTexture(GL_TEXTURE0+n);\r
135                         pbo_[n]->bind_texture();\r
136                 }\r
137                 glBegin(GL_QUADS);\r
138                         glTexCoord2d(texcoords_.left,   texcoords_.bottom); glVertex2d(-1.0, -1.0);\r
139                         glTexCoord2d(texcoords_.right,  texcoords_.bottom); glVertex2d( 1.0, -1.0);\r
140                         glTexCoord2d(texcoords_.right,  texcoords_.top);        glVertex2d( 1.0,  1.0);\r
141                         glTexCoord2d(texcoords_.left,   texcoords_.top);        glVertex2d(-1.0,  1.0);\r
142                 glEnd();\r
143                 glPopMatrix();\r
144         }\r
145 \r
146         unsigned char* data(size_t index)\r
147         {\r
148                 if(pbo_.size() < index)\r
149                         BOOST_THROW_EXCEPTION(out_of_range());\r
150                 return static_cast<unsigned char*>(pixel_data_[index]);\r
151         }\r
152 \r
153         void reset()\r
154         {\r
155                 audio_data_.clear();\r
156                 alpha_          = 1.0f;\r
157                 x_                      = 0.0f;\r
158                 y_                      = 0.0f;\r
159                 texcoords_      = rectangle(0.0, 1.0, 1.0, 0.0);\r
160                 update_fmt_ = video_update_format::progressive;\r
161                 end_write();\r
162         }\r
163 \r
164         std::vector<common::gl::pixel_buffer_object_ptr> pbo_;\r
165         std::vector<void*> pixel_data_; \r
166         std::vector<short> audio_data_;\r
167 \r
168         double alpha_;\r
169         double x_;\r
170         double y_;\r
171         video_update_format::type update_fmt_;\r
172         rectangle texcoords_;\r
173 \r
174         pixel_format_desc desc_;\r
175 };\r
176 \r
177 frame::frame(size_t width, size_t height) \r
178         : impl_(new implementation(width, height)){}\r
179 frame::frame(const pixel_format_desc& desc)\r
180         : impl_(new implementation(desc)){}\r
181 void frame::draw(const frame_shader_ptr& shader){impl_->draw(shader);}\r
182 void frame::begin_write(){impl_->begin_write();}\r
183 void frame::end_write(){impl_->end_write();}    \r
184 void frame::begin_read(){impl_->begin_read();}\r
185 void frame::end_read(){impl_->end_read();}\r
186 void frame::pix_fmt(pixel_format::type format) {impl_->desc_.pix_fmt = format;}\r
187 unsigned char* frame::data(size_t index){return impl_->data(index);}\r
188 size_t frame::size(size_t index) const { return impl_->desc_.planes[index].size; }\r
189 std::vector<short>& frame::audio_data() { return impl_->audio_data_; }\r
190 void frame::reset(){impl_->reset();}\r
191 void frame::alpha(double value){ impl_->alpha_ = value;}\r
192 void frame::translate(double x, double y) { impl_->x_ += x; impl_->y_ += y; }\r
193 void frame::texcoords(double left, double top, double right, double bottom){impl_->texcoords_ = rectangle(left, top, right, bottom);}\r
194 void frame::update_fmt(video_update_format::type fmt){ impl_->update_fmt_ = fmt;}\r
195 double frame::x() const { return impl_->x_;}\r
196 double frame::y() const { return impl_->y_;}\r
197 }}