2 * copyright (c) 2010 Sveriges Television AB <info@casparcg.com>
\r
4 * This file is part of CasparCG.
\r
6 * CasparCG is free software: you can redistribute it and/or modify
\r
7 * it under the terms of the GNU General Public License as published by
\r
8 * the Free Software Foundation, either version 3 of the License, or
\r
9 * (at your option) any later version.
\r
11 * CasparCG is distributed in the hope that it will be useful,
\r
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 * GNU General Public License for more details.
\r
16 * You should have received a copy of the GNU General Public License
\r
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
\r
21 #include "../../StdAfx.h"
\r
23 #include "ogl_consumer.h"
\r
25 #include "../../video/video_format.h"
\r
26 #include "../../processor/frame.h"
\r
27 #include "../../../common/utility/memory.h"
\r
28 #include "../../../common/gl/utility.h"
\r
29 #include "../../../common/gl/pixel_buffer_object.h"
\r
31 #include <boost/thread.hpp>
\r
34 #include <SFML/Window.hpp>
\r
36 #include <windows.h>
\r
38 namespace caspar { namespace core { namespace ogl{
\r
40 struct consumer::implementation : boost::noncopyable
\r
42 implementation(const video_format_desc& format_desc, unsigned int screen_index, stretch stretch, bool windowed)
\r
43 : index_(0), format_desc_(format_desc), stretch_(stretch), screen_width_(0), screen_height_(0), windowed_(windowed)
\r
46 DISPLAY_DEVICE dDevice;
\r
47 memset(&dDevice,0,sizeof(dDevice));
\r
48 dDevice.cb = sizeof(dDevice);
\r
50 std::vector<DISPLAY_DEVICE> displayDevices;
\r
51 for(int n = 0; EnumDisplayDevices(NULL, n, &dDevice, NULL); ++n)
\r
53 displayDevices.push_back(dDevice);
\r
54 memset(&dDevice,0,sizeof(dDevice));
\r
55 dDevice.cb = sizeof(dDevice);
\r
58 if(screen_index >= displayDevices.size())
\r
59 BOOST_THROW_EXCEPTION(out_of_range() << arg_name_info("screen_index_"));
\r
62 memset(&devmode,0,sizeof(devmode));
\r
64 if(!EnumDisplaySettings(displayDevices[screen_index].DeviceName, ENUM_CURRENT_SETTINGS, &devmode))
\r
65 BOOST_THROW_EXCEPTION(invalid_operation() << arg_name_info("screen_index") << msg_info("EnumDisplaySettings"));
\r
67 screen_width_ = windowed ? format_desc_.width : devmode.dmPelsWidth;
\r
68 screen_height_ = windowed ? format_desc_.height : devmode.dmPelsHeight;
\r
69 screenX_ = devmode.dmPosition.x;
\r
70 screenY_ = devmode.dmPosition.y;
\r
73 BOOST_THROW_EXCEPTION(not_supported() << msg_info("OGLConsumer doesn't support non-Win32 fullscreen"));
\r
75 if(screen_index != 0)
\r
76 CASPAR_LOG(warning) << "OGLConsumer only supports screen_index=0 for non-Win32";
\r
78 screen_width_ = format_desc_.width;
\r
79 screen_height_ = format_desc_.height;
\r
83 frame_buffer_.set_capacity(1);
\r
84 thread_ = boost::thread([=]{run();});
\r
89 frame_buffer_.push(nullptr),
\r
95 window_.Create(sf::VideoMode(format_desc_.width, format_desc_.height, 32), "CasparCG", windowed_ ? sf::Style::Titlebar : sf::Style::Fullscreen);
\r
96 window_.ShowMouseCursor(false);
\r
97 window_.SetPosition(screenX_, screenY_);
\r
98 window_.SetSize(screen_width_, screen_height_);
\r
99 window_.SetActive();
\r
100 GL(glEnable(GL_TEXTURE_2D));
\r
101 GL(glDisable(GL_DEPTH_TEST));
\r
102 GL(glClearColor(0.0, 0.0, 0.0, 0.0));
\r
103 GL(glViewport(0, 0, format_desc_.width, format_desc_.height));
\r
106 wratio_ = static_cast<float>(format_desc_.width)/static_cast<float>(format_desc_.width);
\r
107 hratio_ = static_cast<float>(format_desc_.height)/static_cast<float>(format_desc_.height);
\r
109 std::pair<float, float> target_ratio = None();
\r
110 if(stretch_ == ogl::fill)
\r
111 target_ratio = Fill();
\r
112 else if(stretch_ == ogl::uniform)
\r
113 target_ratio = Uniform();
\r
114 else if(stretch_ == ogl::uniform_to_fill)
\r
115 target_ratio = UniformToFill();
\r
117 wSize_ = target_ratio.first;
\r
118 hSize_ = target_ratio.second;
\r
120 pbos_[0].create(format_desc_.width, format_desc_.height);
\r
121 pbos_[1].create(format_desc_.width, format_desc_.height);
\r
124 std::pair<float, float> None()
\r
126 float width = static_cast<float>(format_desc_.width)/static_cast<float>(screen_width_);
\r
127 float height = static_cast<float>(format_desc_.height)/static_cast<float>(screen_height_);
\r
129 return std::make_pair(width, height);
\r
132 std::pair<float, float> Uniform()
\r
134 float aspect = static_cast<float>(format_desc_.width)/static_cast<float>(format_desc_.height);
\r
135 float width = std::min(1.0f, static_cast<float>(screen_height_)*aspect/static_cast<float>(screen_width_));
\r
136 float height = static_cast<float>(screen_width_*width)/static_cast<float>(screen_height_*aspect);
\r
138 return std::make_pair(width, height);
\r
141 std::pair<float, float> Fill()
\r
143 return std::make_pair(1.0f, 1.0f);
\r
146 std::pair<float, float> UniformToFill()
\r
148 float wr = static_cast<float>(format_desc_.width)/static_cast<float>(screen_width_);
\r
149 float hr = static_cast<float>(format_desc_.height)/static_cast<float>(screen_height_);
\r
150 float r_inv = 1.0f/std::min(wr, hr);
\r
152 float width = wr*r_inv;
\r
153 float height = hr*r_inv;
\r
155 return std::make_pair(width, height);
\r
158 void render(const frame_ptr& frame)
\r
160 index_ = (index_ + 1) % 2;
\r
161 int next_index = (index_ + 1) % 2;
\r
163 auto ptr = pbos_[index_].end_write();
\r
164 common::aligned_parallel_memcpy(ptr, frame->data(), format_desc_.size);
\r
166 GL(glClear(GL_COLOR_BUFFER_BIT));
\r
167 pbos_[next_index].bind_texture();
\r
169 glTexCoord2f(0.0f, hratio_); glVertex2f(-wSize_, -hSize_);
\r
170 glTexCoord2f(wratio_, hratio_); glVertex2f( wSize_, -hSize_);
\r
171 glTexCoord2f(wratio_, 0.0f); glVertex2f( wSize_, hSize_);
\r
172 glTexCoord2f(0.0f, 0.0f); glVertex2f(-wSize_, hSize_);
\r
175 pbos_[next_index].begin_write();
\r
178 void display(const frame_ptr& frame)
\r
180 if(frame == nullptr)
\r
183 if(exception_ != nullptr)
\r
184 std::rethrow_exception(exception_);
\r
186 frame_buffer_.push(frame);
\r
198 frame_buffer_.pop(frame);
\r
199 if(frame != nullptr)
\r
202 while(window_.GetEvent(e)){}
\r
203 window_.SetActive();
\r
210 exception_ = std::current_exception();
\r
213 while(frame != nullptr);
\r
223 common::gl::pixel_buffer_object pbos_[2];
\r
226 unsigned int screen_width_;
\r
227 unsigned int screen_height_;
\r
228 unsigned int screenX_;
\r
229 unsigned int screenY_;
\r
232 video_format_desc format_desc_;
\r
234 std::exception_ptr exception_;
\r
235 boost::thread thread_;
\r
236 tbb::concurrent_bounded_queue<frame_ptr> frame_buffer_;
\r
238 sf::Window window_;
\r
241 consumer::consumer(const video_format_desc& format_desc, unsigned int screen_index, stretch stretch, bool windowed)
\r
242 : impl_(new implementation(format_desc, screen_index, stretch, windowed)){}
\r
243 void consumer::display(const frame_ptr& frame){impl_->display(frame);}
\r