Home | History | Annotate | Download | only in testingcamera
      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