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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
|
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include shared
#define YUV_FORMAT_NV12 0
#define YUV_FORMAT_PLANAR 1
#define YUV_FORMAT_INTERLEAVED 2
#ifdef WR_VERTEX_SHADER
#ifdef WR_FEATURE_TEXTURE_RECT
#define TEX_SIZE(sampler) vec2(1.0)
#else
#define TEX_SIZE(sampler) vec2(textureSize(sampler, 0).xy)
#endif
#define YUV_COLOR_SPACE_REC601 0
#define YUV_COLOR_SPACE_REC709 1
#define YUV_COLOR_SPACE_REC2020 2
#define YUV_COLOR_SPACE_IDENTITY 3
// The constants added to the Y, U and V components are applied in the fragment shader.
// From Rec601:
// [R] [1.1643835616438356, 0.0, 1.5960267857142858 ] [Y - 16]
// [G] = [1.1643835616438358, -0.3917622900949137, -0.8129676472377708 ] x [U - 128]
// [B] [1.1643835616438356, 2.017232142857143, 8.862867620416422e-17] [V - 128]
//
// For the range [0,1] instead of [0,255].
//
// The matrix is stored in column-major.
const mat3 YuvColorMatrixRec601 = mat3(
1.16438, 1.16438, 1.16438,
0.0, -0.39176, 2.01723,
1.59603, -0.81297, 0.0
);
// From Rec709:
// [R] [1.1643835616438356, 0.0, 1.7927410714285714] [Y - 16]
// [G] = [1.1643835616438358, -0.21324861427372963, -0.532909328559444 ] x [U - 128]
// [B] [1.1643835616438356, 2.1124017857142854, 0.0 ] [V - 128]
//
// For the range [0,1] instead of [0,255]:
//
// The matrix is stored in column-major.
const mat3 YuvColorMatrixRec709 = mat3(
1.16438, 1.16438, 1.16438,
0.0 , -0.21325, 2.11240,
1.79274, -0.53291, 0.0
);
// From Re2020:
// [R] [1.16438356164384, 0.0, 1.678674107142860 ] [Y - 16]
// [G] = [1.16438356164384, -0.187326104219343, -0.650424318505057 ] x [U - 128]
// [B] [1.16438356164384, 2.14177232142857, 0.0 ] [V - 128]
//
// For the range [0,1] instead of [0,255]:
//
// The matrix is stored in column-major.
const mat3 YuvColorMatrixRec2020 = mat3(
1.16438356164384 , 1.164383561643840, 1.16438356164384,
0.0 , -0.187326104219343, 2.14177232142857,
1.67867410714286 , -0.650424318505057, 0.0
);
// The matrix is stored in column-major.
// Identity is stored as GBR
const mat3 IdentityColorMatrix = mat3(
0.0 , 1.0, 0.0,
0.0 , 0.0, 1.0,
1.0 , 0.0, 0.0
);
mat3 get_yuv_color_matrix(int color_space) {
if (color_space == YUV_COLOR_SPACE_REC601) {
return YuvColorMatrixRec601;
} else if (color_space == YUV_COLOR_SPACE_REC709) {
return YuvColorMatrixRec709;
} else if (color_space == YUV_COLOR_SPACE_IDENTITY) {
return IdentityColorMatrix;
} else {
return YuvColorMatrixRec2020;
}
}
vec3 get_yuv_offset_vector(int color_space) {
// Float conversion to work around a macOS Intel shader compiler bug
if (float(color_space) == float(YUV_COLOR_SPACE_IDENTITY)) {
return vec3(0.0, 0.0, 0.0);
} else {
return vec3(0.06275, 0.50196, 0.50196);
}
}
void write_uv_rect(
vec2 uv0,
vec2 uv1,
vec2 f,
vec2 texture_size,
out vec2 uv,
out vec4 uv_bounds
) {
uv = mix(uv0, uv1, f);
uv_bounds = vec4(uv0 + vec2(0.5), uv1 - vec2(0.5));
#ifndef WR_FEATURE_TEXTURE_RECT
uv /= texture_size;
uv_bounds /= texture_size.xyxy;
#endif
}
#endif
#ifdef WR_FRAGMENT_SHADER
vec4 sample_yuv(
int format,
mat3 yuv_color_matrix,
vec3 yuv_offset_vector,
float coefficient,
vec3 yuv_layers,
vec2 in_uv_y,
vec2 in_uv_u,
vec2 in_uv_v,
vec4 uv_bounds_y,
vec4 uv_bounds_u,
vec4 uv_bounds_v
) {
vec3 yuv_value;
switch (format) {
case YUV_FORMAT_PLANAR:
{
// The yuv_planar format should have this third texture coordinate.
vec2 uv_y = clamp(in_uv_y, uv_bounds_y.xy, uv_bounds_y.zw);
vec2 uv_u = clamp(in_uv_u, uv_bounds_u.xy, uv_bounds_u.zw);
vec2 uv_v = clamp(in_uv_v, uv_bounds_v.xy, uv_bounds_v.zw);
yuv_value.x = TEX_SAMPLE(sColor0, vec3(uv_y, yuv_layers.x)).r;
yuv_value.y = TEX_SAMPLE(sColor1, vec3(uv_u, yuv_layers.y)).r;
yuv_value.z = TEX_SAMPLE(sColor2, vec3(uv_v, yuv_layers.z)).r;
}
break;
case YUV_FORMAT_NV12:
{
vec2 uv_y = clamp(in_uv_y, uv_bounds_y.xy, uv_bounds_y.zw);
vec2 uv_uv = clamp(in_uv_u, uv_bounds_u.xy, uv_bounds_u.zw);
yuv_value.x = TEX_SAMPLE(sColor0, vec3(uv_y, yuv_layers.x)).r;
yuv_value.yz = TEX_SAMPLE(sColor1, vec3(uv_uv, yuv_layers.y)).rg;
}
break;
case YUV_FORMAT_INTERLEAVED:
{
// "The Y, Cb and Cr color channels within the 422 data are mapped into
// the existing green, blue and red color channels."
// https://www.khronos.org/registry/OpenGL/extensions/APPLE/APPLE_rgb_422.txt
vec2 uv_y = clamp(in_uv_y, uv_bounds_y.xy, uv_bounds_y.zw);
yuv_value = TEX_SAMPLE(sColor0, vec3(uv_y, yuv_layers.x)).gbr;
}
break;
default:
yuv_value = vec3(0.0);
break;
}
// See the YuvColorMatrix definition for an explanation of where the constants come from.
vec3 rgb = yuv_color_matrix * (yuv_value * coefficient - yuv_offset_vector);
vec4 color = vec4(rgb, 1.0);
return color;
}
#endif
|