1 
2 /*
3  * Copyright 2018 Google LLC. All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6  * use this file except in compliance with the License. You may obtain a copy of
7  * the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14  * License for the specific language governing permissions and limitations under
15  * the License.
16  */
17 
18 // This file contains an adaptation of the algorithm at:
19 // https://github.com/GoogleChromeLabs/wasm-av1/blob/master/yuv-to-rgb.c
20 
21 // The algorithm here creates precomputed lookup tables to speed up converting
22 // YUV frames to RGB. Since it is done once every camera frame it needs to be
23 // efficient.
24 //
25 // NOTE: This is code is being used temporarily until Cuttlefish supports
26 // hardware-accelerated camera frame transfer from host to guest.  Ideally the
27 // conversions will be done via DMA or GPU algorithms, not via CPU copy
28 
29 // Number of luminance values to precompute tables of for speed. Value is higher
30 // than 255 as to allow for future color depth expansion
31 #define ZOF_TAB 65536
32 
33 // Size of single output pixel in bytes (RGBA x 1 byte each = 4 bytes)
34 #define ZOF_RGB 4
35 
36 namespace cuttlefish {
37 
38 // These tables will store precomputes values
39 static int T1[ZOF_TAB], T2[ZOF_TAB], T3[ZOF_TAB], T4[ZOF_TAB];
40 static int tables_initialized;
41 
42 // Called once to initialize tables
build_yuv2rgb_tables()43 static void build_yuv2rgb_tables() {
44   for (int i = 0; i < ZOF_TAB; i++) {
45     T1[i] = (int)(1.370705 * (float)(i - 128));
46     T2[i] = (int)(-0.698001 * (float)(i - 128));
47     T3[i] = (int)(-0.337633 * (float)(i - 128));
48     T4[i] = (int)(1.732446 * (float)(i - 128));
49   }
50 }
51 
52 #define clamp(val) ((val) < 0 ? 0 : (255 < (val) ? 255 : (val)))
53 
Yuv2Rgb(unsigned char * src,unsigned char * dst,int width,int height)54 void Yuv2Rgb(unsigned char *src, unsigned char *dst, int width, int height) {
55   if (tables_initialized == 0) {
56     tables_initialized = !0;
57     build_yuv2rgb_tables();
58   }
59   // Setup pointers to the Y, U, V planes
60   unsigned char *y = src;
61   unsigned char *u = src + (width * height);
62   unsigned char *v =
63       u + (width * height) / 4;  // Each chroma does 4 pixels in 4:2:0
64   // Loop the image, taking into account sub-sample for the chroma channels
65   for (int h = 0; h < height; h++) {
66     unsigned char *uline = u;
67     unsigned char *vline = v;
68     for (int w = 0; w < width; w++, y++) {
69       int r = *y + T1[*vline];
70       int g = *y + T2[*vline] + T3[*uline];
71       int b = *y + T4[*uline];
72       // Note: going BGRA here not RGBA
73       dst[0] = clamp(b);  // 16-bit to 8-bit, chuck precision
74       dst[1] = clamp(g);
75       dst[2] = clamp(r);
76       dst[3] = 255;
77       dst += ZOF_RGB;
78       if (w & 0x01) {
79         uline++;
80         vline++;
81       }
82     }
83     if (h & 0x01) {
84       u += width / 2;
85       v += width / 2;
86     }
87   }
88 }
89 
90 }  // End namespace cuttlefish