• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #pragma version(1)
2 #pragma rs java_package_name(com.android.testingcamera)
3 #pragma rs_fp_relaxed
4 
5 uchar *yuv_in;
6 
7 // Input globals
8 uint32_t yuv_height;
9 uint32_t yuv_width;
10 uint32_t out_width;
11 uint32_t out_height;
12 // Derived globals
13 uint32_t y_stride;
14 uint32_t uv_stride;
15 uint32_t u_start;
16 uint32_t v_start;
17 float x_scale;
18 float y_scale;
19 
20 static const float CLAMP_MIN = 0;
21 static const float CLAMP_MAX = 255;
22 
23 /**
24  * JFIF standard YCbCr <-> RGB conversion matrix,
25  * column-major order.
26  */
27 static const float YUV2RGB[] = {
28     1.0f, 1.0f, 1.0f, 0.0f,
29     0.0f, -0.34414f, 1.772f, 0.0f,
30     1.402f, -0.71414f, 0.0f, 0.0f,
31     -0.701f, 0.529f, -0.886f, 1.0f
32 };
33 rs_matrix4x4 yuv2rgb_matrix;
34 
35 enum ImageFormat {
36     NV16 = 16,
37     NV21 = 17,
38     RGB_565 = 4,
39     UNKNOWN = 0,
40     YUY2 = 20,
41     YV12 = 0x32315659
42 };
43 
44 // Must be called before using any conversion methods
45 void init_convert(uint32_t yw, uint32_t yh, uint32_t format,
46         uint32_t ow, uint32_t oh) {
47     yuv_height = yh;
48     yuv_width = yw;
49     out_width = ow;
50     out_height = oh;
51     rsMatrixLoad(&yuv2rgb_matrix, YUV2RGB);
52 
53     x_scale = (float)yuv_width / out_width;
54     y_scale = (float)yuv_height / out_height;
55 
56     switch (format) {
57     case NV16:
58     case NV21:
59         y_stride = yuv_width;
60         uv_stride = yuv_width;
61         v_start = y_stride * yuv_height;
62         u_start = v_start + 1;
63         break;
64     case YV12:
65         // Minimum align-16 stride
66         y_stride = (yuv_width + 0xF) & ~0xF;
67         uv_stride = (y_stride / 2 + 0xF) & ~0xF;
68         v_start = y_stride * yuv_height;
69         u_start = v_start + uv_stride * (yuv_height / 2);
70         break;
71     case YUY2:
72         y_stride = yuv_width * 2;
73         uv_stride = y_stride;
74         u_start = 1;
75         v_start = 3;
76         break;
77     case RGB_565:
78     case UNKNOWN:
79     default:
80         y_stride = yuv_width;
81         uv_stride = yuv_width;
82         v_start = 0;
83         u_start = 0;
84     }
85 }
86 
87 // Multiply by color matrix and clamp to range [0, 255]
88 static inline uchar4 multiply_and_clamp(const rs_matrix4x4* mat, uchar4 input) {
89     float4 intermediate = convert_float4(input);
90     intermediate = rsMatrixMultiply(mat, intermediate);
91     intermediate = clamp(intermediate, CLAMP_MIN, CLAMP_MAX);
92     return convert_uchar4(intermediate);
93 }
94 
95 // Makes up a conversion for unknown YUV types to try to display something
96 // Asssumes that there's at least 1bpp in input YUV data
97 uchar4 __attribute__((kernel)) convert_unknown(uint32_t x, uint32_t y) {
98     uint32_t x_scaled = x * x_scale;
99     uint32_t y_scaled = y * y_scale;
100 
101     uchar4 out;
102     out.r = yuv_in[y_stride * y_scaled + x_scaled];
103     out.g = 128;
104     out.b = 128;
105     out.a = 255; // For affine transform later
106 
107     // Apply yuv->rgb color transform
108     return multiply_and_clamp(&yuv2rgb_matrix, out);
109 }
110 
111 // Converts semiplanar YVU to interleaved YUV, nearest neighbor
112 uchar4 __attribute__((kernel)) convert_semiplanar(uint32_t x, uint32_t y) {
113     uint32_t x_scaled = x * x_scale;
114     uint32_t y_scaled = y * y_scale;
115 
116     uint32_t uv_row = y_scaled / 2; // truncation is important here
117     uint32_t uv_col = x_scaled & ~0x1;
118     uint32_t vu_pixel = uv_row * uv_stride + uv_col;
119 
120     uchar4 out;
121     out.r = yuv_in[y_stride * y_scaled + x_scaled];
122     out.g = yuv_in[u_start + vu_pixel];
123     out.b = yuv_in[v_start + vu_pixel];
124     out.a = 255; // For affine transform later
125 
126     // Apply yuv->rgb color transform
127     return multiply_and_clamp(&yuv2rgb_matrix, out);
128 }
129 
130 // Converts planar YVU to interleaved YUV, nearest neighbor
131 uchar4 __attribute__((kernel)) convert_planar(uint32_t x, uint32_t y) {
132     uint32_t x_scaled = x * x_scale;
133     uint32_t y_scaled = y * y_scale;
134 
135     uint32_t uv_row = y_scaled / 2; // truncation is important here
136     uint32_t vu_pixel = uv_stride * uv_row + x_scaled / 2;
137 
138     uchar4 out;
139     out.r = yuv_in[y_stride * y_scaled + x_scaled];
140     out.g = yuv_in[u_start + vu_pixel];
141     out.b = yuv_in[v_start + vu_pixel];
142     out.a = 255; // For affine transform later
143 
144     // Apply yuv->rgb color transform
145     return multiply_and_clamp(&yuv2rgb_matrix, out);
146 }
147 
148 // Converts interleaved 4:2:2 YUV to interleaved YUV, nearest neighbor
149 uchar4 __attribute__((kernel)) convert_interleaved(uint32_t x, uint32_t y) {
150     uint32_t x_scaled = x * x_scale;
151     uint32_t y_scaled = y * y_scale;
152 
153     uint32_t uv_col = 2 * (x_scaled & ~0x1);
154     uint32_t vu_pixel = y_stride * y_scaled + uv_col;
155 
156     uchar4 out;
157     out.r = yuv_in[y_stride * y_scaled + x_scaled * 2];
158     out.g = yuv_in[u_start + vu_pixel];
159     out.b = yuv_in[v_start + vu_pixel];
160     out.a = 255; // For affine transform later
161 
162     // Apply yuv->rgb color transform
163     return multiply_and_clamp(&yuv2rgb_matrix, out);
164 }
165