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