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