Release Movit 1.3.2. (From a branch, since I do not want to break ABI compatibility...
[movit] / deinterlace_effect.cpp
1 #include <epoxy/gl.h>
2
3 #include "deinterlace_effect.h"
4 #include "util.h"
5
6 using namespace std;
7
8 namespace movit {
9
10 DeinterlaceEffect::DeinterlaceEffect()
11         : enable_spatial_interlacing_check(true),
12           current_field_position(TOP),
13           num_lines(1080)
14 {
15         register_int("enable_spatial_interlacing_check", (int *)&enable_spatial_interlacing_check);
16         register_int("current_field_position", (int *)&current_field_position);
17         register_uniform_float("num_lines", &num_lines);
18         register_uniform_float("inv_width", &inv_width);
19         register_uniform_float("self_offset", &self_offset);
20         register_uniform_float_array("current_offset", current_offset, 2);
21         register_uniform_float_array("other_offset", other_offset, 3);
22 }
23
24 string DeinterlaceEffect::output_fragment_shader()
25 {
26         char buf[256];
27         snprintf(buf, sizeof(buf), "#define YADIF_ENABLE_SPATIAL_INTERLACING_CHECK %d\n",
28                 enable_spatial_interlacing_check);
29         string frag_shader = buf;
30
31         frag_shader += read_file("deinterlace_effect.frag");
32         return frag_shader;
33 }
34
35 void DeinterlaceEffect::inform_input_size(unsigned input_num, unsigned width, unsigned height)
36 {
37         assert(input_num >= 0 && input_num < 5);
38         widths[input_num] = width;
39         heights[input_num] = height;
40         num_lines = height * 2;
41 }
42
43 void DeinterlaceEffect::get_output_size(unsigned *width, unsigned *height,
44                                         unsigned *virtual_width, unsigned *virtual_height) const
45 {
46         assert(widths[0] == widths[1]);
47         assert(widths[1] == widths[2]);
48         assert(widths[2] == widths[3]);
49         assert(widths[3] == widths[4]);
50         assert(heights[0] == heights[1]);
51         assert(heights[1] == heights[2]);
52         assert(heights[2] == heights[3]);
53         assert(heights[3] == heights[4]);
54         *width = *virtual_width = widths[0];
55         *height = *virtual_height = heights[0] * 2;
56 }
57
58 void DeinterlaceEffect::set_gl_state(GLuint glsl_program_num, const string &prefix, unsigned *sampler_num)
59 {
60         Effect::set_gl_state(glsl_program_num, prefix, sampler_num);
61
62         inv_width = 1.0 / widths[0];
63
64         // Texel centers: t = output texel center for top field, b = for bottom field,
65         // x = the input texel. (The same area is two pixels for output, one for input;
66         // thus the stippled line in the middle.)
67         //
68         // +---------+
69         // |         |
70         // |    t    |
71         // |         |
72         // | - -x- - |
73         // |         |
74         // |    b    |
75         // |         |
76         // +---------+
77         //
78         // Note as usual OpenGL's bottom-left convention.
79         if (current_field_position == 0) {
80                 // Top.
81                 self_offset = -0.5 / num_lines;
82         } else {
83                 // Bottom.
84                 assert(current_field_position == 1);
85                 self_offset = 0.5 / num_lines;
86         }
87
88         // Having now established where the texels lie for the uninterpolated samples,
89         // we can use that to figure out where to sample for the interpolation. Drawing
90         // the fields as what lines they represent, here for three-pixel high fields
91         // with current_field_position == 0 (plus an ā€œoā€ to mark the pixel we're trying
92         // to interpolate, and ā€œcā€ for corresponding texel in the other field):
93         //
94         // Prev Cur Next
95         //       x
96         //   x       x
97         //       x
98         //   c   o   c
99         //       x
100         //   x       x
101         //
102         // Obviously, for sampling in the current field, we are one half-texel off
103         // compared to <self_offset>, so sampling in the current field is easy:
104         current_offset[0] = self_offset - 0.5 / heights[0];
105         current_offset[1] = self_offset + 0.5 / heights[0];
106
107         // Now to find the texel in the other fields corresponding to the pixel
108         // we're trying to interpolate, let's realign the diagram above:
109         //
110         // Prev Cur Next
111         //   x   x   x
112         //
113         //   c   x   c
114         //       o
115         //   x   x   x
116         //
117         // So obviously for this case, we need to center on the same place as
118         // current_offset[1] (the texel directly above the o; note again the
119         // bottom-left convention). For the case of current_field_position == 1,
120         // the shift in the alignment goes the other way, and what we want
121         // is current_offset[0] (the texel directly below the o).
122         float center_offset = current_offset[1 - current_field_position];
123         other_offset[0] = center_offset - 1.0 / heights[0];
124         other_offset[1] = center_offset;
125         other_offset[2] = center_offset + 1.0 / heights[0];
126 }
127
128 }  // namespace movit