1 /*
2  * This file is part of bino, a 3D video player.
3  *
4  * Copyright (C) 2010, 2011, 2012, 2015, 2016
5  * Martin Lambers <marlam@marlam.de>
6  * Frédéric Devernay <Frederic.Devernay@inrialpes.fr>
7  * Joe <cuchac@email.cz>
8  * Binocle <http://binocle.com> (author: Olivier Letz <oletz@binocle.com>)
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  */
23 
24 #ifndef VIDEO_OUTPUT_H
25 #define VIDEO_OUTPUT_H
26 
27 #include <vector>
28 #include <string>
29 
30 #include <GL/glew.h>
31 
32 #include "base/blb.h"
33 
34 #include "media_data.h"
35 #include "subtitle_renderer.h"
36 #include "dispatch.h"
37 
38 
39 class subtitle_updater;
40 #if HAVE_LIBXNVCTRL
41 class CNvSDIout;
42 #endif // HAVE_LIBXNVCTRL
43 
44 class video_output : public controller
45 {
46 private:
47     bool _initialized;
48 
49     /* We manage two frames, each with its own set of properties etc.
50      * The active frame is the one that is displayed, the other frame is the one
51      * that is prepared for display.
52      * Each frame contains a left view and may contain a right view. */
53     int _active_index;                                  // 0 or 1
54 
55     video_frame _frame[2];              // input frames (active / preparing)
56     // Step 1: input of video data
57     video_frame _input_last_frame;      // last frame for this step
58     GLuint _input_pbo;                  // pixel-buffer object for texture uploading
59     GLuint _input_fbo;                  // frame-buffer object for texture clearing
60     GLuint _input_yuv_y_tex[2];         // for yuv formats: y component
61     GLuint _input_yuv_u_tex[2];         // for yuv formats: u component
62     GLuint _input_yuv_v_tex[2];         // for yuv formats: v component
63     GLuint _input_bgra32_tex[2];        // for bgra32 format
64     int _input_yuv_chroma_width_divisor;        // for yuv formats: chroma subsampling
65     int _input_yuv_chroma_height_divisor;       // for yuv formats: chroma subsampling
66     subtitle_box _subtitle[2];          // the current subtitle box
67     GLuint _subtitle_tex[2];            // subtitle texture
68     bool _subtitle_tex_current[2];      // whether the subtitle tex contains the current subtitle buffer
69     // Step 2: color space conversion and color correction
70     parameters _color_last_params[2];   // last params for this step; used for reinitialization check
71     video_frame _color_last_frame[2];   // last frame for this step; used for reinitialization check
72     GLuint _color_prg[2];               // color space transformation, color adjustment
73     GLuint _color_fbo;                  // framebuffer object to render into the sRGB texture
74     GLuint _color_tex[2][2];            // output: SRGB8 or linear RGB16 texture
75     // Step 3: rendering
76     parameters _render_params;          // current parameters for display
77     parameters _render_last_params;     // last params for this step; used for reinitialization check
78     video_frame _render_last_frame;     // last frame for this step; used for reinitialization check
79     GLuint _render_prg;                 // reads sRGB texture, renders according to _params[_active_index]
80     GLuint _render_dummy_tex;           // an empty subtitle texture
81     GLuint _render_mask_tex;            // for the masking modes even-odd-{rows,columns}, checkerboard
82     blob _3d_ready_sync_buf;            // for 3-D Ready Sync pixels
83     // OpenGL viewports and tex coordinates for drawing the two views of the video frame
84     GLint _full_viewport[4];
85     GLint _viewport[2][4];
86     float _tex_coords[2][4][2];
87 
88     subtitle_updater *_subtitle_updater;        // the subtitle updater thread
89 #if HAVE_LIBXNVCTRL
90     CNvSDIout *_nv_sdi_output;          // access the nvidia quadro sdi output card
91     int64_t _last_nv_sdi_displayed_frameno;
92 #endif // HAVE_LIBXNVCTRL
93 
94     // GL Helper functions
95     bool xglCheckError(const std::string& where = std::string()) const;
96     bool xglCheckFBO(const std::string& where = std::string()) const;
97     GLuint xglCompileShader(const std::string& name, GLenum type, const std::string& src) const;
98     GLuint xglCreateProgram(GLuint vshader, GLuint fshader) const;
99     GLuint xglCreateProgram(const std::string& name,
100             const std::string& vshader_src, const std::string& fshader_src) const;
101     void xglLinkProgram(const std::string& name, const GLuint prg) const;
102     void xglDeleteProgram(GLuint prg) const;
103 
104     bool srgb8_textures_are_color_renderable();
105 
106     void draw_quad(float x, float y, float w, float h,
107             const float tex_coords[2][4][2] = NULL,
108             const float more_tex_coords[4][2] = NULL) const;
109 
110     // Step 1: initialize/deinitialize, and check if reinitialization is necessary
111     void input_init(const video_frame &frame);
112     void input_deinit();
113     bool input_is_compatible(const video_frame &current_frame);
114     void subtitle_init(int index);
115     void subtitle_deinit(int index);
116     // Step 2: initialize/deinitialize, and check if reinitialization is necessary
117     void color_init(int index, const parameters& params, const video_frame &frame);
118     void color_deinit(int index);
119     bool color_is_compatible(int index, const parameters& params, const video_frame &current_frame);
120     // Step 3: initialize/deinitialize, and check if reinitialization is necessary
121     void render_init();
122     void render_deinit();
123     bool render_needs_subtitle(const parameters& params);
124     bool render_needs_coloradjust(const parameters& params);
125     bool render_needs_ghostbust(const parameters& params);
126     bool render_is_compatible();
127 
128 protected:
129     subtitle_renderer _subtitle_renderer;
130 
131 #ifdef GLEW_MX
132     virtual GLEWContext* glewGetContext() const = 0;
133 #endif
134 
135     // Get the total viewport size.
136     int full_display_width() const;
137     int full_display_height() const;
138     // Get size of the viewport area that is used for video. This is overridable for Equalizer.
139     virtual int video_display_width() const;
140     virtual int video_display_height() const;
141 
142     virtual bool context_is_stereo() const = 0; // Is our current OpenGL context a stereo context?
143     virtual void recreate_context(bool stereo) = 0;     // Recreate an OpenGL context and make it current
144     virtual void trigger_resize(int w, int h) = 0;      // Trigger a resize the video area
145 
146     void clear() const;                         // Clear the video area
147     void reshape(int w, int h, const parameters& params = dispatch::parameters());       // Call this when the video area was resized
148 
149     /* Get screen properties (fixed) */
150     virtual int screen_width() const = 0;       // in pixels
151     virtual int screen_height() const = 0;      // in pixels
152     virtual float screen_pixel_aspect_ratio() const = 0;// the aspect ratio of a pixel on screen
153 
154     /* Get current video area properties */
155     virtual int width() const = 0;              // in pixels
156     virtual int height() const = 0;             // in pixels
157     virtual int pos_x() const = 0;              // in pixels
158     virtual int pos_y() const = 0;              // in pixels
159 
160     /* Display the current frame.
161      * The first version is used by Equalizer, which needs to set some special properties.
162      * The second version is used by NVIDIA SDI output.
163      * The third version is for everyone else.
164      * TODO: This function needs to handle interlaced frames! */
165     void display_current_frame(int64_t display_frameno, bool keep_viewport, bool mono_right_instead_of_left,
166             float x, float y, float w, float h,
167             const GLint viewport[2][4], const float tex_coords[2][4][2],
168             int dst_width, int dst_height,
169             parameters::stereo_mode_t stereo_mode);
display_current_frame(int64_t display_frameno,int dst_width,int dst_height,parameters::stereo_mode_t stereo_mode)170     void display_current_frame(int64_t display_frameno, int dst_width, int dst_height, parameters::stereo_mode_t stereo_mode)
171     {
172         display_current_frame(display_frameno, false, false, -1.0f, -1.0f, 2.0f, 2.0f,
173                 _viewport, _tex_coords, dst_width, dst_height, stereo_mode);
174     }
175     void display_current_frame(int64_t display_frameno = 0)
176     {
177         display_current_frame(display_frameno, false, false, -1.0f, -1.0f, 2.0f, 2.0f,
178                 _viewport, _tex_coords, full_display_width(), full_display_height(),
179                 dispatch::parameters().stereo_mode());
180     }
181 
182 #if HAVE_LIBXNVCTRL
183     void sdi_output(int64_t display_frameno = 0);
184 #endif // HAVE_LIBXNVCTRL
185 
186 public:
187     /* Constructor, Destructor */
188     video_output();
189     virtual ~video_output();
190 
191     /* Initialize the video output, or throw an exception */
192     virtual void init();
193     /* Wait for subtitle renderer initialization to finish. Has to be called
194      * if the video has subtitles. Returns the number of microseconds that the
195      * waiting took. */
196     virtual int64_t wait_for_subtitle_renderer() = 0;
197     /* Deinitialize the video output */
198     virtual void deinit();
199 
200     /* Set a video area size suitable for the given input/output settings */
201     void set_suitable_size(int w, int h, float ar, parameters::stereo_mode_t stereo_mode);
202 
203     /* Get capabilities */
204     virtual bool supports_stereo() const = 0;           // Is OpenGL quad buffered stereo available?
205 
206     /* Center video area on screen */
207     virtual void center() = 0;
208 
209     /* Enter/exit fullscreen mode */
210     virtual void enter_fullscreen() = 0;
211     virtual void exit_fullscreen() = 0;
212 
213     /* Process window system events (if applicable) */
214     virtual void process_events() = 0;
215 
216     /* Prepare a new frame for display. */
217     virtual void prepare_next_frame(const video_frame &frame, const subtitle_box &subtitle);
218     /* Switch to the next frame (make it the current one) */
219     virtual void activate_next_frame();
220     /* Get an estimation of when the next frame will appear on screen */
221     virtual int64_t time_to_next_frame_presentation() const;
222 };
223 
224 #endif
225