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
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2020, Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*
* YUV_packed.frag - Fragment shader code for YUYV packed formats
*/
#ifdef GL_ES
precision mediump float;
#endif
varying vec2 textureOut;
uniform sampler2D tex_y;
uniform vec2 tex_step;
void main(void)
{
mat3 yuv2rgb_bt601_mat = mat3(
vec3(1.164, 1.164, 1.164),
vec3(0.000, -0.392, 2.017),
vec3(1.596, -0.813, 0.000)
);
vec3 yuv2rgb_bt601_offset = vec3(0.063, 0.500, 0.500);
/*
* The sampler won't interpolate the texture correctly along the X axis,
* as each RGBA pixel effectively stores two pixels. We thus need to
* interpolate manually.
*
* In integer texture coordinates, the Y values are layed out in the
* texture memory as follows:
*
* ...| Y U Y V | Y U Y V | Y U Y V |...
* ...| R G B A | R G B A | R G B A |...
* ^ ^ ^ ^ ^ ^
* | | | | | |
* n-1 n-0.5 n n+0.5 n+1 n+1.5
*
* For a texture location x in the interval [n, n+1[, sample the left
* and right pixels at n and n+1, and interpolate them with
*
* left.r * (1 - a) + left.b * a if fract(x) < 0.5
* left.b * (1 - a) + right.r * a if fract(x) >= 0.5
*
* with a = fract(x * 2) which can also be written
*
* a = fract(x) * 2 if fract(x) < 0.5
* a = fract(x) * 2 - 1 if fract(x) >= 0.5
*/
vec2 pos = textureOut;
float f_x = fract(pos.x / tex_step.x);
vec4 left = texture2D(tex_y, vec2(pos.x - f_x * tex_step.x, pos.y));
vec4 right = texture2D(tex_y, vec2(pos.x + (1.0 - f_x) * tex_step.x , pos.y));
#if defined(YUV_PATTERN_UYVY)
float y_left = mix(left.g, left.a, f_x * 2.0);
float y_right = mix(left.a, right.g, f_x * 2.0 - 1.0);
vec2 uv = mix(left.rb, right.rb, f_x);
#elif defined(YUV_PATTERN_VYUY)
float y_left = mix(left.g, left.a, f_x * 2.0);
float y_right = mix(left.a, right.g, f_x * 2.0 - 1.0);
vec2 uv = mix(left.br, right.br, f_x);
#elif defined(YUV_PATTERN_YUYV)
float y_left = mix(left.r, left.b, f_x * 2.0);
float y_right = mix(left.b, right.r, f_x * 2.0 - 1.0);
vec2 uv = mix(left.ga, right.ga, f_x);
#elif defined(YUV_PATTERN_YVYU)
float y_left = mix(left.r, left.b, f_x * 2.0);
float y_right = mix(left.b, right.r, f_x * 2.0 - 1.0);
vec2 uv = mix(left.ag, right.ag, f_x);
#else
#error Invalid pattern
#endif
float y = mix(y_left, y_right, step(0.5, f_x));
vec3 rgb = yuv2rgb_bt601_mat * (vec3(y, uv) - yuv2rgb_bt601_offset);
gl_FragColor = vec4(rgb, 1.0);
}
|